Mixed Content for JAXB not working from WSDL - java

I'm using NetBeans and I have two projects:
A EJB Module to generate a webservice and deploy it to GlassFish
A simple console client to test and consume this webservice
For the webservice, I'm using an XSD with mixed content elements.
Adding a binding file for JAXB import with the following code worked:
<?xml version="1.0" encoding="UTF-8"?>
<jaxb:bindings
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc= "http://java.sun.com/xml/ns/jaxb/xjc" jaxb:extensionBindingPrefixes="xjc"
jaxb:version="2.0">
<jaxb:globalBindings generateMixedExtensions="true"/>
</jaxb:bindings>
It generated this code:
#XmlMixed
#OverrideAnnotationOf
protected List<Serializable> contentOverrideForED;
I can live with this generated code, although it's not ideal.
My problem is with the client, for which I've added a Web Service Reference to my generated and deployed webservice, running simply on localhost.
Using the same binding file in WSDL Customization: External Binding File doesn't yield the content code, nor does using it directly as an option for Wsimport, nor using it as a Jaxb option. I have a feeling that this setting is being disregarded somehow, but how?
And why does the initial JAXB generation include it and why doesn't wsimport use it? I'm kind of puzzled here.

Great question! I and my collegaues spent many hours to solve mixed type in class which I generated with wsimport. I try many adjust and get List<Object>, List<Serializable> or List<String>. We used simple wsimport and we didn't know about:
<jaxb:globalBindings generateMixedExtensions="true"/>
Now, I offer you to create simple wsimport batch script and this released for customer. I think you can use external binding file (-b parameter) in wsimport script.
Martin Grebac wrote great article about this topic:
it is a good decision to
avoid use of mixed content, especially when designing a large schema
with a lot of type extensions. Mapping that kind of schema to any
binding framework is usually complex and leads to complications and
slowdown of development. JAXB has never been designed to handle these
cases in a convenient way - it is a Java <-> XML mapping framework,
and it's not possible to represent this kind of content in a hierarchy
of Java objects.
I fully agreed with a Martin. The JAXB is simple Java <-> XML mapping framework. But It is existing one customization which solved problem with multiple mixed type in one XSD. That is generateMixedExtensions="true". This customization is change the behaviour of JAXB.
I'd really like to know why wsimport does this differently from xjc
I think you are change behavior of JAXB when use xjc and wsimport use simple JAXB without this customization.
Please check wsimport 2.0 or wsimport 2.1 documetntation for parameters. Here is link about mixed content model and if you use xs:any in mixed type can you adjust it.

You may want to consider using Eclipse to gen what you need. Even though the xsd and wsdl you are using isn't included in the question, I came up with a simple example that seems to work. I did not use a bindings file, the wizard in Eclipse picked the fact that mixed was needed because mixed="true" in the XSD (may want to try yours with no binding):
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/NewXMLSchema" xmlns:tns="http://www.example.org/NewXMLSchema" elementFormDefault="qualified">
<xs:element name="letter">
<xs:complexType mixed="true">
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="orderid" type="xs:positiveInteger"/>
<xs:element name="shipdate" type="xs:date"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
WSDL:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://www.example.org/NewWSDLFile/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="NewWSDLFile" targetNamespace="http://www.example.org/NewWSDLFile/" xmlns:xsd1="http://www.example.org/NewXMLSchema">
<wsdl:types>
<xsd:schema targetNamespace="http://www.example.org/NewWSDLFile/">
<xsd:element name="NewOperation">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="in" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="NewOperationResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="out" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:import namespace="http://www.example.org/NewXMLSchema"
schemaLocation="NewXMLSchema.xsd">
</xsd:import></xsd:schema></wsdl:types>
<wsdl:message name="NewOperationRequest">
<wsdl:part element="xsd1:letter" name="parameters"/>
</wsdl:message>
<wsdl:message name="NewOperationResponse">
<wsdl:part element="tns:NewOperationResponse" name="parameters"/>
</wsdl:message>
<wsdl:portType name="NewWSDLFile">
<wsdl:operation name="NewOperation">
<wsdl:input message="tns:NewOperationRequest"/>
<wsdl:output message="tns:NewOperationResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="NewWSDLFileSOAP" type="tns:NewWSDLFile">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="NewOperation">
<soap:operation soapAction="http://www.example.org/NewWSDLFile/NewOperation"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="NewWSDLFile">
<wsdl:port binding="tns:NewWSDLFileSOAP" name="NewWSDLFileSOAP">
<soap:address location="http://www.example.org/"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
Pertinent Java:
//
// Generated By:JAX-WS RI IBM 2.2.1-11/28/2011 08:28 AM(foreman)- (JAXB RI IBM 2.2.3-11/28/2011 06:21 AM(foreman)-)
//
package org.example.newwsdlfile;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.xml.bind.annotation.XmlSeeAlso;
import org.example.newxmlschema.Letter;
#WebService(name = "NewWSDLFile", targetNamespace = "http://www.example.org/NewWSDLFile/")
#SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
#XmlSeeAlso({
org.example.newwsdlfile.ObjectFactory.class,
org.example.newxmlschema.ObjectFactory.class
})
public interface NewWSDLFile {
/**
*
* #param parameters
* #return
* returns org.example.newwsdlfile.NewOperationResponse
*/
#WebMethod(operationName = "NewOperation", action = "http://www.example.org/NewWSDLFile/NewOperation")
#WebResult(name = "NewOperationResponse", targetNamespace = "http://www.example.org/NewWSDLFile/", partName = "parameters")
public NewOperationResponse newOperation(
#WebParam(name = "letter", targetNamespace = "http://www.example.org/NewXMLSchema", partName = "parameters")
Letter parameters);
}
Implementation:
package org.example.newwsdlfile;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.transform.Source;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;
import javax.xml.ws.soap.SOAPBinding;
import org.example.newxmlschema.Letter;
public class NewWSDLFileSOAPProxy{
protected Descriptor _descriptor;
public class Descriptor {
private org.example.newwsdlfile.NewWSDLFile_Service _service = null;
private org.example.newwsdlfile.NewWSDLFile _proxy = null;
private Dispatch<Source> _dispatch = null;
public Descriptor() {
init();
}
public Descriptor(URL wsdlLocation, QName serviceName) {
_service = new org.example.newwsdlfile.NewWSDLFile_Service(wsdlLocation, serviceName);
initCommon();
}
public void init() {
_service = null;
_proxy = null;
_dispatch = null;
_service = new org.example.newwsdlfile.NewWSDLFile_Service();
initCommon();
}
private void initCommon() {
_proxy = _service.getNewWSDLFileSOAP();
}
public org.example.newwsdlfile.NewWSDLFile getProxy() {
return _proxy;
}
public Dispatch<Source> getDispatch() {
if (_dispatch == null ) {
QName portQName = new QName("http://www.example.org/NewWSDLFile/", "NewWSDLFileSOAP");
_dispatch = _service.createDispatch(portQName, Source.class, Service.Mode.MESSAGE);
String proxyEndpointUrl = getEndpoint();
BindingProvider bp = (BindingProvider) _dispatch;
String dispatchEndpointUrl = (String) bp.getRequestContext().get(BindingProvider.ENDPOINT_ADDRESS_PROPERTY);
if (!dispatchEndpointUrl.equals(proxyEndpointUrl))
bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, proxyEndpointUrl);
}
return _dispatch;
}
public String getEndpoint() {
BindingProvider bp = (BindingProvider) _proxy;
return (String) bp.getRequestContext().get(BindingProvider.ENDPOINT_ADDRESS_PROPERTY);
}
public void setEndpoint(String endpointUrl) {
BindingProvider bp = (BindingProvider) _proxy;
bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpointUrl);
if (_dispatch != null ) {
bp = (BindingProvider) _dispatch;
bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpointUrl);
}
}
public void setMTOMEnabled(boolean enable) {
SOAPBinding binding = (SOAPBinding) ((BindingProvider) _proxy).getBinding();
binding.setMTOMEnabled(enable);
}
}
public NewWSDLFileSOAPProxy() {
_descriptor = new Descriptor();
_descriptor.setMTOMEnabled(false);
}
public NewWSDLFileSOAPProxy(URL wsdlLocation, QName serviceName) {
_descriptor = new Descriptor(wsdlLocation, serviceName);
_descriptor.setMTOMEnabled(false);
}
public Descriptor _getDescriptor() {
return _descriptor;
}
public NewOperationResponse newOperation(Letter parameters) {
return _getDescriptor().getProxy().newOperation(parameters);
}
}
Class "Letter":
//
// Generated By:JAX-WS RI IBM 2.2.1-11/28/2011 08:28 AM(foreman)- (JAXB RI IBM 2.2.3-11/28/2011 06:21 AM(foreman)-)
//
package org.example.newxmlschema;
import java.io.Serializable;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElementRef;
import javax.xml.bind.annotation.XmlElementRefs;
import javax.xml.bind.annotation.XmlMixed;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.datatype.XMLGregorianCalendar;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"content"
})
#XmlRootElement(name = "letter")
public class Letter {
#XmlElementRefs({
#XmlElementRef(name = "name", namespace = "http://www.example.org/NewXMLSchema", type = JAXBElement.class),
#XmlElementRef(name = "shipdate", namespace = "http://www.example.org/NewXMLSchema", type = JAXBElement.class),
#XmlElementRef(name = "orderid", namespace = "http://www.example.org/NewXMLSchema", type = JAXBElement.class)
})
#XmlMixed
protected List<Serializable> content;
public List<Serializable> getContent() {
if (content == null) {
content = new ArrayList<Serializable>();
}
return this.content;
}
}

Related

ObjectFactory class generated from wsdl missing Factory Metods

I have searched for this in Internet but unable to find a answer.
I am new to SOAP services, If I am wrong at any point please correct me. I was trying to generate Java classes from wsdl using command line tool ** JAX-WS RI wsimport**. I was able to generate all Request and Response classes.
The ObjectFactory.java generated from wsdl was missing most of the methods.
employee.wsdl.jaxb.bnd.xml
<jaxb:bindings version="2.0"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb/xjc">
<jaxb:bindings>
<jaxb:globalBindings generateElementProperty="false">
<xjc:serializable>
</jaxb:globalBindings>
</jaxb:bindings>
</jaxb:bindings>
employee.wsdl.bnd.xml
<jaxws:bindings xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns="http://java.sun.com/xml/ns/jaxws"
xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
wsdlLocation="../sp.wsdl">
<jaxws:enableWrapperStyle>false</jaxws:enableWrapperStyle>
</jaxws:bindings>
In jaxb.bnd.xml
While trying with <jaxb:globalBindings generateElementProperty="true"> Its able to generate all of the factory methods. But it was using JAXBElement<> wrapper for primititve data types like String,int,Long
While trying with <jaxb:globalBindings generateElementProperty="fasle"> Its able to generate the class without JAXBElement<> wrapper, but missing most of the factory methods.
cmd: wsimport META-INF/wsdl/employee.wsdl -keep -b META-INF/wsdl/bindings/employee.bnd.xml -b META-INF/wsdl/bindings/employee.jaxb.bnd.xml -wsdllocation META-INF/wsdl/employee.wsdl
Sample ObjectFactory.java
package xyz;
#XmlRegistry
class ObjectFactory {
private final static Qname _EmpDetailsSpecialEmpDetail_QNAME = new QName("", "scheduleEmp");
#XmlElementDecl(namespce = "", name="specialEmployee", scope= EmpDetails.class)
public SpecialEmpDetail EmpDetailsSpecialEmployee(SpecialEmpDetail value) {
return new SpecialEmpDetail(_EmpDetailsSpecialEmpDetail_QNAME, SpecialEmpDetail.class, EmpDetail.class, value);
}
EmpDetail.java
public class EmpDetail implements Serializable {
#XmlElementRef(name= "specialEmployee", required=false)
protected SpecialEmpDetail specialEmployee;
public SpcialEmpDetail getSpecialEmployee() {
return specialEmployee;
}
public SpcialEmpDetail setSpecialEmployee(SpcialEmpDetail value) {
this.specialEmployee = value;
}
}
SpecialEmpDetail.java
public class SpecialEmpDetail {
//local var
//getter and setter
.....
}
employee.wsdl
<?xml version="1.0" encoding="UTF-8">
<definitions name="psp"
targetNamespace="http://www.namespace.com/employee.wsdl"
.....
/>
<types>
<schmea targerNamespace = "http://www.namespace.com/employee.wsdl"
xmlns:SOAP-ENV = "http://www.w3.org/2003/05/soap-envelope"
xmlns:xsi = "http://www.w3.org/2003/05/XMLSchema-instance"
xmlns:xsd = "http://www.w3.org/2001/XMLSchema"
xmlns:emp = "http://www.namespace.com/employee/employee.xsd1"
<import namespace="http://www.namespace.com/employee.xsd1"/>
<import namespace="http://www.w3.org/2003/05/soap-encoding"/>
</schmea>
<schmea targerNamespace = "http://www.namespace.com/employee.xsd1"
xmlns:SOAP-ENV = "http://www.w3.org/2003/05/soap-envelope"
xmlns:xsi = "http://www.w3.org/2003/05/XMLSchema-instance"
xmlns:xsd = "http://www.w3.org/2001/XMLSchema"
xmlns:emp = "http://www.namespace.com/employee/employee.xsd1"
<import namespace="http://www.namespace.com/employee.wsdl"/>
<import namespace="http://www.w3.org/2003/05/soap-encoding"/>
<simpleType name="empName">
<restrictions base="xsd:string">
<minLength value="1"/>
<maxLength value="30"/>
</restrictions>
<simpleType name="EmpID">
<restrictions base="xsd:string">
<minLength value="0"/>
<maxLength value="25"/>
</restrictions>
</simpleType>
<complexType name="">
<sequence>
<element name="specialEmployee" type="emp:SpecialEmpDetail minOccurs="0" maxOccurs="1" />
</sequence>
</complexType>
.....
.........
</schema>
</types>
Here is the sample wsdl and java. I can able to generate SpecialEmpDetail.java & EmpDetail.java The ObjectFctory.java should create the mentioned function, but its failed to do so.... Using JAXBElement<> wrapper I can able to generate all functions but the problem here is its a complextType data so wrapping is fine, But String also wrapped this is not expected.
What may be problem?? How can I resolve it??
Thanks in Advance!

Unmarshall NMTOKENS as List

The NMTOKENS type is a list of NMTOKEN separated by whitespace characters. The issue is that I can't unmarshall the value as a List for complexType.
I created the object model with JAXB and the generated source for A type is a List<Serializable> for the content, whereas for TestSimpleList is a List<String>.
public class A {
#XmlMixed
protected List<Serializable> content;
#XmlAttribute(name = "a", required = true)
#XmlSchemaType(name = "anySimpleType")
protected String a;
public class UseCase {
#XmlList
#XmlElement(name = "TestSimpleList", required = true)
#XmlSchemaType(name = "NMTOKENS")
protected List<String> testSimpleList;
The marshalling works as expected, so if I add several values to the content, these values are serialized as a String separated by whitespace characters. But it's not working for unmarshalling, the List<Serializable> contains only one element with the String separated by whitespace characters.
You can test the issue with the following schema and test case:
A valid XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<UseCase xmlns="urn:xxx/1">
<TestSimpleList>a b</TestSimpleList>
<TestComplexList a="a">a b</TestComplexList>
</UseCase>
The corresponding schema:
<?xml version="1.0" encoding="UTF-8" ?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="urn:xxx/1"
xmlns:a="urn:xxx/1"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<element name="UseCase">
<complexType>
<sequence>
<element name="TestSimpleList" type="a:SimpleList"></element>
<element name="TestComplexList" type="a:ComplexList"></element>
</sequence>
</complexType>
</element>
<simpleType name="SimpleList">
<restriction base="NMTOKENS"></restriction>
</simpleType>
<complexType name="ComplexList">
<simpleContent>
<restriction base="a:A">
<simpleType>
<restriction base="NMTOKENS"/>
</simpleType>
</restriction>
</simpleContent>
</complexType>
<complexType name="A" mixed="true">
<attribute name="a" use="required"/>
</complexType>
</schema>
The JAXB Bindings:
<?xml version="1.0" encoding="UTF-8"?>
<jaxb:bindings
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="2.0"
jaxb:extensionBindingPrefixes="xjc">
<jaxb:globalBindings generateMixedExtensions="true"/>
<jaxb:bindings scd="x-schema::a" xmlns:a="urn:xxx/1">
<jaxb:schemaBindings>
<jaxb:package name="com.example.demo.tools.domain"/>
</jaxb:schemaBindings>
</jaxb:bindings>
</jaxb:bindings>
The test case:
package com.example.demo.tools;
import com.example.demo.tools.domain.ComplexList;
import com.example.demo.tools.domain.UseCase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.StringReader;
import java.io.StringWriter;
import static org.junit.Assert.assertEquals;
#RunWith(MockitoJUnitRunner.class)
public class JaxbTest {
#Test
public void marshall() throws JAXBException {
JAXBContext contextObj = JAXBContext.newInstance(UseCase.class);
Marshaller marshaller = contextObj.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
UseCase useCase = new UseCase();
useCase.getTestSimpleList().add("a");
useCase.getTestSimpleList().add("b");
ComplexList complexList = new ComplexList();
complexList.setA("a");
complexList.getContent().add("a");
complexList.getContent().add("b");
useCase.setTestComplexList(complexList);
StringWriter sw = new StringWriter();
marshaller.marshal(useCase, sw);
System.out.println("sw = " + sw);
}
#Test
public void unmarshall() throws JAXBException {
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" +
"<UseCase xmlns=\"urn:xxx/1\">" +
"<TestSimpleList>a b</TestSimpleList>" +
"<TestComplexList a=\"a\">a b</TestComplexList>" +
"</UseCase>";
JAXBContext contextObj = JAXBContext.newInstance(UseCase.class);
Unmarshaller unmarshaller = contextObj.createUnmarshaller();
UseCase useCase = (UseCase) unmarshaller.unmarshal(new StringReader(xml));
assertEquals(2, useCase.getTestSimpleList().size());
// The following assertion fails
assertEquals(2, useCase.getTestComplexList().getContent().size());
}
}

How can I have two different endpoint with different namespace and same JAXB class?

I am using spring soap ws.
I have following JAXB domain classes correspond to complex types
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"reference",
"reason"
})
#XmlRootElement(name = "request-message")
public class RequestMessageType {
#XmlElement(name = "reference", required = true)
protected String reference;
#XmlElement(name = "reason")
protected String reason;
// I have getters and setters but removed here.
}
I have following class with #XmlRegistry annotations
#XmlRegistry
public class ObjectFactory {
private final static QName _RequestMessage_QNAME = new QName("http://namespace/url", "request-message");
public ObjectFactory() {
}
#XmlElementDecl(namespace = "http://namespace/url", name = "request-message")
public JAXBElement<RequestMessageType> createDisconnectRequestMessage(RequestMessageType value) {
return new JAXBElement<RequestMessageType>(_RequestMessage_QNAME, RequestMessageType.class, null, value);
}
}
Following are endpoints
#Endpoint
public class FirstEndPoint {
private static final String NAMESPACE_URI = "http://first/url/version";
private static final Logger LOG = Logger.getLogger(FirstEndPoint.class);
#PayloadRoot(namespace = NAMESPACE_URI, localPart = "request-message")
#ResponsePayload
public JAXBElement<ResponseMessageType> requestMessage(#RequestPayload JAXBElement<RequestMessageType> requestMessage) {
LOG.info("request-message : first version ID : " + requestMessage.getValue().getReference());
//Preparing response and return response
}
}
#Endpoint
public class SecondEndPoint {
private static final String NAMESPACE_URI = "http://second/url/version";
private static final Logger LOG = Logger.getLogger(SecondEndPoint.class);
#PayloadRoot(namespace = NAMESPACE_URI, localPart = "request-message")
#ResponsePayload
public JAXBElement<ResponseMessageType> requestMessage(#RequestPayload JAXBElement<RequestMessageType> requestMessage) {
LOG.info("request-message : second version ID : " + requestMessage.getValue().getReference());
//Preparing response and return response
}
}
When I make Soap request, I am using NAMESPACE_URI given in endpoints in soap request.
Here, in this case, I am getting following response
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>SOAP-ENV:Server</faultcode>
<faultstring xml:lang="en">unexpected element (uri:"http://first/url/version", local:"request-message"). Expected elements are <{http://namespace/url}request-message></faultstring>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
If I use "http://namespace/url" as NAMESPACE_URI in endpoint and in soap request I am getting the proper response but I try to make it different for two endpoints with two different namespaces then it is not working and gives above response.
How can I use two different namespaces for two different endpoints with same JAXB class? I am completely new to spring and web service.
Additional info : RequestMessageType class and ObjectFactory class are in one package and in package-info.java namespace is
#javax.xml.bind.annotation.XmlSchema(namespace="http://namespace/url",elementFormDefault=javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package com.example
Do I need to change anything in package-info.java file ?
I created a sample project. I hope it can be useful to you. You can give a look at it here: https://github.com/angeloimm/spring-ws-sample
Basically this is my WSDL file (in SOAP Web Service all is ruled by WSDL):
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:ss="http://www.example.org/SpringSample/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="SpringSample"
targetNamespace="http://www.example.org/SpringSample/">
<wsdl:types>
<xsd:schema targetNamespace="http://www.example.org/SpringSample/">
<xsd:complexType name="abstractRequest">
<xsd:sequence minOccurs="1" maxOccurs="1">
<xsd:element name="reqName" type="xsd:string" nillable="false"
maxOccurs="1" minOccurs="1" />
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="abstractResponse">
<xsd:sequence minOccurs="1" maxOccurs="1">
<xsd:element name="responseName" type="xsd:string"
nillable="false" maxOccurs="1" minOccurs="1" />
</xsd:sequence>
</xsd:complexType>
<xsd:element name="requestImplementation" type="ss:abstractRequest" />
<xsd:element name="responseImplementation" type="ss:abstractResponse" />
<xsd:element name="requestImplementation2" type="ss:abstractRequest" />
<xsd:element name="responseImplementation2" type="ss:abstractResponse" />
</xsd:schema>
</wsdl:types>
<wsdl:message name="OperationRequest">
<wsdl:part element="ss:requestImplementation" name="request" />
</wsdl:message>
<wsdl:message name="OperationResponse">
<wsdl:part element="ss:responseImplementation" name="response" />
</wsdl:message>
<wsdl:message name="OperationRequest2">
<wsdl:part element="ss:requestImplementation2" name="request2" />
</wsdl:message>
<wsdl:message name="OperationResponse2">
<wsdl:part element="ss:responseImplementation2" name="response2" />
</wsdl:message>
<wsdl:portType name="SpringSample">
<wsdl:operation name="Operation1">
<wsdl:input message="ss:OperationRequest" />
<wsdl:output message="ss:OperationResponse" />
</wsdl:operation>
<wsdl:operation name="Operation2">
<wsdl:input message="ss:OperationRequest2" />
<wsdl:output message="ss:OperationResponse2" />
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="SpringSampleSOAP" type="ss:SpringSample">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="Operation1">
<soap:operation style="document" soapAction="http://www.example.org/SpringSample/Operation1" />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="Operation2">
<soap:operation style="document" soapAction="http://www.example.org/SpringSample/Operation2" />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="SpringSample">
<wsdl:port binding="ss:SpringSampleSOAP" name="SpringSampleSOAP">
<soap:address location="http://www.example.org/" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
As you can see I defined 2 complex type: abstractRequest and abstractResponse. Then I implemented them by using the elements requestImplementation,requestImplementation2,responseImplementation,responseImplementation2 According to WS-I specification you need to use separate operations and elements
Then I wrote this endpoint:
#Endpoint
public class SampleEndpoint
{
private static final Logger logger = LoggerFactory.getLogger(SampleEndpoint.class.getName());
private static final String NAME_SPACE_URI = "http://www.example.org/SpringSample/";
#PayloadRoot(namespace = NAME_SPACE_URI, localPart="requestImplementation")
#ResponsePayload
public JAXBElement<AbstractResponse> operationOneResp(#RequestPayload JAXBElement<AbstractRequest> ar)
{
if( logger.isDebugEnabled() )
{
logger.debug("Operation 1 request "+ar.getValue().getReqName());
}
ObjectFactory of = new ObjectFactory();
AbstractResponse aResp = of.createAbstractResponse();
aResp.setResponseName("operation 1 response");
JAXBElement<AbstractResponse> result = of.createResponseImplementation(aResp);
return result;
}
#PayloadRoot(namespace = NAME_SPACE_URI, localPart="requestImplementation2")
#ResponsePayload
public JAXBElement<AbstractResponse> operationTwoResp(#RequestPayload JAXBElement<AbstractRequest> ar)
{
if( logger.isDebugEnabled() )
{
logger.debug("Operation 2 request "+ar.getValue().getReqName());
}
ObjectFactory of = new ObjectFactory();
AbstractResponse aResp = of.createAbstractResponse();
aResp.setResponseName("operation 2 response");
JAXBElement<AbstractResponse> result = of.createResponseImplementation(aResp);
return result;
}
}
As you can see now I always use AbstractRequest and AbstractResponse JAXBElement in both methods. The 2 methods can also be in 2 different endpoints
I hope it's what you needed and it's useful
Angelo

Invoke a webservice from Android using SOAP

I'm consuming a webservice using java, i'm using the below WSDL, but i'm confused with the SOAP_ACTION:
NAMESPACE:
URL:
METHOD_NAME:
WSDL
<wsdl:definitions
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:soapjms="http://www.w3.org/2010/soapjms/"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:tns="http://cloudx623.company.com:5555/ws/Monish:TestWebservice/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"name="TestWebservice"
targetNamespace="http://cloudx623.company.com:5555/ws/Monish:TestWebservice/myTest">
<wsdl:types>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://localhost:8080/Monish/TestWebservice"
targetNamespace="http://localhost:8080/Monish/TestWebservice">
<xsd:element name="myTest" type="tns:myTest"/>
<xsd:element name="myTestResponse" type="tns:myTestResponse"/>
<xsd:complexType name="myTest">
<xsd:sequence>
<xsd:element name="a" nillable="true" type="xsd:string"/>
<xsd:element name="b" nillable="true" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="myTestResponse">
<xsd:sequence>
<xsd:element name="output" nillable="true" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
</wsdl:types>
<wsdl:message name="TestWebservice_PortType_myTestResponse">
<wsdl:part name="parameters" element="tns:myTestResponse"></wsdl:part>
</wsdl:message>
<wsdl:message name="TestWebservice_PortType_myTest">
<wsdl:part name="parameters" element="tns:myTest"></wsdl:part>
</wsdl:message>
<wsdl:portType name="TestWebservice_PortType">
<wsdl:operation name="myTest">
<wsdl:input message="tns:TestWebservice_PortType_myTest"></wsdl:input>
<wsdl:output message="tns:TestWebservice_PortType_myTestResponse"></wsdl:output>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="Monish_TestWebservice_Binder" type="tns:TestWebservice_PortType">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="myTest">
<soap:operation soapAction="Monish_TestWebservice_Binder_myTest" style="document"/>
<wsdl:input>
<soap:body parts="parameters" use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body parts="parameters" use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="TestWebservice">
<wsdl:port name="Monish_TestWebservice_Port" binding="tns:Monish_TestWebservice_Binder">
<soap:address location="http://192.28.50.46:5555/ws/Monish:TestWebservice/Monish_TestWebservice_Port"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
The Java code using ksoap2 is as below
private static final String SOAP_ACTION = "http://cloudx623.company.com:5555/ws/Monish:TestWebservice/myTest";
private static final String METHOD_NAME = "myTest";
private static final String NAMESPACE = "Monish_TestWebservice_Binder_myTest";
// !!!!! IMPORTANT!!!!! THE URL OF THE CoLDFUSION WEBSERVER NOT LOCALHOST BECAUSE LOCALHOST IS THE ANDROID EMULATOR !!!!!
private static final String URL = "http://192.28.50.46:5555/ws/Monish:TestWebservice?WSDL";
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
//CALL the web service method with the two parameters vname and nname
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
request.addProperty("a", "3");
request.addProperty("b", "4");
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER12);
envelope.setOutputSoapObject(request);
HttpTransportSE androidHttpTransport = new HttpTransportSE (URL);
try {
androidHttpTransport.call(SOAP_ACTION, envelope);
// Get the SAOP Envelope back and the extract the body
SoapObject resultsRequestSOAP = (SoapObject) envelope.bodyIn;
Vector Vec = (Vector) resultsRequestSOAP.getProperty("getMessageReturn");
//Count of the arrays beneath starting from 0
//You can see the buildup with the php site with nusoap http://localhost/DA/nusoapclient_test2.php
int testat = Vec.size();
// It depends on how many arrays we have we can get to the attributs of one of them with get(0), get(1) ....
SoapObject test = (SoapObject) Vec.get(0);
System.out.println(envelope.getResponse());
//Get the attributes in the array
String tem = (String) test.getProperty("a");
tem = tem + " " + (String) test.getProperty("b");
//Just show it in a text area field called lblStatus
((TextView)findViewById(R.id.lblStatus)).setText(tem.toString());
// with androidhttptransport you need a catch block
} catch(Exception E) {
((TextView)findViewById(R.id.lblStatus)).setText("ERROR:" + E.getClass().getName() + ": " + E.getMessage());
}
}
Kindly let me know what the issue is. I'm getting a HTTP error status 500 in Android
I think you need to achieve like this.
You can see full example from here.
Part - 1 : Calling Web Service from Android
Part - 2: Webservice running in Android with Database
I hope this will help you.
Be sure that your are using right namespace or soap action. When you use wrong one, that error occures.

JAXB substitution group marshals but will not unmarshal correctly

I am implementing the OGC Web Feature Service and part of that is creating a feature schema that will inherit from the OGC schema. My service marshals the XML fine, but the client is unable to unmarshal the XML. I wrote a tester that illustrates the problem:
...
ObjectFactory wfsfactory = new ObjectFactory();
net.opengis.gml.v_3_1_1.ObjectFactory gmlfactory = new net.opengis.gml.v_3_1_1.ObjectFactory();
com.example.ObjectFactory exampleFactory = new com.example.ObjectFactory();
OgcJaxbManager manager = OgcJaxbManager.getInstance();
FeatureCollectionType featureCollection = wfsfactory
.createFeatureCollectionType();
FeaturePropertyType prop = gmlfactory.createFeaturePropertyType();
prop.setFeature(exampleFactory.createFoo(exampleFactory.createFoo()));
featureCollection.setFeatureMember(Arrays.asList(prop));
//marshal to XML
String xml = manager.marshal(wfsfactory
.createFeatureCollection(featureCollection));
log.info(xml);
//unmarshal back to object
FeatureCollectionType afterMarshal = (FeatureCollectionType) manager
.unmarshal(xml);
JAXBElement<? extends AbstractFeatureType> feature = afterMarshal
.getFeatureMember().get(0).getFeature();
if (feature == null) {
log.info("null");
} else {
log.info("not null");
}
...
Output:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns4:FeatureCollection xmlns:ns2="http://www.w3.org/1999/xlink" xmlns:ns1="http://www.opengis.net/gml" xmlns:ns4="http://www.opengis.net/wfs" xmlns:ns3="http://www.w3.org/2001/SMIL20/" xmlns:ns9="http://www.opengis.net/wms" xmlns:ns5="http://www.opengis.net/ows/1.1" xmlns:ns6="http://www.opengis.net/ogc" xmlns:ns10="http://example.com" xmlns:ns7="http://www.opengis.net/ows" xmlns:ns11="http://www.w3.org/2001/SMIL20/Language" xmlns:ns8="http://www.opengis.net/wcs/1.1.1">
<ns1:featureMember>
<ns10:foo>
<ns10:bar>0</ns10:bar>
</ns10:foo>
</ns1:featureMember>
</ns4:FeatureCollection>
null
Here is the OGC schema I am extending:
...
<element name="FeatureCollection" type="gml:FeatureCollectionType" substitutionGroup="gml:_Feature"/>
<!-- =========================================================== -->
<complexType name="FeatureCollectionType">
<annotation>
<documentation>Concrete generic feature collection.</documentation>
</annotation>
<complexContent>
<extension base="gml:AbstractFeatureCollectionType"/>
</complexContent>
</complexType>
<!-- =========================================================== -->
<complexType name="AbstractFeatureCollectionType" abstract="true">
<annotation>
<documentation>A feature collection contains zero or more features.</documentation>
</annotation>
<complexContent>
<extension base="gml:AbstractFeatureType">
<sequence>
<element ref="gml:featureMember" minOccurs="0" maxOccurs="unbounded"/>
<element ref="gml:featureMembers" minOccurs="0"/>
</sequence>
</extension>
</complexContent>
</complexType>
<!-- ===== property for feature association ==== -->
<element name="featureMember" type="gml:FeaturePropertyType"/>
<!-- ============================================================== -->
<complexType name="FeaturePropertyType">
<annotation>
<documentation>Container for a feature - follow gml:AssociationType pattern.</documentation>
</annotation>
<sequence minOccurs="0">
<element ref="gml:_Feature"/>
</sequence>
<attributeGroup ref="gml:AssociationAttributeGroup"/>
</complexType>
<!-- ============================================================== -->
<element name="_Feature" type="gml:AbstractFeatureType" abstract="true" substitutionGroup="gml:_GML"/>
<!-- =========================================================== -->
<complexType name="AbstractFeatureType" abstract="true">
<annotation>
<documentation>An abstract feature provides a set of common properties, including id, metaDataProperty, name and description inherited from AbstractGMLType, plus boundedBy. A concrete feature type must derive from this type and specify additional properties in an application schema. A feature must possess an identifying attribute ('id' - 'fid' has been deprecated).</documentation>
</annotation>
<complexContent>
<extension base="gml:AbstractGMLType">
<sequence>
<element ref="gml:boundedBy" minOccurs="0"/>
<element ref="gml:location" minOccurs="0">
<annotation>
<appinfo>deprecated</appinfo>
<documentation>deprecated in GML version 3.1</documentation>
</annotation>
</element>
<!-- additional properties must be specified in an application schema -->
</sequence>
</extension>
</complexContent>
</complexType>
...
Here is my schema:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xsd:schema version="1.0" targetNamespace="http://example.com"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:example="http://example.com"
xmlns:gml="http://www.opengis.net/gml"
elementFormDefault="qualified">
<xsd:import namespace="http://www.opengis.net/gml"
schemaLocation="http://schemas.opengis.net/gml/3.1.1/base/gml.xsd"/>
<xsd:element name="foo" type="example:foo"
substitutionGroup="gml:_Feature"/>
<xsd:complexType name="foo">
<xsd:complexContent>
<xsd:extension base="gml:AbstractFeatureType">
<xsd:sequence>
<xsd:element name="bar" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>
Here is the POJO that xjc produces:
package com.example;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "foo", propOrder = { "bar" })
public class Foo extends AbstractFeatureType {
protected String bar;
...
Any help would be greatly appreciated.
I made this work, with two caveats.
You didn't post the ObjectContext for com.example, so I used a hand-coded ObjectContext. It is critical to include the
substitutionHeadNamespace="http://www.opengis.net/gml" and substitutionHeadName="_Feature"
values in the #XmlElementDecl for the factory method, otherwise I see the same symptoms, i.e. marshalling OK, unmarshalling is empty, but no exceptions.
com.example.ObjectContext looks like this:
package com.example;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlElementDecl;
import javax.xml.bind.annotation.XmlRegistry;
import javax.xml.namespace.QName;
#XmlRegistry
public class ObjectFactory {
public ObjectFactory() { }
public Foo createFoo() { return new Foo(); }
#XmlElementDecl(namespace="http://example.com",
name="foo",
substitutionHeadNamespace="http://www.opengis.net/gml",
substitutionHeadName="_Feature")
public JAXBElement<Foo> createFoo(Foo foo) {
return new JAXBElement<Foo>(new QName("http://example.com", "foo"), Foo.class, foo);
}
}
com.example.Foo looks like this, including main:
package com.example;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Arrays;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.XmlAccessType;
import net.opengis.gml.v_3_1_1.AbstractFeatureType;
import net.opengis.gml.v_3_1_1.FeaturePropertyType;
import net.opengis.wfs.v_1_1_0.FeatureCollectionType;
import net.opengis.wfs.v_1_1_0.ObjectFactory;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "foo", propOrder = { "bar" })
public class Foo extends AbstractFeatureType {
#XmlElement
protected String bar = "0";
#Override
public Object createNewInstance() {
return new Foo();
}
public static void main(String[] args) throws JAXBException {
ObjectFactory wfsfactory = new ObjectFactory();
net.opengis.gml.v_3_1_1.ObjectFactory gmlfactory = new net.opengis.gml.v_3_1_1.ObjectFactory();
com.example.ObjectFactory exampleFactory = new com.example.ObjectFactory();
FeatureCollectionType featureCollection = wfsfactory
.createFeatureCollectionType();
FeaturePropertyType prop = gmlfactory.createFeaturePropertyType();
prop.setFeature(exampleFactory.createFoo(exampleFactory.createFoo()));
featureCollection.setFeatureMember(Arrays.asList(prop));
//marshal to XML
JAXBContext ctx = JAXBContext.newInstance(ObjectFactory.class, net.opengis.gml.v_3_1_1.ObjectFactory.class, com.example.ObjectFactory.class);
StringWriter sw =new StringWriter();
Marshaller marshaller = ctx.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(wfsfactory.createFeatureCollection(featureCollection), sw);
System.out.println(sw.toString());
//unmarshal back to object
JAXBElement<FeatureCollectionType> afterMarshal = (JAXBElement<FeatureCollectionType>)
ctx.createUnmarshaller().unmarshal(new StringReader(sw.toString()));
JAXBElement<? extends AbstractFeatureType> feature = afterMarshal
.getValue().getFeatureMember().get(0).getFeature();
if (feature == null) {
System.out.println("null");
} else {
System.out.println("not null");
}
}
}
And this is the output I get:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns3:FeatureCollection xmlns:ns2="http://www.w3.org/1999/xlink" xmlns:ns1="http://www.opengis.net/gml" xmlns:ns4="http://example.com" xmlns:ns3="http://www.opengis.net/wfs" xmlns:ns5="http://www.w3.org/2001/SMIL20/" xmlns:ns6="http://www.opengis.net/ogc" xmlns:ns7="http://www.opengis.net/ows" xmlns:ns8="http://www.w3.org/2001/SMIL20/Language">
<ns1:featureMember>
<ns4:foo>
<ns4:bar>0</ns4:bar>
</ns4:foo>
</ns1:featureMember>
</ns3:FeatureCollection>
not null
Good luck going forward!

Categories