JAXB substitution group marshals but will not unmarshal correctly - java

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!

Related

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());
}
}

jax ws double tostring change format

We get the WSDLs from our customer. (I.e., we can't change them.)
The definition of one of the types looks something like this:
<complexType name="Type1">
<complexContent>
<restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
<sequence>
<element name="value" minOccurs="0">
<complexType>
<complexContent>
<restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
<choice>
<element name="bigdecimal" type="{http://www.w3.org/2001/XMLSchema}double"/>
<element name="date" type="{http://www.w3.org/2001/XMLSchema}date"/>
<element name="string" type="{http://www.w3.org/2001/XMLSchema}string"/>
</choice>
</restriction>
</complexContent>
</complexType>
</element>
<element name="element2" type="{http://www.w3.org/2001/XMLSchema}integer" minOccurs="0"/>
</sequence>
</restriction>
</complexContent>
</complexType>
resulting in things like
public void setBigdecimal(Double value) {
this.bigdecimal = value;
}
Now when we send a request with this type in it, it will generate something like this:
<rpcOp:value>
<rpcOp:bigdecimal>10.0</rpcOp:bigdecimal> <!-- IN SPITE OF THE NAME, THIS IS A DOUBLE VALUE! -->
<rpcOp:string>N</rpcOp:string>
</rpcOp:value>
The customer wants the content of to be shown without decimal digits, i.e., 10 etc.
I suspect that when generating the request xml from the Java objects, the JAX-WS framework simply calls Double.toString(), which will inevitably add a decimal point and a decimal digit.
Is there a way to change this without being able to modify the WSDL? Register some custom number formatter for this type or something like this?
Thanks!
In the meantime I found a solution. It looks something like this: (using JAXB)
xjc-serializable.xml :
...
<jaxb:globalBindings>
<xjc:serializable />
<!-- ADDED THIS: -->
<xjc:javaType name="java.lang.Double" xmlType="xs:double"
adapter="util.MyDoubleAdapter" />
</jaxb:globalBindings>
...
Then the java class:
public class MyDoubleAdapter extends XmlAdapter<String, Double> {
#Override
public String marshal(Double doubleValue) throws Exception {
if (doubleValue == null) {
return null;
}
String string = doubleValue.toString();
if (string.endsWith(".0")) {
string = string.replaceAll("\\.0", "");
}
return string;
}
public Double unmarshal(String stringValue) throws Exception {
if (stringValue == null) {
return null;
}
return Double.valueOf(stringValue);
}
}
And there you go.

Mixed Content for JAXB not working from WSDL

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;
}
}

Different parent child namespace prefix expected

I have two xsds from which i have generated jaxb pojos using xjc. And i have generated XMLs using jaxb marshaller with jaxb-impl-2.2.6
For this I have overriden NamespacePrefixMapper as MyNamespacePrefixMapper
Parent.xsd
<xs:schema targetNamespace="parent"
elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:Env="Parent"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:child="urn:xsd:child">
<xs:import namespace="urn:xsd:child" schemaLocation="child.xsd"/>
<xs:element name="parent">
<xs:complexType>
<xs:sequence>
<xs:element name="child" type="child:child1"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
child.xsd
<xs:schema xmlns="urn:xsd:child" xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="urn:xsd:child">
<xs:element name="child" type="child1"/>
<xs:complexType name="child1">
<xs:sequence>
<xs:element name="Id" type="Max20Text"/>
</xs:sequence>
</xs:complexType>
<xs:simpleType name="Max20Text">
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="20"/>
</xs:restriction>
</xs:simpleType>
XmlMarshallingTest.java
import javax.xml.bind.*;
import javax.xml.stream.XMLStreamException;
import org.junit.Test;
import parent.Parent;
import xsd.child.Child1;
public class XmlMarshallingTest {
#Test
public void testXmlMarshalling() throws JAXBException, XMLStreamException{
Parent envelope = new Parent();
Child1 businessApplicationHeaderV01 = new Child1();
businessApplicationHeaderV01.setId("ABC123");
envelope.setChild(businessApplicationHeaderV01);
JAXBContext context = JAXBContext.newInstance(envelope.getClass());
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", new MyNamespacePrefixMapper());
marshaller.marshal(envelope, System.out);
}
}
MyNamespacePrefixMapper.java
import com.sun.xml.bind.marshaller.NamespacePrefixMapper;
import com.sun.xml.bind.marshaller.NamespacePrefixMapper;
public class MyNamespacePrefixMapper extends NamespacePrefixMapper {
#Override
public String getPreferredPrefix(String namespaceUri, String suggestion, boolean arg2) {
if("Parent".equals(namespaceUri)) {
return "parentPrefix";
} else if("urn:xsd:child".equals(namespaceUri)) {
return "childPrefix";
}
return "defaultPrefix";
}
}
the generated xml is like
<parentPrefix:parent xmlns:childPrefix="urn:xsd:child" xmlns:parentPrefix="parent">
<parentPrefix:child>
<childPrefix:Id>ABC123</childPrefix:Id>
</parentPrefix:child>
</parentPrefix:parent>
Here, my problem is , I expect the xml to be look like following
<parentPrefix:parent xmlns:childPrefix="urn:xsd:child" xmlns:parentPrefix="parent">
<childPrefix:child>
<childPrefix:Id>ABC123</childPrefix:Id>
</childPrefix:child>
</parentPrefix:parent>
I expect the prefix of child tag to be "childPrefix" but it shows "parentPrefix"
The parent tag is well generated with prefix "parentPrefix"
Environment Description
Maven 3.0.4
Java version: 1.7.0_04
OS : windows 7
Your schema defines the parent element as having a child element named child in the parent schema's own targetNamespace, whose type happens to come from the child namespace. If you want the parent to use the child element that is defined in the child schema (and thus in the urn:xsd:child namespace) then instead of
<xs:element name="child" type="child:child1"/>
you need
<xs:element ref="child:child"/>

JAXB :Class cast exception while trying to unmarshall XML using JAXB

I am novice to JAXB , i am trying to sample using JAXB.
trying to dispaly the values in the MenuList.xml
----MenuList.xml-----------
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<menulist xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Category1 name="Development">
<MenuItem1>Projects</MenuItem1>
<MenuItem2>Library</MenuItem2>
<MenuItem3>Library1</MenuItem3>
</Category1>
</menulist>
----------------------------MenuList.xsd-------------------
<?xml version="1.0" encoding="utf-8" ?>
<!--Created with Liquid XML Studio Developer Edition (Trial) 8.0.11.2171 (http://www.liquid-technologies.com)-->
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="menulist">
<xs:complexType>
<xs:sequence>
<xs:element name="Category1">
<xs:complexType>
<xs:attribute name="MenuItem1" type="xs:string" use="required" />
<xs:attribute name="MenuItem2" type="xs:string" use="required" />
<xs:attribute name="MenuItem3" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
The uisng the command I run the xsd file and it generated the classes.
MenuList and Object Factory.
AppTest.java
package com.xx.menu;
import java.io.File;
import java.io.IOException;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.UnmarshalException;
import javax.xml.bind.Unmarshaller;
public class TestNew {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
JAXBContext jc = JAXBContext.newInstance("com.xx.menu"); //Create unmarshaller
Unmarshaller um = jc.createUnmarshaller();
File file = new File ("C:\\sample\\menulist.xml");
JAXBElement element = (JAXBElement)um.unmarshal(file);
Menulist menulist= (Menulist) element.getValue ();
System.out.println("name : "+menulist.getMenu());
}
catch( UnmarshalException ue ) {
ue.printStackTrace();
System.out.println( "Caught UnmarshalException" );
} catch( JAXBException je ) {
je.printStackTrace();
} catch( Exception ioe ) {
ioe.printStackTrace();
}
}
}
Error:
java.lang.ClassCastException: com.xx.menu.Menulist
at com.xx.menu.TestNew.main(TestNew.java:26)
Can you please help me where I am going wrong ...I will be greatly thankful to you.
Thanks
You're overcomplicating things. You don't need to muck about with JAXBElement if the Unmarshaller is giving you the Menulist object directly. The ClassCastExcepotion pretty much tells you what you need to do:
Menulist menulist= (Menulist) um.unmarshal(file);
JAXBElement is only used in certain specific situations, and this isn't one of them.
Could you please add a short description about when JAXBElement is to
be used?
JAXBElement is used by JAXB when a class or property does not contain enough information by itself to indicate what element should be written to XML.
#XmlRootElement
In your example the Menulist class corresponds to the menulist element. Since in the schema that element has an anonymous complex type, one element is associated with the class generated from the corresponding complex type.
#XmlElementDecl
If in your example the menulist element had corresponded to a named complex type, then potentially multiple elements could correspond to the same class generated from that complex type. Instead of annotating the class with #XmlRootElement, one or more #XmlElementDecl annotations would be generated on the ObjectFactory class. This would cause JAXBElement to be unmarshalled.
Handling All Results
If you don't know whether or not a JAXBElement will be returned you can leverage a JAXBIntrospector to do any necessary unwrapping.
JAXBIntrospector ji = jaxbContext.createJAXBIntrospector();
Menulist menulist = (Menulist) ji.getValue(unmarshaller.unmarshal(xml));
For More Information
http://blog.bdoughan.com/2012/07/jaxb-and-root-elements.html

Categories