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());
}
}
Related
I am having trouble to unmarshall my data. I got the following error:
ERROR FsceClient - Error in getDataInMatches : unexpected element
(uri:"", local:"SearchAndList"). Expected elements are (none)
requested params:+COUNTRY=US+YR=2016+DIV=Ford+WB=122.0
javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"SearchAndList"). Expected elements are (none)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:726)
This is my xml file:
<SearchAndList>
<fvd>
+COUNTRY=US+YR=2016+DIV=Ford+WB=122.0
</fvd>
<sol>
<rsi>
<sType>Ss</sType>
<mHave>true</mHave>
<toAr>0</toAr>
<toAr>0</toAr>
<toAr>22</toAr>
</rsi>
<rsi>
<sType>ssa</sType>
<mHave>true</mHave>
<toAr>77</toAr>
</rsi>
</sol>
<sol>
<rsi>
<sType>sve</sType>
<mHave>false</mHave>
<toAr>0</toAr>
<toAr>21</toAr>
</rsi>
</sol>
</SearchAndList>
This is encountered when the XSD schema does not contain element definitions and only contains class definitions (i.e. complex types).
e.g. for this XSD,
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="foo">
<xs:sequence>
<xs:element name="bar" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
The object factory created is like this:
#XmlRegistry
public class ObjectFactory {
public ObjectFactory() {
}
public Foo createFoo() {
return new Foo();
}
}
BUT FOR THIS XSD:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="foo" type="foo" nillable="true"/>
<xs:complexType name="foo">
<xs:sequence>
<xs:element name="bar" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
The ObjectFactory class created by JAXB is:
#XmlRegistry
public class ObjectFactory {
private final static QName _Foo_QNAME = new QName("", "foo");
public ObjectFactory() {
}
public Foo createFoo() {
return new Foo();
}
#XmlElementDecl(namespace = "", name = "foo")
public JAXBElement<Foo> createFoo(Foo value) {
return new JAXBElement<Foo>(_Foo_QNAME, Foo.class, null, value);
}
}
You can see that the JAXBElement wrapper creation method is also added. With the second XSD, the unmarshaller knows what to do when it encounters a tag with name "foo". So if you have an XSD, add "element" definitions as well as the complex types.
----- EDIT----
The sample unmarshaller code:
JAXBContext jaxbContext = JAXBContext.newInstance(ObjectFactory.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Object result = ((JAXBElement<Object>) jaxbUnmarshaller.unmarshal(stream)).getValue();
I am running into multiple namespaces while marshalling a complex type Element(contains list of Element in it Example: device see below) using JAXB. Appreciate any help in getting the desired output as mentioned below.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Request xmlns="urn:ietf:params:xml:ns:geopriv:held"
xmlns:ns2="urn:ietf:params:xml:ns:geopriv:held:id"
xmlns:ns3="urn:ietf:params:xml:ns:geopriv:held:vendor" responseTime="10">
<ns2:device xmlns="urn:ietf:params:xml:ns:geopriv:held:id"
xmlns:ns2="urn:ietf:params:xml:ns:geopriv:held">
<uri>http://stackoverflow.com</uri>
</ns2:device>
Here device is a complex type element as defined in the extension schema. I am working with many schema's.
But the desired output without the extra namespaces around device complex type element is like this:
<?xml version="1.0" encoding="utf-8"?>
<Request xmlns="urn:ietf:params:xml:ns:geopriv:held" responseTime="10">
<device xmlns="urn:ietf:params:xml:ns:geopriv:held:id">
<uri>http://stackoverflow.com</uri>
</device>
</Request>
Device Schema:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema targetNamespace="urn:ietf:params:xml:ns:geopriv:held:id"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:id="urn:ietf:params:xml:ns:geopriv:held:id"
elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="device" type="id:deviceIdentity" />
<xs:complexType name="deviceIdentity">
<xs:sequence>
<xs:any xmlns:id="urn:ietf:params:xml:ns:geopriv:held:id"
processContents="strict" minOccurs="0"
maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
Marshalling Code:
final JAXBElement<String> uri = objectFactory.createUri(uri);
Element elt = XmlMarshaller.getDomElement(uri, String.class);
final Device device = objectFactory.createDevice();
if (elt != null) {
device.getAnies().add(elt);
}
elt = XmlMarshaller.getDomElement(device, Device.class);
Request.getAnies().add(elt);
Element getDomElement(final Object object, final Class<?> clazz) throws JAXBException {
final JAXBContext jaxbContext = JAXBContext.newInstance(clazz);
final Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
final DOMResult res = new DOMResult();
jaxbMarshaller.marshal(object, res);
final Element elt = ((Document) res.getNode()).getDocumentElement();
return (elt);
}
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;
}
}
I have the following in a WSDL file:
<definitions xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:tns="urn:zimbraAdmin"
xmlns:zns="urn:zimbra"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:si="http://soapinterop.org/xsd"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns="http://schemas.xmlsoap.org/wsdl/"
targetNamespace="urn:zimbraAdmin">
<element name="AuthResponse">
<complexType>
<sequence>
<element name="authToken" type="xsd:string" />
<element name="lifetime" type="xsd:string"/>
<element ref="tns:a" maxOccurs="unbounded"/>
</sequence>
</complexType>
</element>
<message name="AuthResponse">
<part name="AuthResponse" element="tns:AuthResponse"/>
</message>
<operation name="AuthRequest">
<input message="tns:AuthRequest"/>
<output message="tns:AuthResponse"/>
</operation>
However, when the following request gets sent:
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:AuthRequest xmlns:ns2="urn:zimbraAdmin" xmlns:ns3="urn:zimbra">
<name>admin</name>
<password>password</password>
</ns2:AuthRequest>
</S:Body>
</S:Envelope>
The following comes back:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<context xmlns="urn:zimbra">
<change token="2099" />
</context>
</soap:Header>
<soap:Body>
<AuthResponse xmlns="urn:zimbraAdmin">
<authToken>0_c728cf3ae4049ecb8fa5eb19f19397e4661e53a2_69643d33363a38373861353736372d356630632d343266352d623466372d6166666163383064326133643b6578703d31333a313337343533383131303638333b61646d696e3d313a313b747970653d363a7a696d6272613b</authToken>
<lifetime>43199997</lifetime>
<a n="zimbraIsDomainAdminAccount">false</a>
</AuthResponse>
</soap:Body>
</soap:Envelope>
The problem I have is that authToken and lifetime are not assigned (i.e. they come back null)
The code generated for AuthResponse (which was generated with cxf 2.7.5 wsdl2java) looks like follows:
#XmlRootElement(name = "AuthResponse")
public class AuthResponse {
#XmlElement(required = true)
protected String authToken;
#XmlElement(required = true)
protected String lifetime;
#XmlElement(namespace = "urn:zimbraAdmin", required = true)
protected List<A> a;
I believe that if it read as follows my problems would be solved:
#XmlRootElement(name = "AuthResponse")
public class AuthResponse {
#XmlElement(namespace = "urn:zimbraAdmin",required = true)
protected String authToken;
#XmlElement(namespace = "urn:zimbraAdmin",required = true)
protected String lifetime;
#XmlElement(namespace = "urn:zimbraAdmin", required = true)
protected List<A> a;
The question is, what do I need to change in the WSDL file so that the correct code for the client is generated?
EDIT
For reference, I am using the zimbra.wsdl available from http://blog.jeshurun.ca/wp-content/uploads/2011/12/zimbra.wsdl
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!