While generating JAX-WS web service client code using wsimport, it generates Object factory top level method input and output type. This restricts the use to marshal and unmarshal classes which are contained within the top level objects.
More often than not, top level Schema objects are non-domain specific objects like MethodInput/MethodOutput. You can unmarshal them using ObjectFactory
ObjectFactory.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@XmlRegistry | |
public class ObjectFactory { | |
// ... | |
private final static QName Query1_QNAME = new QName("urn:Account-WSDL", "query"); | |
// ... | |
} |
query.xml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<query xmlns="urn:Account-WSDL"> | |
<serviceContext> | |
<externalUserName>USR</externalUserName> | |
</serviceContext> | |
<account> | |
<accountKey> | |
<location>Texas</location> | |
<number>6086510</number> | |
<code>06</code> | |
</accountKey> | |
</account> | |
</query> |
MethodInput.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@XmlAccessorType(XmlAccessType.FIELD) | |
@XmlType(name = "MethodInput", propOrder = { | |
"serviceContext", | |
"account" | |
}) | |
public class MethodInput{ | |
@XmlElement(required = true) | |
protected ServiceContext serviceContext; | |
@XmlElement(required = true) | |
protected Account account; | |
// .... omitted for brevity | |
} |
JaxbUnmarshallerMethodInput.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class JaxbUnmarshallerMethodInput{ | |
public static void main(String args[]){ | |
try{ | |
JAXBContext jc = JAXBContext.newInstance("com.kartikshah.api.account.wsdl"); | |
Unmarshaller u = jc.createUnmarshaller(); | |
JAXBElement element = (JAXBElement)u.unmarshal(JaxbUnmarshallerMethodInput.class.getResource("query.xml")); | |
MethodInput methodInput = (MethodInput)element.getValue(); | |
Account account = methodInput.getAccount(); | |
ServiceContext context = methodInput.getServiceContext(); | |
} | |
catch (Exception e){ | |
// Removed for brevity | |
} | |
} | |
} |
But if you want to unmarshal XML chunks of objects contained within those top level object, the same approach does not work, if those generated classes are not included as part of ObjectFactory or they do not have annotation @XmlRootElement on top of that.
account.xml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<account> | |
<accountKey> | |
<location>Texas</location> | |
<number>6086510</number> | |
<code>06</code> | |
</accountKey> | |
</account> |
Option 1
So the obvious option is to add @XmlRootElement to any generated classes that you want to unmarshal directly, but when you are using wsdls are from an external source, idea of updating generated classes breaks the process.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@XmlRootElement | |
@XmlAccessorType(XmlAccessType.FIELD) | |
@XmlType(name = "Account", propOrder = { | |
"accountKey", // .. other fields omitted for brevity | |
}) | |
public class Account{ | |
protected AccountKey accountKey; | |
// ... | |
} |
Option 2
Another option is to pass the child element's Node object to unmarshal
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class JaxbUnmarshallerWithDocBuilder { | |
public static void main(String args[]){ | |
try{ | |
JAXBContext jc = JAXBContext.newInstance("com.kartikshah.api.account.wsdl"); | |
Unmarshaller u = jc.createUnmarshaller(); | |
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); | |
dbf.setNamespaceAware(true); | |
DocumentBuilder db = dbf.newDocumentBuilder(); | |
Document doc = db.parse(JaxbUnmarshallerWithDocBuilder.class.getResource("account.xml")); | |
Node fooSubtree = doc.getFirstChild(); | |
JAXBElement<Account> account = u.unmarshal( fooSubtree, Account.class); | |
} | |
catch (Exception e){ | |
// ... Omitted for brevity | |
} | |
} |
4 comments:
thanks men - good post
thanks man - option 2 was very helpful for me
I have 2 xsd files
Element from XSD A
element from XSD B
When I try to marshal "LifeObj" EXception I am getting is
[com.sun.istack.internal.SAXException2: unable to marshal type "packagebname.ProcessParameters" as an element because it is missing an @XmlRootElement annotation]
Code i am using is
ProcessParameters parametersType = new ProcessParameters();
parametersType.setTransactionID("TXID");
ExtensionObj eExtensionType = new ExtensionObj();
eExtensionType.getContent().add(parametersType);
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
File SEEC_Life_xsd = new File("xsd/Life.xsd");
Schema schema = schemaFactory.newSchema(Life_xsd);
JAXBContext jc = JAXBContext.newInstance(ObjectFactory.class.getPackage().getName());
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(javax.xml.bind.Marshaller.JAXB_ENCODING, "UTF-8");
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.setSchema(schema);
marshaller.marshal(new JAXBElement(new QName(url,"ExtensionObj"), ExtensionObj.class, eExtensionType), System.out);
Thanks, this was the post that finally solved my problem!
Post a Comment