I have generated a web service client using wsimport command line (JAX-WS) and generated Java objects using JAXB and separate XSD files.
But when I try to request, it gives following error from server side.
SAXException, cause: The markup in the document following the root element must be well-formed.
So I checked my soap request with a sample working soap message. Then I realized that there is a different between these two messages.
1. Sample working message.
<m:getMyDetail xmlns:m="http://axis.frontend.hi.example.net"> <MyDetailRQ xmlns="http://www.example.net/schemas/1005/06/messages" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.net/1005/06/messages ../xsd/MyDetailRQ.xsd" version="2013/12">
2. Web service client generated soap message.
<ns3:getMyDetail xmlns:ns3="http://axis.frontend.hi.example.net" xmlns="http://www. example.net/schemas/1005/06/messages" xmlns:ns2="http://www. example.net/wsdl/1005/06" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="MyDetailRQ">
As you can see, above expected MyDetailRQ wrapper tag element is missing but it generated as xsi:type="MyDetailRQ" attribute.
I’m not sure why this happen and how to fix this through my client project configurations.
Appreciate your help and advice.
Thanks
- Relevant WSDL part
<wsdl:types>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://axis.frontend.h1.example.com">
<element name="getMyDetail" type="xsd:anyType"/>
</schema>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.com/wsdl/2005/06">
<element name="getMyDetailReturn" type="xsd:anyType"/>
</schema>
</wsdl:types>
<wsdl:message name="getMyDetailRequest">
<wsdl:part element="tns1:getMyDetail" name="part"/>
</wsdl:message>
<wsdl:message name="getMyDetailResponse">
<wsdl:part element="impl:getMyDetailReturn" name="getMyDetailReturn"/>
</wsdl:message>
<wsdl:portType name="MyService">
<wsdl:operation name="getMyDetail">
<wsdl:input message="impl:getMyDetailRequest" name="getMyDetailRequest"/>
<wsdl:output message="impl:getMyDetailResponse" name="getMyDetailResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="MyServiceSoapBinding" type="impl:MyService">
<wsdl:operation name="getMyDetail">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="getMyDetailRequest">
<wsdlsoap:body use="literal"/>
</wsdl:input>
<wsdl:output name="getMyDetailResponse">
<wsdlsoap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="MyServiceService">
<wsdl:port binding="impl:MyServiceSoapBinding" name="MyService">
<wsdlsoap:address location="http://interface.example.com/xmls/ws/MyService"/>
</wsdl:port>
</wsdl:service>
- Relevant XSD part
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns="http://www.example.net/schemas/1005/06/messages" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.net/schemas/1005/06/messages" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:include schemaLocation="MyCommonTypes.xsd"/>
<xs:element name="MyDetailRQ">
- Relevant Java Object
@XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "MyDetailRQ", propOrder = { "myCode" }) @XmlRootElement(name = "MyDetailRQ") public class MyDetailRQ extends MainRequest { }
- web service client - service interface (Updated on 17-Oct-2014)
@WebService(name = "MyService", targetNamespace = "http://www.example.net/wsdl/1005/06")
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
@XmlSeeAlso({
com.myp.hi.frontend.axis.ObjectFactory.class,
com.myp.ObjectFactory.class
})
public interface MyService {
/**
*
* @param part
* @return
* returns java.lang.Object
*/
@WebMethod
@WebResult(name = "getMyDetailReturn", targetNamespace = "http://www.example.net/wsdl/1005/06", partName = "getMyDetailReturn")
public Object getMyDetail(
@WebParam(name = "getMyDetail", targetNamespace = "http://axis.frontend.hi.example.net", partName = "part")
Object part);
}
- ObjectFactory class (Updated on 17-Oct-2014)
@XmlRegistry
public class ObjectFactory {
private final static QName _GetMyDetail_QNAME = new QName("http://axis.frontend.hi.example.net", "getMyDetail");
public ObjectFactory() {
}
@XmlElementDecl(namespace = "http://axis.frontend.hi.example.net", name = "getMyDetail")
public JAXBElement<Object> createGetMyDetail(Object value) {
return new JAXBElement<Object>(_GetMyDetail_QNAME, Object.class, null, value);
}
}
-MyServiceService class (Updated on 17-Oct-2014)
@WebServiceClient(name = "MyServiceService", targetNamespace = "http://www.example.net/wsdl/1005/06", wsdlLocation = "http://interface.example.com/xmls/ws/MyService?wsdl")
@GZIP
public class MyServiceService
extends Service
{
private final static URL MYSERVICESERVICE_WSDL_LOCATION;
private final static WebServiceException MYSERVICESERVICE_EXCEPTION;
private final static QName MYSERVICESERVICE_QNAME = new QName("http://www.example.net/wsdl/1005/06", "MyServiceService");
static {
URL url = null;
WebServiceException e = null;
try {
url = new URL("http://interface.example.com/xmls/ws/MyService?wsdl");
} catch (MalformedURLException ex) {
e = new WebServiceException(ex);
}
MYSERVICESERVICE_WSDL_LOCATION = url;
MYSERVICESERVICE_EXCEPTION = e;
}
@WebEndpoint(name = "MyService")
public MyService getMyService() {
MyService port = super.getPort(new QName("http://www.example.net/wsdl/1005/06", "MyService"), MyService.class);
return port;
}
private static URL __getWsdlLocation() {
if (MYSERVICESERVICE_EXCEPTION!= null) {
throw MYSERVICESERVICE_EXCEPTION;
}
return MYSERVICESERVICE_WSDL_LOCATION;
}
}
- My Test class (Updated on 17-Oct-2014)
MyService myService = new MyServiceService().getMyService();
MyDetailRQ myDetailRQ = new MyDetailRQ();
myDetailRQ.setCredentials(credentials);
myDetailRQ.setLanguage("ENG");
myDetailRQ.setMyCode("52319");
MyDetailRS myDetailRS = (MyDetailRS) myService.getMyDetail(myService);
I have found a solution, but not sure whether perfect one.
What I have done is; pass a XML String to service and get response as a String from service. Then manually do marshalling and un- marshalling.
See the example below.
MyService myService = new MyServiceService().getMyService();
MyDetailRQ myDetailRQ = new MyDetailRQ();
myDetailRQ.setCredentials(credentials);
myDetailRQ.setLanguage("ENG");
myDetailRQ.setMyCode("52319");
String requestStr = getStringFromJaxb(myDetailRQ.class, myDetailRQ);
String responseStr = (String) myService.getMyDetail(requestStr);
MyDetailRS myDetailRS = (MyDetailRS) getJaxbFromString(MyDetailRS.class, responseStr);
private static Object getJaxbFromString(Class<?> clazz, String xmlString) {
StringReader input = null;
Object o = null;
try {
input = new StringReader(xmlString);
JAXBContext context = JAXBContext.newInstance(clazz);
Unmarshaller um = context.createUnmarshaller();
o = um.unmarshal(input);
if (o instanceof JAXBElement)
o = ((JAXBElement<?>) o).getValue();
} catch (JAXBException e) {
e.printStackTrace();
} finally {
if (input != null)
input.close();
}
return o;
}
/**
* Helper method to get xml string from JAXB Object.
* @param clazz
* @param o
* @return
*/
private static String getStringFromJaxb(Class<?> clazz, Object o) {
String theXML = "";
try {
StringWriter writer = new StringWriter();
JAXBContext context = JAXBContext.newInstance(clazz);
Marshaller m = context.createMarshaller();
m.setProperty("com.sun.xml.bind.xmlDeclaration", Boolean.FALSE);
m.marshal(o, writer);
// output string to console
theXML = writer.toString();
} catch (Exception e) {
e.printStackTrace();
}
return theXML;
}