JAXB: unmarshalling xml with multiple names for the same element - java

I figure this will be easy for someone who really understands JAXB binding files...
Basic Question
How do you configure JAXB to unmarshal multiple elements into the same class?
Note: I want to avoid adding another dependency to my project (like MOXy). Ideally, this can be accomplished with annotations or a custom bindings file.
Background
I have an XML document that contains lots of variations of the same element--each with the exact same properties. Using my example below, all I care about is "Employees" but the XML specifies "directors, managers and staff." For our purposes, these are all subclasses of the same parent and we only need to work with the parent type (Employee) and our object model doesn't have or need instances of the subclasses.
I want JAXB to bind any instance of director, manager, or staff elements into an Employee object.
Example
input:
<organization>
<director>
<fname>Dan</fname>
<lname>Schman</lname>
</director>
<manager>
<fname>Joe</fname>
<lname>Schmo</lname>
</manager>
<staff>
<fname>Ron</fname>
<lname>Schwan</lname>
</staff>
<staff>
<fname>Jim</fname>
<lname>Schwim</lname>
</staff>
<staff>
<fname>Jon</fname>
<lname>Schwon</lname>
</staff>
</organization>
output:
After unmarshalling this example, I would end up with an Organization object with one property: List<Employees> employees where each employee only has a firstName and lastName.
(Note: each employee would be of type Employee NOT Director/Manager/Staff. Subclass information would be lost when unmarshalling. We also don't care about marshaling back out--we only need to create objects from XML)
Can this be done without extensions like MOXy? Can a custom bindings.xjb file save the day?

This corresponds to a choice structure. You could use an #XmlElements annotation for this use case:
#XmlElements({
#XmlElement(name="director", type=Employee.class),
#XmlElement(name="manager", type=Employee.class)
})
List<Employee> getEmployees() {
return employees;
}
If you are starting from an XML schema the following will help:
http://blog.bdoughan.com/2011/04/xml-schema-to-java-xsd-choice.html

Related

AccessOrder for Properties in JAXB

In my class, I have more than 80 attributes.
I have to do it into xml file using JAXB using the same order in class.
so please suggest me a propOrder that create automatically or some other way to give in same order as i given in class.
Note:By default i m getting output in alphabetical order
example:
Java object : order[id = 1, item = 121, qty = 10, city = QWE, ..........., addr = ASD]
excepted result : In xml file
<order>
<id>1</id>
<item no>121</item no>
<qty>10</qty>
.
.
.
.
<addr>ASD</addr>
</order>
If you are creating the xml from the Java object then use
#XmlType (propOrder={"id","item",..."addr"})
A similar post talks about is and in more details.
JAXB and property ordering
For additional check
If you are converting xml to Java object you should use sequence element if you are validating via xsd.
http://www.w3schools.com/schema/el_sequence.asp
The order that you specify the fields and properties in your class is not significant. This means that when the JAXB (JSR-222) implementation introspects the class it may not see the fields/properties in the same order that you specified them in. Alphabetical order is the easiest way to offer consistent ordering. If you want to specify an order you need to use propOrder on #XmlType.

What data type should be used to reference serialized objects by ID?

I have a bunch of classes that will be instantiated and passed between my JS front-end and Spring MVC.
I'm using Simple to serialize my object as XML for persistent storage and Jackson to pass it to my UI as JSON. Consequently I need to have an ID attribute that is used to reference an object, and this needs to be consistent in both the JSON, POJO and XML.
This means I need an ID attribute in my Java class. What type should I declare it as? I've seen int being used in the Simple library tutorial and I've also seen UUID being used here.
The Simple library creates id and ref attributes (or any other that you provide) to maintain references:
<parent name="john" id="1">
<children>
<child id="2" name="tom">
<parent ref="1"/>
</child>
</children>
</parent>
The accompanying Java to read it back in:
Strategy strategy = new CycleStrategy("id", "ref");
Serializer serializer = new Persister(strategy);
File source = new File("example.xml");
Parent parent = serializer.read(Parent.class, source);
The id isn't in the original Java object however, so it won't be passed with the JSON to the UI. Should I define a private UUID uid; and pass that, while also letting Simple generate the auxiliary id and ref attributes it uses, or is there a way to use a single Java attribue to do both?
EDIT: Hibernate has an #Id annotation, but I can't find something similar for Simple. Will this do?
#Attribute
private int id;
The problem is that I'll need to instantiate and pass it as JSON, but it needs to be unique as well (meaning it'd be easier to use UID). Also, will Simple use this id for its ref?
EDIT 2:
Using id as an attribute and then using the CycleStrategy causes it to use the value you define from the class and not the internal ones it uses in the XML which the ref point to... I'm using two attributes for now - a uuid I generate together with the id Simple uses internally.

JAXB REST PUT'ting referenced association

Consider the following entity classes:
Manufacturer: represents a car manufacturer (Ford, Volvo, ...) and has a name.
Model: represents a model (Fiesta, S80), has a name, and is manufactured by a single manufacturer.
The manufacturer field in the model is annotated as follows:
#ManyToOne
#XmlIDREF
private Manufacturer manufacturer;
I then have two REST resources defined for getting and putting both manufacturers and types. The problem is with putting types:
#PUT
#Consumes("application/xml")
public void putModel(JAXBElement<Model> model) {
modelFacade.create(model.getValue());
}
and the XML I try to put:
<model>
<name>Fiesta</name>
<manufacturer>1</manufacturer>
</model>
The manufacturer element points to 1, a valid instance of Manufacturer, however, when the Model is persisted, the MANUFACTURER_ID is null. How can I get JAXB to read the manufacturer's ID from the XML as well?
Thanks!
Consider adding a hyperlink to the manufacturer instead of an ID (to make it more RESTful). See this e-mail from the users#jersey mailing list which has an example of that.
The following answer I gave to a similar question may help. It makes use of an XmlAdapter to convert the referenced object to/from an ID:
Serialize a JAXB object via its ID?
To leverage this in a JAX-RS environment to create a RESTful service you will need to leverage a MessageBodyReader in order to set an instance of EntityManager on the XmlAdapter passed to the Unmarshaller.

Automatically populate HATEAOS links using JAXB or something similar?

Let's say I'm following HATEOAS and using hypertext in my XML. Something like this:
/customer/32
<Customer>
<FirstName>Joe</FirstName>
<LastName>Smith</LastName>
<Address href="/address/4324">
</Customer>
/address/4324
<Address>
<Street>123 Fake St</Street>
<Town>Springfield</Town>
</Address>
Is there a library akin to or an extension of JAXB that can unmarshall a Customer and automatically query for and unmarshall Address as a property of that Customer (like customer.getAddress().getStreet())? If not, what's a good approach to this that lends itself to client-side caching?
In JAXB you could use an XmlAdapter for this use case. The XmlAdapter would specify value type String and bound type Address. The you would add the logic to convert between them.
For More Info
http://bdoughan.blogspot.com/2010/07/xmladapter-jaxbs-secret-weapon.html?m=1

Converting XML string into valid XML in the Jersey XML output

I am developing RESTful web services in Java using Jersey, Tomcat and Toplink. One of my requirement is replacing a resource link(person) with actual xml data(returned by that person resource link) in the XML data that my "Customer" service returns. In order to achieve this, while calling(GET method) the Customer service I get the xml output from the "Person" resource and remove the <person> and </person> tags from this xml data(since my "Customer" service has the property "person" where I want to stick this xml data) and set this xml data in the "person" property of the "Customer" resource.
Here is my output:
Output returned from Customer service:
<customer>
<person>http://localhost:8080/xxxx/resources/person/JONESTD</person>
<xxx>...... </xxx>
<xxx>...... </xxx>
......
......
......
</customer>
Output returned from Customer service when I use query string composite=person(to replace
person resource url with actual data) while calling this service:
<customer>
<person><namePrefix>Mr.</namePrefix> <nameFirst>Timothy</nameFirst>
<nameLast>Jones</nameLast> <nameMiddle>D.</nameMiddle> <nameSuffix/>
<nameDisplayInformal>Timothy D. Jones</nameDisplayInformal> <nameDisplayFormal>Mr.
Timothy D. Jones</nameDisplayFormal> <nameSortedInformal>Jones, Timothy
D.</nameSortedInformal> <nameSortedFormal>Timothy, Jones D. Mr.</nameSortedFormal>
<username>JONESTD</username> <emailAddress>JONESTD#xxxx.xx</emailAddress> </person>
<xxx>...... </xxx>
<xxx>...... </xxx>
......
......
......
</customer>
As you see, the XML string I set in the person property of Customer resource is not properly indented. If I view "View Source" it shows this output like this:
<customer>
<namePrefix>Mr.</namePrefix>
<nameFirst>Timothy</nameFirst>
<nameLast>Jones</nameLast> <nameMiddle>D.</nameMiddle>
<nameSuffix/> <nameDisplayInformal>Timothy D.
Jones</nameDisplayInformal> <nameDisplayFormal>Mr. Timothy D.
Jones</nameDisplayFormal> <nameSortedInformal>Timothy, Jones
D.</nameSortedInformal> <nameSortedFormal>Timothy, Jones D.
Mr.</nameSortedFormal> <username>JONESTD</username>
<emailAddress>JONESTD#xxxx.xx</emailAddress>
<xxx>...... </xxx>
<xxx>...... </xxx>
.......
.......
.......
</customer>
I see this < and > only in the person xml string I set in the "person" property. I tried several things(including StringEscapeUtils.unescapeHtml) to convert < and > into < and > (proper xml). But nothing worked for me. Could you please give me some idea on how I can fix this issue?
In order to achieve this, while
calling(GET method) the Customer
service I get the xml output from the
"Person" resource and remove the
and tags from this
xml data(since my "Customer" service
has the property "person" where I want
to stick this xml data) and set this
xml data in the "person" property of
the "Customer" resource.
I believe you are saying that you have a Customer object with a String property to represent the XML contents? When you marshal this content you will see the addition of escaped characters.
I am developing RESTful web services
in Java using Jersey, Tomcat and
Toplink.
When you say you are using TopLink, are you oracle.toplink.* classes, or the org.eclipse.persistence.* classes. If you are using the latter (EclipseLink), you will be able to leverage EclipseLink JAXB (MOXy) to do what you want.
Representing XML as a String
Refer to: Using JAXB to extract inner text of XML element
http://bdoughan.blogspot.com/2011/04/xmlanyelement-and-non-dom-properties.html
Using MOXy with Jersey
http://bdoughan.blogspot.com/2010/08/creating-restful-web-service-part-35.html

Categories