Let's say I have an XML file like the following
<root>
<record>foo</record>
<record>bar</record>
</root>
I use JAXB to read in the record. Does JAXB keep the information of say bar comes before foo?
My gut feeling is NO, JAXB does not maintain this information. But then I am stuck since I actually need to get this information... Any recommendation... BTW, I can't change the format of the xml.
Thanks.
Have you actually tried it?
JAXB's #XmlType annotation as a propOrder property which defines the order of properties.
So you can do:
#XmlRootElemen(name="root")
#XmlType(propOrder={"record2", "record1"})
public class Root {
public String record1;
public String record2;
}
Update
The OP has edited his original XML from this:
<root>
<record2>
<record1>
</root>
To this:
<root>
<record>foo</record>
<record>bar</record>
</root>
My answer applies to the original XML with two elements record2 and record1.
Order & Repeated Elements
If your XML is like the following:
<root>
<record>foo</record>
<record>bar</record>
</root>
If you map a repeating element to a java.util.List the order of the elements will be maintained in the List.
#XmlElement(name="record")
public List<String> getRecords() {
return records;
}
Order & Non-Repeated Elements
If on the other hand your XML is like the following:
<root>
<hello>foo</hello>
<world>bar</world>
</root>
Using Marshaller
Then using Marshaller the order in which the elements are marshalled to XML will be controlled by:
The propOrder property on the #XmlType annotation.
The #XmlAccessorOrder annotation
Using Binder
Using Binder you parse your XML into a DOM and use Binder to unmarshal that. Then you can make changes to your object and apply those changes back to the DOM. This allows you to preserve aspects such as ordering from the orginal XML
Does JAXB support modification of existing XML documents without marshalling/unmarshalling?
Related
For elements with multiplicity > 1 (i.e.. where maxOccurs>1 or maxOccurs=unbound), e.g.:
<element name="Name" type="tns:Type" minOccurs="0" maxOccurs="unbound"/>
JAXB generates the following code:
#XmlElement(name = "Name")
protected List<type> name;
Strictly speaking the above schema describes an XML snippet that looks like so:
<Name attr1="a" attr2="x">
<Name attr1="b" attr2="y">
<Name attr1="c" attr2="z">
i.e. a sequence of "Name" elements (and only that!).
When marshalling a Java object to XML the JAXB runtime creates XML, which contains an additional wrapper element around the list, like so:
<Name>
<Name attr1="a" attr2="x">
<Name attr1="b" attr2="y">
<Name attr1="c" attr2="z">
<Name>
By default the wrapping element has the same name as the individual items. Note, that there is no Java class representing that element!
One can overrule the naming to something that makes more sense by manually (!) adding a java-annotation "#XmlElementWrapper" annotation, like so:
#XmlElementWrapper(name = "NameList")
#XmlElement(name = "Name")
protected List<Type> name;
which then yields the following XML:
<NameList>
<Name attr1="a" attr2="x">
<Name attr1="b" attr2="y">
<Name attr1="c" attr2="z">
<NameList>
I agree that such a wrapper element is syntactically nice and makes the XML more readable, BUT there is a severe problem with this: the generated Java code (with or without renaming the wrapper element) generates and expects an XML dialect which - strictly speaking - does not match the original schema anymore! There is no mentioning or any implicit notion of any such wrapper element in the original schema!
The issue only surfaces, if one uses the original schema in different tools (e.g. to create web forms or a different schema-based code generator) and if their result then adheres and/or expects the original XML (i.e. the bare sequence without any wrapper element), while the JAXB-generated code creates and insists on the presence of the wrapper element. Then the two cannot understand each other!
My question thus: how can one instruct JAXB to NOT add/expect said wrapper element while marshalling/unmarshalling XML?
I have searched the web now for quite a while for solutions or work-arounds to this but found nothing! I can't imagine that nobody else before ever stumbled over this and that there seems no other solution to this other problem than to hand-tweak the XML marshalling/unmarshalling code. Any ideas or suggestions to solve this issue?
I have an integration with some flows and JAXBcontext declared like this
<mulexml:jaxb-context name="JaxbContext" packageNames="se.razorlib.SystemAProduct:se.razorlib.SystemAPurchase:se.razorlib.SystemAOrder"/>
In one of my flows I transform XML to Purchase and in another XML to Order, which are very similar objects.
However, in the Order flow JAXB transforms my XML to PurchaseObject instead of OrderObject, which of course throws me an error:
The object transformed is of type: "SimpleDataType{type=se.razorlib.SystemAPurchase.Header, mimeType='*/*', encoding='null'}", but the expected return type is "SimpleDataType{type=se.razorlib.SystemAOrder.Header, mimeType='*/*', encoding='null'}"
This is my configuration, how can I force a tranfsformation to the "right" object?
<file:inbound-endpoint path="C:\temp\OrderfileIn" responseTimeout="10000" doc:name="FileIn"/>
<mulexml:jaxb-xml-to-object-transformer jaxbContext-ref="JAXB_Context" doc:name="XML to JAXB Object" returnClass="se.razorlib.SystemAOrder.Header"/>
<custom-transformer returnClass="se.razorlib.SystemBOrder.SalesOrder" encoding="UTF-8" class="se.didriksson.Transformer.Map2SystemBOrder" doc:name="Map2B"/>
To pick the correct bean class you have to place the
#XmlRootElement(name = "Order")
Instead of order you may have to put the root element of your xml.
Another point
I also face an issue with mule 3.7 which is it doesn't read package.info file in the package
I defined objects with XSD model and I used Jaxb to create corresponding classes, to be able to load XML files on instance of classes and to generate XML files from instance of classes.
My elements defined on the XSD model are complex with several hierarchical level, using list, ID and IDREF.
One command of my program is to duplicate elements.
I can't use the clone method cause classes of element are generated by JAXB.
So i have tried to do deep copy with BeanUtils.cloneBean, next with SerializationUtils.clone from Apache but both methods don't work correctly with all my objects because of their complexity.
I found a solution that work, using JAXB to create a clone unmarshalling my element :
public ObjectXML duplicate(ObjectXML objectXML) throws JAXBException {
JAXBContext sourceJaxbContext = JAXBContext.newInstance(objectXML.getClass());
JAXBContext targetJaxbContext = JAXBContext.newInstance(objectXML.getClass());
Unmarshaller unmarshaller = targetJaxbContext.createUnmarshaller();
ObjectXML objectCopy = (ObjectXML) unmarshaller.unmarshal(new JAXBSource(sourceJaxbContext, objectXML));
return objectCopy;
}
ObjectXML is my parent class from all elements generated by JAXB. All elements inherit directly or indirectly from this class.
This method work fine except with IDREF attributes that link to another object : JAXB don't know the element that have the corresponding ID when I unmarshall an individual object, so it assign null to the attribute.
Have someone a solution to keep IDREF on the copy when linked object are not supplied to the unmarshal of JAXB?
Thank you for advance.
Few hints.
Try the copyable plugin from JAXB2-Basics. This plugin generates deep reflection-free copying methods which handle JAXB structures very well, and you can also specify your own copying strategy. Disclaimer: I'm the author.
Implement and register your own IDResolver, see this blog post. This would allow you to plug your own ID resolution strategy.
We have a Spring Integration application which uses a JDBC poller together with a RowMapper to read from a database and output a collection of domain objects (presuming the result set returned more than one row).
The domain objects are then marshalled into XML. When using Castor as the marshaller, this works ok, and the XML represents a collection of the domain objects:
<array-list>
<order>
<orderID>23940210</orderID>
...
</order>
<order>
...
</array-list>
We now wish to switch from Castor to JAXB.
This is the definition of the JAXB marshaller in XML:
<oxm:jaxb2-marshaller id="jaxbMarshallerBean">
<oxm:class-to-be-bound name="com.mycompany.Order" />
</oxm:jaxb2-marshaller>
... the JAXB marshaller is used as the transformer used in the Spring Integration chain ..
<int:chain input-channel="input" output-channel="output-jms">
<si-xml:marshalling-transformer id="defaultMarshaller" marshaller="jaxbMarshallerBean" />
</int:chain>
and of course the domain class is annotated:
#XmlRootElement(namespace ="Order")
public class Order{
...
#XmlElement(name="OrderID")
public String getOrderId() {
return orderId;
}
Now, the following exception is thrown:
org.springframework.oxm.UncategorizedMappingException:
Unknown JAXB exception;
nested exception is javax.xml.bind.JAXBException:
class java.util.ArrayList nor any of its super class is known to this context.
It looks like JAXB does not like the fact that it is handling a collection of domain objects. What is the correct way to configure or handle this?
Thanks very much
Surely you want an unmarshalling transformer to go from XML to POJO.
I don't know if there is a way to configure JAXB to handle it directly, but you could add an XPath splitter before the unmarshaller and an aggregator after it.
I am attempting to use JAXB to unmarshall an XML files whose schema is defined by a DTD (ugh!).
The external provider of the DTD has specified one of the element attributes as xml:lang:
<!ATTLIST langSet
id ID #IMPLIED
xml:lang CDATA #REQUIRED
>
This comes into the xjc-generated class (standard generation; no *.xjb magic) as:
#XmlAttribute(name = "xml:lang", required = true)
#XmlJavaTypeAdapter(NormalizedStringAdapter.class)
protected String xmlLang;
However, when unmarshalling valid XML files with JAXB, the xmlLang attribute is always null.
When I edited the XML file, replacing xml:lang with lang and changed the #XmlAttribute to match, unmarshalling was successful (i.e. attributes were non-null).
I did find this http://old.nabble.com/unmarshalling-ignores-element-attribute-%27xml%27-td22558466.html. But, the resolution there was to convert to XML Schema, etc. My strong preference is to go straight from an un-altered DTD (since it is externally provided and defined by an ISO standard).
Is this a JAXB bug? Am I missing something about "namespaces" in attribute names?
FWIW, java -version = "build 1.6.0_20-b02" and xjc -version = "xjc version "JAXB 2.1.10 in JDK 6""
Solved the issue by changing replacing xml: with a namespace declaration in the JAXB-generated class:
#XmlAttribute(name = "lang", namespace="http://www.w3.org/XML/1998/namespace", required = true)
Which makes sense, in a way.
Without this kind of guidance, how would JAXB know how to interpret the otherwise-undefined namespace xml:? Unless, of course, it implemented some special-case internal handling to xml: as done in http://java.sun.com/javase/6/docs/api/javax/xml/stream/XMLStreamReader.html#getNamespaceURI%28java.lang.String%29 (see the first NOTE:)
Whether it's a bug in xjc's generation of the annotated objects or a bug in the unmarhaller, or simply requires a mapping somewhere in the xjc process is still an open question in my mind.
For now, it's working and all it requires is a little xjc magic, so I'm reasonably happy.
Disclaimer: Although 8 years late, I am adding this answer for lost souls such as myself trying to understand auto generation of java files from a DTD.
You can set project wide namespaces for the unmarshaller to work with directly in the project-info.java file via the #XmlSchema option.
This file should be automatically generated by xjc when generating classes from a schema, however it appears xjc does not automatically generate the package-info.java file when generating from a DTD!
However, you can manually make this file, and add it to the same package as the files generated by xjc.
The file would look like the following:
package-info.java :
#XmlSchema(
elementFormDefault=XmlNsForm.QUALIFIED,
xmlns = {
#XmlNs(prefix="xlink", namespaceURI="http://www.w3c.org/1999/xlink"),
#XmlNs(prefix="namespace2", namespaceURI="http://www.w3c.org/1999/namespace2")
})
package your.generated.package.hierarchy;
import javax.xml.bind.annotation.*;
You can add as many namespaces as required, simply add a new line in the form:
#XmlNs(prefix="namespace", namespaceURI="http://www.uri.to.namespace.com")
The benefit of doing it this way, rather than compared to editing the generated #XmlAttribute is that you do not need to change each generated XmlAttribute, and you do not need to manually remove the namespaces from the XmlAttribute name variable.