Invoke soap webservice returning list of objects f

2019-04-30 01:21发布

问题:

I'm getting mad with webservices.

I have a very simple soap webservice :

@Remote
public interface StudentService
{
public String sayHello();
public List<Student> getStudents();
}

And

@Stateless
@WebService
public class StudentServiceImpl implements StudentService
{

@Override
public String sayHello()
{
    return "Hello World";
}

public List<Student> getStudents()
{
    List<Student> students = new ArrayList<Student>();

    Student st1 = new Student();
    st1.setMatricule(1234);
    st1.setName("student1");
    students.add(st1);

    Student st2 = new Student();
    st2.setMatricule(5678);
    st2.setName("student2");
    students.add(st2);

    return students;
    }
}

And

public class Student implements Serializable
{
private static final long serialVersionUID = 8286393242028201686L;

private int matricule; 
private String name;

public int getMatricule()
{
    return matricule;
}
public void setMatricule(int matricule)
{
    this.matricule = matricule;
}

public String getName()
{
    return name;
}
public void setName(String name)
{
    this.name = name;
}
}

I deploy the service under glassfish 3.1.

Using the glassfish console, it's working.

<?xml version="1.0" encoding="UTF-8"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
    <S:Body>
        <ns2:getStudentsResponse xmlns:ns2="http://services.tuto.java.com/">
            <return>
                <matricule>1234</matricule>
                <name>student1</name>
            </return>
            <return>
                <matricule>5678</matricule>
                <name>student2</name>
            </return>
        </ns2:getStudentsResponse>
    </S:Body>
</S:Envelope>

Using php it's also working (for both methods).

Now with a java client :

import javax.xml.namespace.QName;

import org.apache.axis.client.Call;
import org.apache.axis.client.Service;

public class Client
{
public static void main(String[] args) throws Exception
{
    String endPoint = "http://localhost:8080/StudentServiceImplService/StudentServiceImpl";

    Service service = new Service();
    Call call = (Call) service.createCall();
    call.setTargetEndpointAddress(new java.net.URL(endPoint));
    call.setOperationName(new QName("http://services.tuto.java.com/","sayHello"));

    System.out.println(call.invoke(new Object[0]));

    Service service2 = new Service();
    Call call2 = (Call) service2.createCall();
    call2.setTargetEndpointAddress(new java.net.URL(endPoint));
    call2.setOperationName(new QName("http://services.tuto.java.com/","getStudents"));

    System.out.println(call2.invoke(new Object[0]));
    }
}

The first call is working but not the second one.

Hello World
12-mars-2012 14:53:23 org.apache.axis.client.Call invoke
GRAVE: Exception:
org.xml.sax.SAXException: SimpleDeserializer encountered a child element, which is NOT expected, in something it was trying to deserialize.
at org.apache.axis.encoding.ser.SimpleDeserializer.onStartChild(SimpleDeserializer.java:145)
at org.apache.axis.encoding.DeserializationContext.startElement(DeserializationContext.java:1035)
at org.apache.axis.message.SAX2EventRecorder.replay(SAX2EventRecorder.java:165)
at org.apache.axis.message.MessageElement.publishToHandler(MessageElement.java:1141)
at org.apache.axis.message.RPCElement.deserialize(RPCElement.java:345)
at org.apache.axis.message.RPCElement.getParams(RPCElement.java:384)
at org.apache.axis.client.Call.invoke(Call.java:2467)
at org.apache.axis.client.Call.invoke(Call.java:2366)
at org.apache.axis.client.Call.invoke(Call.java:1812)
at Client.main(Client.java:24)

What can I do ?

After lot of hours searching on internet and trying differents solutions still nothing working ...

Is there a simple solution ?

Thanks.

Edit :

Also tried that :

public class SoapClient
{
public static void main(String[] args) throws Exception
{
    SOAPMappingRegistry smr = new SOAPMappingRegistry();
    BeanSerializer beanSer = new BeanSerializer();
    smr.mapTypes(Constants.NS_URI_SOAP_ENC,new QName("http://services.tuto.java.com/", "StudentServiceImplService"),Student.class, beanSer, beanSer);       

    Call call = new Call();
    call.setSOAPMappingRegistry(smr);
    call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC);

    call.setTargetObjectURI("http://services.tuto.java.com/");
    call.setMethodName("getStudents");

    Response resp;
    try
    {
        resp = call.invoke(new URL("http://8h9l45j:8080/StudentServiceImplService/StudentServiceImpl"), "");
    }
    catch (SOAPException e)
    {
        System.err.println("Caught SOAPException (" +
          e.getFaultCode() + "): " + e.getMessage());
        return;
    }

    if (!resp.generatedFault())
    {
        Parameter ret = resp.getReturnValue();
        Object value = ret.getValue();
        if ( value != null )
        {
            String[] tlist = (String[])value;
            System.out.println();
            for ( int i = 0; i < tlist.length; i++ )
                System.out.println(tlist[i]);
        }
    }
    else
    {
        Fault fault = resp.getFault();
        System.err.println("Generated fault: ");
        System.out.println ("  Fault Code   = "
                            + fault.getFaultCode());
        System.out.println ("  Fault String = "
                            + fault.getFaultString());
    }
}

With that result :

Caught SOAPException (SOAP-ENV:Client): No Deserializer found to deserialize a ':return' using encoding style 'http://schemas.xmlsoap.org/soap/encoding/'.

回答1:

First element of response using soap client.

The problem is coming from the maptypes name space : there is no namespace

So now, I have

    smr.mapTypes(Constants.NS_URI_SOAP_ENC,new QName("","student"),Student.class, null, new BeanSerializer());  
    smr.mapTypes(Constants.NS_URI_SOAP_ENC,new QName("","matricule"),Integer.class, null, new IntDeserializer());   
    smr.mapTypes(Constants.NS_URI_SOAP_ENC,new QName("","name"),Integer.class, null, new StringDeserializer()); 

And also add

@XmlRootElement(name = "Student",namespace="http://services.tuto.java.com/")

to the Student class to have

<?xml version="1.0" encoding="UTF-8"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
    <S:Body>
        <ns2:getStudentsResponse xmlns:ns2="http://services.tuto.java.com/">
            <student>
                <matricule>1236</matricule>
                <name>student1</name>
            </student>
            <student>
                <matricule>5678</matricule>
                <name>student2</name>
            </student>
        </ns2:getStudentsResponse>
    </S:Body>
</S:Envelope>

The axis client :

 public class AxisClient
{
    public static void main(String[] args) throws Exception
    {
    String endPoint = "http://localhost:8080/StudentServiceImplService/StudentServiceImpl";
    Service service2 = new Service();
    Call call2 = (Call) service2.createCall();
    call2.setTargetEndpointAddress(new java.net.URL(endPoint));
    call2.setOperationName(new QName("http://services.tuto.java.com/","getStudents"));
    call2.setReturnType(new QName("","student"), Student.class);
    call2.setReturnType(new QName("", "student"));
    call2.registerTypeMapping(Student.class, new QName("", "student"), null,new BeanDeserializerFactory(Student.class, new QName("", "student")));
    List<Student> students = (List<Student>) call2.invoke(new Object[0]);
    for (Student student : students)
    {
        System.out.println(student);
    }
    }
 }

Giving all students :

Student [matricule=1236, name=student1]
Student [matricule=5678, name=student2]

The axis2 client :

public static void main(String[] args) throws Exception
{
    String endPoint = "http://localhost:8080/StudentServiceImplService/StudentServiceImpl";

    ServiceClient sc = new ServiceClient();

    Options opts = new Options();
    opts.setTo(new EndpointReference("http://localhost:8080/StudentServiceImplService/StudentServiceImpl"));
    sc.setOptions(opts);

    OMFactory fac = OMAbstractFactory.getOMFactory();
    OMNamespace omNs = fac.createOMNamespace("http://services.tuto.java.com/","ns1");

    OMElement method = fac.createOMElement("getStudents", omNs);
    OMElement res = sc.sendReceive(method);
    System.out.println(res);

    Iterator<OMElement> it = res.getChildElements();
    while(it.hasNext())
    {
        System.out.println(it.next());
    }
}

Giving

<ns2:getStudentsResponse xmlns:ns2="http://services.tuto.java.com/"><student><matricule>1236</matricule><name>student1</name></student><student><matricule>5678</matricule><name>student2</name></student></ns2:getStudentsResponse>
<student><matricule>1236</matricule><name>student1</name></student>
<student><matricule>5678</matricule><name>student2</name></student>

But I don't know how to deserialize the omelement.

I tried with

Student student = (Student) BeanUtil.deserialize(Student.class,res,new DefaultObjectSupplier(),null);

but gives me

Student [matricule=null, name=null]

How can I do ?

Leaving problems :

  • don't know how to do the same with axis --OK See before--/axis 2
  • the 'resp' (soap client) contains only first student


回答2:

Can you not get to the WSDL something like

http://localhost:8080/StudentServiceImplService/StudentServiceImpl?wsdl

and then use axis wsdl2java to let Axis create the client code for you (which will have all the correct type mappings and namespaces)?



回答3:

Whats the SOAP binding style you are using,RPC/DOCUMENT ? If you are using RPC then the request and response will be encoded and processed,Axis2 is not supporting the RPC encoded format messages. Try using DOCUMENT SOAP binding style. (I should have put this in comments,kindly bear)

Refer https://stackoverflow.com/a/9598193/752129