Can't unmarshal marshalled document when default namespace used - java

I set up a repo which shows my problem: https://github.com/Waxolunist/stackoverflow.34392476
I try to unmarshal a simple xml document:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<for:document xmlns:for="http://www.adcubum.com/wsdl/global/callout/syrius/modul_bl/doc/service/documentrenderer/forwktbx">
<Export xmlns="urn:adcubum:Syrius">
<ExportInhalt/>
<ExportKopf>
<Quelle>lokal</Quelle>
</ExportKopf>
<SchemaVersion>bec811a9807a8c8da403d70b9b5e22ad</SchemaVersion>
</Export>
</for:document>
This is the document I get from following code:
Document document = new Document();
Export export = new Export();
ExportKopf exportKopf = new ExportKopf();
exportKopf.setQuelle("lokal");
export.setExportKopf(exportKopf);
ExportInhalt exportInhalt = new ExportInhalt();
export.setExportInhalt(exportInhalt);
export.setSchemaVersion("bec811a9807a8c8da403d70b9b5e22ad");
document.setExport(export);
JAXBContext jaxbContext = JAXBContext.newInstance(Document.class);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(document, System.out);
Document looks as follows:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "document", namespace = "http://www.adcubum.com/wsdl/global/callout/syrius/modul_bl/doc/service/documentrenderer/forwktbx")
public class Document {
#XmlElement(name = "Export", namespace = "urn:adcubum:Syrius")
private vo.dom.common_service.modul_bl.syrius.Export export;
}
package-info.java
#XmlSchema(
namespace = "urn:adcubum:Syrius",
xmlns = {
#XmlNs(prefix = "for", namespaceURI = "http://www.adcubum.com/wsdl/global/callout/syrius/modul_bl/doc/service/documentrenderer/forwktbx"),
#XmlNs(prefix = "", namespaceURI = "urn:adcubum:Syrius")
},
elementFormDefault = XmlNsForm.UNQUALIFIED)
When I try to unmarshal it, I don't get the data mapped:
JAXBContext jaxbContext = JAXBContext.newInstance(Document.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
InputStream is = this.getClass().getResourceAsStream("/requests/document_simple3.xml");
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLStreamReader xmlsr = factory.createXMLStreamReader(is);
Document document = unmarshaller.unmarshal(xmlsr, Document.class).getValue();
ExportKopf and ExportInhalt are returning null.
Instead following xml works. The only difference is the namespace prefix:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<for:document xmlns:for="http://www.adcubum.com/wsdl/global/callout/syrius/modul_bl/doc/service/documentrenderer/forwktbx">
<ns3:Export xmlns:ns3="urn:adcubum:Syrius">
<ExportInhalt/>
<ExportKopf>
<Quelle>lokal</Quelle>
</ExportKopf>
<SchemaVersion>bec811a9807a8c8da403d70b9b5e22ad</SchemaVersion>
</ns3:Export>
</for:document>
I am using eclipselink moxy.
What do I have to change, so that unmarshaling the marshaled document works.

I think it's always a good idea to see the actual XSD schema of your mapping whenever something strange like this is happening in JAXB. You could easily do that with the following code.
JAXBContext jaxbContext = JAXBContext.newInstance(Document.class);
jaxbContext.generateSchema(new SchemaOutputResolver() {
#Override
public Result createOutput(String namespaceUri, String suggestedFileName) throws IOException {
StreamResult streamResult = new StreamResult(new PrintWriter(System.err) {
#Override
public void close() {
}
});
streamResult.setSystemId(suggestedFileName);
return streamResult;
}
});
That will print the schema(s) that should reflect your JAXB model (you can use another writer to write them to a file). The XSD files are usually very revealing about these kind of issues. I think the problem in your case is the #XmlSchema mapping. You should try to use elementFormDefault = XmlNsForm.QUALIFIED instead. It's always a good idea to use QUALIFIED whenever you're working with multiple namespaces in your mapping.
EDIT: while the main problem with your JAXB mapping was the wrong and/or missing value for the elementFormDefault there were other things that had to be fixed for the code in your repo to work.
the Export element in the Document was missing a namespace declaration (from your example, the Document and Export elements are parts of different namespaces)
missing elementFormDefault = XmlNsForm.QUALIFIED from the export package
wrong namespace value for your main package #XmlSchema annotation (was urn:stackoverflow:exportnamespace instead of urn:stackoverflow:documentnamespace in which the Document element should be)
wrong import for jdk_jaxb/UnmarshallerTest.java - it was importing the model.eclipselink.Document instead of model.sun.Document

EDIT: Here's the updated code https://github.com/MojoJojo/stackoverflow.34392476
Okay, here's the working version with all moxy_jaxb test passing. Because you said you are using moxy, I left out the changes for model.sun.* packages. If you understand the concept below, you should be able to fix it easily on your own.
First, I cleaned up namespace declarations in your mode.* packages. Most of the times, the declarations and bindings inside package-info.java suffice. Declaring them over and over again on package, entities, fields will add to complexity and unwanted behavior. Check out this link for details. There is no need to re-declare them on the individual Models/Entities themselves, unless there is a strong reason to do otherwise. Next, the test xml itself was a little broken. Fixed the test xml with proper prefixes wherever necessary:
First, model.eclipselink.Document.java
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "document")
public class Document {
#XmlElement(name = "Export", namespace="urn:adcubum:Syrius")
private Export export;
public Export getExport() {
return export;
}
public void setExport(Export export) {
this.export = export;
}
}
model.eclipselink.package-info.java:
#XmlSchema(namespace = "http://www.adcubum.com/wsdl/global/callout/syrius/modul_bl/doc/service/documentrenderer/forwktbx",
elementFormDefault = XmlNsForm.QUALIFIED)
package model.eclipselink;
import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
Similar refactoring on model.eclipselink.export.packageinfo.java:
#XmlSchema(namespace = "urn:adcubum:Syrius",
elementFormDefault = XmlNsForm.QUALIFIED)
package model.eclipselink.export;
import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.Xml
And on Export.java:
package model.eclipselink.export;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import org.eclipse.persistence.oxm.annotations.XmlElementNillable;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "Export")
#XmlType(name = "Export", propOrder = {
"exportInhalt",
"exportKopf",
"schemaVersion"
})
public class Export {
#XmlElement(name = "ExportKopf", required = true)
private ExportKopf exportKopf;
#XmlElement(name = "ExportInhalt", required = true)
private ExportInhalt exportInhalt;
#XmlElement(name = "SchemaVersion", required = true)
private String schemaVersion;
public ExportKopf getExportKopf() {
return exportKopf;
}
public void setExportKopf(ExportKopf exportKopf) {
this.exportKopf = exportKopf;
}
public ExportInhalt getExportInhalt() {
return exportInhalt;
}
public void setExportInhalt(ExportInhalt exportInhalt) {
this.exportInhalt = exportInhalt;
}
public String getSchemaVersion() {
return schemaVersion;
}
public void setSchemaVersion(String schemaVersion) {
this.schemaVersion = schemaVersion;
}
}
And the few tweaks to your xml files for prefixes.Here's document_prefix.xml
<?xml version="1.0" encoding="UTF-8"?>
<for:document xmlns:for="http://www.adcubum.com/wsdl/global/callout/syrius/modul_bl/doc/service/documentrenderer/forwktbx">
<ns1:Export xmlns:ns1="urn:adcubum:Syrius">
<ns1:ExportKopf>
<ns1:Quelle>lokal</ns1:Quelle>
</ns1:ExportKopf>
<ns1:ExportInhalt/>
<ns1:SchemaVersion>bec811a9807a8c8da403d70b9b5e22ad</ns1:SchemaVersion>
</ns1:Export>
</for:document>
document.xml:
<?xml version="1.0" encoding="UTF-8"?>
<for:document
xmlns:for="http://www.adcubum.com/wsdl/global/callout/syrius/modul_bl/doc/service/documentrenderer/forwktbx" xmlns="urn:adcubum:Syrius">
<Export>
<ExportKopf>
<Quelle>lokal</Quelle>
</ExportKopf>
<ExportInhalt />
<SchemaVersion>bec811a9807a8c8da403d70b9b5e22ad</SchemaVersion>
</Export>
</for:document>
and document_realnamespace.xml (Not sure what the purpose of this file is):
<?xml version="1.0" encoding="UTF-8"?>
<for:document xmlns:ns1="urn:adcubum:Syrius" xmlns:for="http://www.adcubum.com/wsdl/global/callout/syrius/modul_bl/doc/service/documentrenderer/forwktbx">
<ns1:Export>
<ns1:ExportKopf>
<ns1:Quelle>lokal</ns1:Quelle>
</ns1:ExportKopf>
<ns1:ExportInhalt/>
<ns1:SchemaVersion>bec811a9807a8c8da403d70b9b5e22ad</ns1:SchemaVersion>
</ns1:Export>
</for:document>
And you run mvn clean test:
Running moxy_jaxb.MarshallerTest
Context class: class org.eclipse.persistence.jaxb.JAXBContext
<?xml version="1.0" encoding="UTF-8"?>
<document xmlns="http://www.adcubum.com/wsdl/global/callout/syrius/modul_bl/doc/service/documentrend
erer/forwktbx" xmlns:ns0="urn:adcubum:Syrius">
<ns0:Export>
<ns0:ExportInhalt/>
<ns0:ExportKopf>
<ns0:Quelle>lokal</ns0:Quelle>
</ns0:ExportKopf>
<ns0:SchemaVersion>bec811a9807a8c8da403d70b9b5e22ad</ns0:SchemaVersion>
</ns0:Export>
</document>
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.044 sec
Running moxy_jaxb.UnmarshallerTest
Context class: class org.eclipse.persistence.jaxb.JAXBContext
lokal
Context class: class org.eclipse.persistence.jaxb.JAXBContext
lokal
Context class: class org.eclipse.persistence.jaxb.JAXBContext
lokal
Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.033 sec

Related

Reading my XML with JAXB

I have an xml:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<measures>
<measure isapplicationaggregated="true" errorseverity="none" servicecontext="SERVER" userdefined="false" id=".NET % Time in Jit" calculatepercentiles="false" createdtimestamp="1478709202942" errortype="none" rate="purepath" description="Percentage of elapsed time spent in JIT compilation since the last JIT compilation phase." ischartable="true" metricid=".NET % Time in Jit" measuretype="PerfMonMeasure" isaggregated="false" metricgroupid=".NET Common Language Runtime" displayaggregations="7" calculatebaseline="false" displayunit="percent">
<perfmonperformancecounter performanceobject=".NET CLR Jit" instance="{monitored_process}" performancecounter="% Time in Jit" />
<color color.blue="64" color.green="0" color.red="64" />
</measure>
<measure isapplicationaggregated="true" errorseverity="none" servicecontext="SERVER" userdefined="false" id=".NET Garbage Collection (# Gen 0)" calculatepercentiles="false" createdtimestamp="1478709202942" errortype="none" rate="purepath" description="Number of times the generation 0 objects were garbage collected (Gen 0 GC) per interval." ischartable="true" metricid=".NET Garbage Collection (# Gen 0)" measuretype="PerfMonMeasure" isaggregated="false" metricgroupid=".NET Common Language Runtime" displayaggregations="31" calculatebaseline="false" displayunit="number">
<perfmonperformancecounter performanceobject=".NET CLR Memory" instance="{monitored_process}" performancecounter="# Gen 0 Collections" />
<color color.blue="64" color.green="192" color.red="128" />
</measure>
</measures>
I need to translate it using the JAXB reader except it keeps saying it cannot read it.
I only need the userdefined , id , and measuretype properties from the measure object.
The code below is what I have so far:
XML
#XmlRootElement(name = "measures")
public class MeasureListWrapper {
private List<Property> measureProperties = new ArrayList<Property>();
#XmlElement(name="measure")
public List<Property> getMeasures() {
return measureProperties;
}
}
MainApp:
JAXBContext context = JAXBContext.newInstance(MeasureListWrapper.class);
Unmarshaller um = context.createUnmarshaller();
// Reading XML from the file and unmarshalling.
MeasureListWrapper wrapper = (MeasureListWrapper) um.unmarshal(file);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_NO_NAMESPACE_SCHEMA_LOCATION, "file:///C:/Users/mydesk/Desktop/FirstXSD.xml");
marshaller.marshal(wrapper, System.out);
I am new to JAXB and can't get this to work. Really I just need to export the preferred properties to a text file after I pull them from this xml.
I would also like to store the ID's and measuretypes to display in a table in my applet window.
Any help?
Thanks!
This worked for me:
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class MeasureParser {
#XmlRootElement(name = "measure")
public static class Measure {
#XmlAttribute(name = "id")
private String id;
#XmlAttribute(name = "measuretype")
private String measureType;
#XmlAttribute(name = "userdefined")
private boolean userDefined;
}
#XmlRootElement(name = "measures")
public static class MeasureListWrapper {
private List<Measure> measureProperties = new ArrayList<>();
#XmlElement(name = "measure")
public List<Measure> getMeasures() {
return measureProperties;
}
}
public static void main(String[] args) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(MeasureListWrapper.class);
Unmarshaller um = context.createUnmarshaller();
// Reading XML from the file and unmarshalling.
MeasureListWrapper wrapper = (MeasureListWrapper) um.unmarshal(new File("test.xml"));
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_NO_NAMESPACE_SCHEMA_LOCATION, "file:///C:/Users/mydesk/Desktop/FirstXSD.xml");
marshaller.marshal(wrapper, System.out);
}
}

JAXB unmarshall element children as plain text [duplicate]

Consider this example -
I have a class called Report that has a field of type Message. The Message class has a field called "body" which is a string. "body" can be any string, but sometimes it contains properly formatted XML content. How can I ensure that when the "body" contains XML content, the serialization takes the form of an XML structure rather than what it gives at present?
Here is the code with the output -
Report class
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
#XmlRootElement(name = "Report")
#XmlType(propOrder = { "message"})
public class Report
{
private Message message;
public Message getMessage() { return message; }
public void setMessage(Message m) { message = m; }
}
Message class
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
#XmlType(propOrder = { "body" })
public class Message
{
private String body;
public String getBody() { return body; }
#XmlElement
public void setBody(String body) { this.body = body; }
}
Main
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
public class SerializationTest
{
public static void main(String args[]) throws Exception
{
JAXBContext jaxbContext = JAXBContext.newInstance(Report.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
Report report = new Report();
Message message = new Message();
message.setBody("Sample report message.");
report.setMessage(message);
jaxbMarshaller.marshal(report, System.out);
message.setBody("<rootTag><body>All systems online.</body></rootTag>");
report.setMessage(message);
jaxbMarshaller.marshal(report, System.out);
}
}
The output is as follows -
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Report>
<message>
<body>Sample report message.</body>
</message>
</Report>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Report>
<message>
<body><rootTag><body>All systems online.</body></rootTag></body>
</message>
</Report>
As you can see in the above output, for the second instance of "body", the serialization produced
<body><rootTag><body>All systems online.</body></rootTag></body>
instead of
<body><rootTag><body>All systems online.</body></rootTag></body>
How to solve this problem?
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
This use case is mapped using the #XmlAnyElement annotation and specifying a DOMHandler. There appears to be bug when doing this with the JAXB RI, but the following use case works with EclipseLink JAXB (MOXy).
BodyDomHandler
By default a JAXB impleemntation will represent unmapped content as a DOM node. You can leverage a DomHandler to an alternate representation of the DOM, In this case we will represent the DOM as a String.
import java.io.*;
import javax.xml.bind.ValidationEventHandler;
import javax.xml.bind.annotation.DomHandler;
import javax.xml.transform.Source;
import javax.xml.transform.stream.*;
public class BodyDomHandler implements DomHandler<String, StreamResult> {
private static final String BODY_START_TAG = "<body>";
private static final String BODY_END_TAG = "</body>";
private StringWriter xmlWriter = new StringWriter();
public StreamResult createUnmarshaller(ValidationEventHandler errorHandler) {
return new StreamResult(xmlWriter);
}
public String getElement(StreamResult rt) {
String xml = rt.getWriter().toString();
int beginIndex = xml.indexOf(BODY_START_TAG) + BODY_START_TAG.length();
int endIndex = xml.indexOf(BODY_END_TAG);
return xml.substring(beginIndex, endIndex);
}
public Source marshal(String n, ValidationEventHandler errorHandler) {
try {
String xml = BODY_START_TAG + n.trim() + BODY_END_TAG;
StringReader xmlReader = new StringReader(xml);
return new StreamSource(xmlReader);
} catch(Exception e) {
throw new RuntimeException(e);
}
}
}
Message
Below is how you would specify the #XmlAnyElement annotation on your Message class.
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlType;
#XmlType(propOrder = { "body" })
public class Message
{
private String body;
public String getBody() { return body; }
#XmlAnyElement(BodyDomHandler.class)
public void setBody(String body) { this.body = body; }
}
Output
Below is the output from running your SerialziationTest:
<?xml version="1.0" encoding="UTF-8"?>
<Report>
<message>
<body>Sample report message.</body>
</message>
</Report>
<?xml version="1.0" encoding="UTF-8"?>
<Report>
<message>
<body>
<rootTag>
<body>All systems online.</body>
</rootTag>
</body>
</message>
</Report>
For More Information
http://blog.bdoughan.com/2011/04/xmlanyelement-and-non-dom-properties.html
http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html
NOTE - Bug in JAXB RI
There appears to be a bug in the JAXB reference implementation, and the example code will result in a stack trace like the following:
Exception in thread "main" javax.xml.bind.MarshalException
- with linked exception:
[com.sun.istack.internal.SAXException2: unable to marshal type "java.lang.String" as an element because it is missing an #XmlRootElement annotation]
at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:317)
at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:243)
at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:75)
at forum12428727.SerializationTest.main(SerializationTest.java:20)
Caused by: com.sun.istack.internal.SAXException2: unable to marshal type "java.lang.String" as an element because it is missing an #XmlRootElement annotation
at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.reportError(XMLSerializer.java:216)
at com.sun.xml.internal.bind.v2.runtime.LeafBeanInfoImpl.serializeRoot(LeafBeanInfoImpl.java:126)
at com.sun.xml.internal.bind.v2.runtime.property.SingleReferenceNodeProperty.serializeBody(SingleReferenceNodeProperty.java:100)
at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:306)
at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:664)
at com.sun.xml.internal.bind.v2.runtime.property.SingleElementNodeProperty.serializeBody(SingleElementNodeProperty.java:141)
at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:306)
at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.childAsSoleContent(XMLSerializer.java:561)
at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.serializeRoot(ClassBeanInfoImpl.java:290)
at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:462)
at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:314)
... 3 more
If its only for Marshalling, and to ignore the < and >,
We can use the following:
marshaller.setProperty("com.sun.xml.bind.marshaller.CharacterEscapeHandler",
new CharacterEscapeHandler() {
#Override
public void escape(char[] ac, int i, int j, boolean flag,
Writer writer) throws IOException {
writer.write(ac, i, j);
}
});
3 different solutions 1), 2) 3), here below :
1) Following post is a the description of your solution Loresh :
http://anna-safronova.livejournal.com/2524.html?thread=9180
This is still missing limitations details.
With embeeded html, we need a <![CDATA block
JAXB's dependancy
com.sun.xml.bind.marshaller.CharacterEscapeHandler
Needs import jaxb-impl for compilation / and may be required for excution, e.g.
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2.4</version>
Limitation : this solution is Container-specific and may not run because of class-loading policy.
2) Another similar approach is JDK's rt.jar dependancy
com.sun.xml.internal.bind.CharacterEscapeHandler
http://theopentutorials.com/tutorials/java/jaxb/jaxb-marshalling-and-unmarshalling-cdata-block/
Same limitation / dependends on target JDK, and some tweaks on Eclipse/Maven are necessary (bad alternative / My opinion)
3) Finally, the best solution was found on another post of Reg Whitton :
https://stackoverflow.com/a/12637295/560410
and this is the detailed reciepe :
http://javacoalface.blogspot.co.uk/2012/09/outputting-cdata-sections-with-jaxb.html
Worked perfect for me !

java xml annotation get field with namespace, <aaa:bbb>value</aaa:bbb>

I'm working on a project that has no schema and I have to parsing the xml response manually.
My problem is i can't get some value using the xml annotation.
For example , the xml is like:
<?xml version='1.0' encoding='UTF-8' ?>
<autnresponse>
<action>QUERY</action>
<response>SUCCESS</response>
<responsedata>
<autn:numhits>7</autn:numhits>
</responsedata>
</autnresponse>
And the java class is :
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "autnresponse")
public class AutonomyResponse {
private String action;
private String response;
private ResponseData responsedata;
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "responsedata")
public class ResponseData {
#XmlElement(name = "numhits",namespace = "autn")
private String numhits;
#XmlElement(name = "totalhits")
private String totalhits;
}
I can get the action and the response, but can't get the numhits in the responsedata,
Can anyone tell me how to handle the <autn:numhits> using annotation?
Too much Thanks !!!
Another issue is : I have multi <autn:numhits> in the responsedata....how can i get all the value in the Java code.
--> I solve this multi same tags, just set List and the annotation will automatically generate the list
The fact is autn - is only prefix, not namespace. For correct processing of the XML document, namespace must be declared.
Right namespace declaration:
<?xml version='1.0' encoding='UTF-8' ?>
<autnresponse xmlns:autn="http://namespace.here">
<action>QUERY</action>
<response>SUCCESS</response>
<responsedata>
<autn:numhits>7</autn:numhits>
</responsedata>
</autnresponse>
You also need to change the annotation:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "responsedata")
public class ResponseData {
#XmlElement(name = "numhits",namespace = "http://namespace.here")
private String numhits;
#XmlElement(name = "totalhits")
private String totalhits;
}
And finnaly advice for you. If you have a xsd scheme for this xml document, use the XJC utilit for java code generation.
http://docs.oracle.com/javaee/5/tutorial/doc/bnbah.html
JAXB and other XML processors that are capable of processing XML Schema are going to treat everything before a : as a namespace prefix. If the colon is then you can do the following.
Java Model
You need to specify that your element name contains the : character.
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
public class ResponseData {
#XmlElement(name = "autn:numhits")
private String numhits;
private String totalhits;
}
Demo
import javax.xml.bind.*;
import javax.xml.parsers.*;
import org.xml.sax.XMLReader;
public class Demo {
public static void main(String[] args) throws Exception {
// Create a SAXParser that is not namespace aware
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
XMLReader xr = sp.getXMLReader();
// Create the JAXBContext
JAXBContext jc = JAXBContext.newInstance(AutonomyResponse.class);
// Instead of Unmarshaller we will use an UnmarshallerHandler
Unmarshaller unmarshaller = jc.createUnmarshaller();
UnmarshallerHandler unmarshallerHandler = unmarshaller.getUnmarshallerHandler();
// Do a SAX parse with the UnmarshallerHanlder as the ContentHandler
xr.setContentHandler(unmarshallerHandler);
xr.parse("src/forum20062536/input.xml");
// Get the result of the unmarshal
AutonomyResponse autonomyResponse = (AutonomyResponse) unmarshallerHandler.getResult();
// Marshal the object back to XML
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(autonomyResponse, System.out);
}
}

JAXB Unmarshalling: List of objects

I have
#XmlRootElement(namespace = "http://www.w3.org/2005/Atom", name = "content")
#XmlType(name = "course")
public class Course implements Resource
...
#XmlElementWrapper(name="subcourses")
#XmlElement(name="course")
List<Xlink> subcourses; //!?
and Xlink class, which works fine in inline variable.
public class Xlink
{
private String href;
private String value;
#XmlAttribute(namespace = "http://www.w3.org/1999/xlink")
public String getHref()
{
return href;
}
public void setHref(String href)
{
this.href = href;
}
#XmlValue
public String getValue()
{
return value;
}
public void setValue(String value)
{
this.value = value;
}
}
for an XML input of
<atom:content atom:type="xml" xsi:type="course">
...
<subcourses>
<course xlink:href="course1">Some course</course>
<course xlink:href="course2">other course</course>
And subcourses refuses to be unmarshalled (without any exception being thrown).
Note: MOXy is unfortunately not an option.
Edit: new marshalled object
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns3:content xmlns:ns2="http://www.w3.org/1999/xlink" xmlns:ns3="http://www.w3.org/2005/Atom">
<code>SOME CODE</code>
<name>name</name>
<subcourses>
<course ns2:href="Some href">some value</course>
<course ns2:href="sdsdg">sdfhdfhdhdh</course>
</subcourses>
</ns3:content>
Edit2: after some experimentation with unmarshalling and marshalling a test object I have discovered that I need to define xmlns namespace in the header of the content to match xlink:href= like xmlns:xlink="http://www.w3.org/1999/xlink" the problem is that I am getting the Course element from inside a wrapper class that is parsed out by resteasy. Thus the resulting class does not carry over the namespace information.
I somehow need to force JAXB to understand that xmlns:xlink="http://www.w3.org/1999/xlink" applies to the course elements, but after an hour of google I am at a loss.
Edit3: I am getting my object from
https://github.com/jirutka/atom-jaxb/blob/master/src/main/java/cz/jirutka/atom/jaxb/Entry.java
which is used on the server counterpart. Which in turn is a part of
https://github.com/jirutka/atom-jaxb/blob/master/src/main/java/cz/jirutka/atom/jaxb/Feed.java
Relevant parts of my unmarshalling code are:
Feed f = r.readEntity(Feed.class);
out.addAll(unmarshaller.Unmarshal(f.getEntries(), clazz));
where r is a javax.ws.rs.core.Response. And the unmarshaller
public List<T> Unmarshal(List<Entry> entries, Class clazz)
{
List<T> out = new ArrayList<T>();
T instance;
for (Entry e : entries)
{
try
{
JAXBContext context = JAXBContext.newInstance(clazz);
Unmarshaller unmarsh = context.createUnmarshaller();
instance = (T) unmarsh.unmarshal((Node) e.getContent());
Since this is my first tangle with this technology, it is entirely possible that this code is 'wtf'.
When you annotate the field (instance variable) be sure to put #XmlAccessorType(XmlAccessType.FIELD) on your class.
import java.util.List;
import javax.xml.bind.annotation.*;
#XmlRootElement(namespace = "http://www.w3.org/2005/Atom", name = "content")
#XmlAccessorType(XmlAccessType.FIELD)
public class Course implements Resource {
#XmlElementWrapper(name = "subcourses")
#XmlElement(name = "course")
List<Xlink> subcourses;
}
Then make sure your XML input is correctly namespace qualified. Your input document should look something like the following:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<atom:content xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:atom="http://www.w3.org/2005/Atom">
<code>SOME CODE</code>
<name>name</name>
<subcourses>
<course xlink:href="Some href">some value</course>
<course xlink:href="sdsdg">sdfhdfhdhdh</course>
</subcourses>
</atom:content>
With my updated Course class, your Xlink class and a properly namespace qualified XML document the following demo code worked perfectly for me.
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Course.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum17766166/input.xml");
Course course = (Course) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(course, System.out);
}
}
UPDATE #1
Edit2: after some experimentation with unmarshalling and marshalling a
test object I have discovered that I need to define xmlns namespace in
the header of the content to match xlink:href= like
xmlns:xlink="http://www.w3.org/1999/xlink" the problem is that I am
getting the Course element from inside a wrapper class that is parsed
out by resteasy. Thus the resulting class does not carry over the
namespace information.
The best place to fix your issue is where you extract the fragment you wish to unmarhal. Below is a strategy you can use with StAX.
input.xml
Below is a sample XML document where the namespace information is defined above the fragment you wish to unmarshal.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<foo xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:atom="http://www.w3.org/2005/Atom">
<bar>
<atom:content>
<code>SOME CODE</code>
<name>name</name>
<subcourses>
<course xlink:href="Some href">some value</course>
<course xlink:href="sdsdg">sdfhdfhdhdh</course>
</subcourses>
</atom:content>
</bar>
</foo>
Demo
Below we will use a StAX XMLStreamReader to navigate to the target fragment. We will have our JAXB implementation unmarshal this fragment. This way all the namespace information is preserved.
import javax.xml.bind.*;
import javax.xml.stream.*;
import javax.xml.transform.stream.StreamSource;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Course.class);
XMLInputFactory xif = XMLInputFactory.newFactory();
StreamSource source = new StreamSource("src/forum17766166/input.xml");
XMLStreamReader xsr = xif.createXMLStreamReader(source);
while(xsr.hasNext()) {
if(xsr.isStartElement() && "content".equals(xsr.getLocalName())) {
break;
}
xsr.next();
}
Unmarshaller unmarshaller = jc.createUnmarshaller();
Course course = (Course) unmarshaller.unmarshal(xsr);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(course, System.out);
}
}
Output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns3:content xmlns:ns2="http://www.w3.org/1999/xlink" xmlns:ns3="http://www.w3.org/2005/Atom">
<subcourses>
<course ns2:href="Some href">some value</course>
<course ns2:href="sdsdg">sdfhdfhdhdh</course>
</subcourses>
</ns3:content>
UPDATE #2
If you can't produce a better XML fragment as described in UPDATE #1, below is how you could fix the XML fragment you currently have.
NamespaceFilter
You could use a SAX XMLFilter to fix up your XML document.
import org.xml.sax.*;
import org.xml.sax.helpers.*;
public class NamespaceFilter extends XMLFilterImpl {
private static final String ATOM_URI = "http://www.w3.org/2005/Atom";
private static final String XLINK_URI = "http://www.w3.org/1999/xlink";
#Override
public void startElement(String uri, String localName, String qName,
Attributes atts) throws SAXException {
if("atom:content".equals(qName)) {
super.startElement(ATOM_URI, "content", qName, atts);
} else if("course".equals(qName)) {
AttributesImpl modifiedAtts = new AttributesImpl();
modifiedAtts.addAttribute(XLINK_URI, "href", "xlink:href", null, atts.getValue(0));
super.startElement(uri, localName, qName, modifiedAtts);
} else {
super.startElement(uri, localName, qName, atts);
}
}
#Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
if("atom:content".equals(qName)) {
super.endElement(ATOM_URI, "content", qName);
} else {
super.endElement(uri, localName, qName);
}
}
}
Demo
Below is how you can leverage the XmlFilter with JAXB:
import javax.xml.bind.*;
import javax.xml.parsers.*;
import org.xml.sax.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Course.class);
// Create the XMLFilter
XMLFilter filter = new NamespaceFilter();
// Set the parent XMLReader on the XMLFilter
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
XMLReader xr = sp.getXMLReader();
filter.setParent(xr);
// Set UnmarshallerHandler as ContentHandler on XMLFilter
Unmarshaller unmarshaller = jc.createUnmarshaller();
UnmarshallerHandler unmarshallerHandler = unmarshaller
.getUnmarshallerHandler();
filter.setContentHandler(unmarshallerHandler);
// Parse the XML
InputSource xml = new InputSource("src/forum17766166/input.xml");
filter.parse(xml);
Course course = (Course) unmarshallerHandler.getResult();
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(course, System.out);
}
}
For More Information
http://blog.bdoughan.com/2012/11/applying-namespace-during-jaxb-unmarshal.html
UPDATE #3
Below is a simplified version of your example code where everything works. Maybe there is something different in your code it will help you find.
Entry
import javax.xml.bind.annotation.*;
#XmlRootElement(namespace="http://www.w3.org/2005/Atom")
#XmlAccessorType(XmlAccessType.FIELD)
public class Entry<T> {
#XmlElement(namespace = "http://www.w3.org/2005/Atom")
#XmlSchemaType(name = "atomInlineOtherContent")
private T content;
public T getContent() {
return content;
}
}
input.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<atom:entry xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:atom="http://www.w3.org/2005/Atom">
<atom:content>
<code>SOME CODE</code>
<name>name</name>
<subcourses>
<course xlink:href="Some href">some value</course>
<course xlink:href="sdsdg">sdfhdfhdhdh</course>
</subcourses>
</atom:content>
</atom:entry>
Demo
import java.io.File;
import javax.xml.bind.*;
import org.w3c.dom.Node;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Entry.class, Course.class);
// Unmarshal Entry
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum17766166/input.xml");
Entry entry = (Entry) unmarshaller.unmarshal(xml);
// Unmarshal Course
Node contentNode = (Node) entry.getContent();
Course course = (Course) unmarshaller.unmarshal(contentNode);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(course, System.out);
}
}
Output
<?xml version="1.0" encoding="UTF-8"?>
<ns0:content xmlns:ns1="http://www.w3.org/1999/xlink" xmlns:ns0="http://www.w3.org/2005/Atom">
<subcourses>
<course ns1:href="Some href">some value</course>
<course ns1:href="sdsdg">sdfhdfhdhdh</course>
</subcourses>
</ns0:content>

Remove ns2 as default namespace prefix

I have a file that is printed with a default namespace. The elements are printed with a prefix of ns2, I need this to be removed, how it is with my code:
<ns2:foo xmlns:ns2="http://namespace" />
how I want it to be:
<foo xmlns="http://namespace" />
this is how I have coded it, something which as I see it should be enough for the ns2 to go away:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:bar="http://namespace" targetNamespace="http://namespace"
elementFormDefault="qualified">
...
the generated package-info turns out like this:
#javax.xml.bind.annotation.XmlSchema(namespace = "http://namespace",
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package com.foo.bar;
I create the file like this:
JAXBContext jaxbContext = JAXBContext.newInstance(generatedClassesPackage);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(new JAXBElement<Foo>(new QName("http://namespace", "Foo"),
Foo.class, rootFoo), outputStream);
generatedClassesPackage is the package where package-info.java and the elements are.
The Foo object is defined and has elements like this::
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"group"
})
#XmlRootElement(name = "Foo")
public class Foo {
#XmlElement(name = "Group", required = true)
protected List<Group> group;
Is it something I have missed? or have I misunderstood how this works?
All you need 2 do is when you open a new package select create package info
in the package info add the following annotation or change it as needed
#javax.xml.bind.annotation.XmlSchema(namespace = "http://www.sitemaps.org/schemas/sitemap/0.9", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED, xmlns = { #javax.xml.bind.annotation.XmlNs(namespaceURI = "http://www.sitemaps.org/schemas/sitemap/0.9", prefix = "") })
This will remove the ns2 prefix
Most likely you have multiple namespaces in the response. This will use the default convention of creating ns# namespace prefixes and one of them becomes the xmlns without a prefix. If you want to control this you can do the following:
NamespacePrefixMapper mapper = new NamespacePrefixMapper() {
public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
if ("http://namespace".equals(namespaceUri) && !requirePrefix)
return "";
return "ns";
}
};
marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", mapper);
marshaller.mashal....
This will set the http://namespace as the default xmlns always and use ns# for all other namespaces when marshalling. You can also give them more descriptive prefixes if you want.
Beginning from JDK6u18 the NamespacePrefixMapper technique is not used anymore.
I solve this deleting the file package-info.java into the jaxb classes package and re-compiling the application.
Change the attribute value of elementFormDefault="unqualified" in
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:bar="http://namespace" targetNamespace="http://namespace" elementFormDefault="qualified">
For Java 8:
I chagnge prefix name from 'ns2' to 'fault'.
Firstly, create your *DefaultNamespacePrefixMapper *.
import com.sun.xml.bind.marshaller.NamespacePrefixMapper;
import java.util.HashMap;
import java.util.Map;
public class DefaultNamespacePrefixMapper extends NamespacePrefixMapper {
private static final String FAULT_PREFIX = "fault";
private Map<String, String> namespaceMap = new HashMap<>();
public DefaultNamespacePrefixMapper() {
this.namespaceMap.put(NAMESPACE, FAULT_PREFIX);
}
#Override
public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
return namespaceMap.getOrDefault(namespaceUri, suggestion);
}
}
Secondy, add your DefaultNamespacePrefixMapper to Marshaller property.
#SuppressWarnings("unchecked")
private <T> void returnFault(T fault, SoapFault soapFault) {
try {
JAXBContext jaxbContext = JAXBContext.newInstance(fault.getClass());
QName name = new QName(NAMESPACE, fault.getClass().getSimpleName());
JAXBElement<T> element = new JAXBElement<>(name, (Class<T>) fault.getClass(), fault);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", new DefaultNamespacePrefixMapper());
marshaller.marshal(element, soapFault.addFaultDetail().getResult());
} catch (JAXBException e) {
log.error("Exception when marshalling SOAP fault.", e);
}
}
Thirdly, add following dependencies in gradle/maven.
compile 'com.sun.xml.bind:jaxb-impl:2.2.11'
compile 'com.sun.xml.bind:jaxb-core:2.2.11'
Remove namespace from #XmlRootElement
Before: XmlRootElement(name = "XXX", namespace = "abc.xsd")
After: #XmlRootElement(name = "XXX")
For example, if you want to generate
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
You need to create such package-info.java class in the same package with your JAXB pojo classes.
#XmlSchema(namespace = "http://www.w3.org/2001/XMLSchema-instance",
elementFormDefault = XmlNsForm.QUALIFIED,
xmlns = #XmlNs(prefix = "", namespaceURI = "urn:iso:std:iso:20022:tech:xsd:pain.001.001.03"))
package com.amway.instantpayments.bankfileservice.jaxb.pojo;
import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
And pay attention, if you will specify namespace as "urn:iso:std:iso:20022:tech:xsd:pain.001.001.03" and namespaceURI as "http://www.w3.org/2001/XMLSchema-instance" you will get
ns2:Document xmlns:ns2="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

Categories