JAXB - Add a node to the XML as html link - java

I have a basic JavaBean in my service layer and originally it was not designed for marshalling. This object is used by both JAX-WS, JAX-RS, and Servlets in other layers of my application. I want to take advantage of a drill down type effect in my REST services so my question is: How do I make one of the fields/properties of the javabean appear in the xml as an HTML Link? Obviously I need to use CData. I cannot modify the original javabean by adding fields, etc. Is there an annotation I can use?
If I have in my class:
...
String data;
...
how do I make that(in xml):
<data><![CDATA[ValueOfData]]></data>
is this possible with JAXB and Annotations? Maybe xlink?

I suggest using a type adapter. These are normally used to adapt XML string values into more strongly-typed values like timestamps, but you can also use them to adapt strings to strings.
First, create a subclass of javax.xml.bind.annotation.adapters.XmlAdapter. This class will have to implement marshal and unmarshal, converting to and from the value of your field, and the HTML fragment in the XML.
Once you have that, you can annotate your field with
#XmlJavaTypeAdapter(MyAdapter.class)
And that should be it.

Related

JAXB XML repeating alternating XmlElements without Parent element

We have been using JAXB to generate XML to interface with a third party. This third party is asking that for one section we produce a set of 2 different 0-n XML Elements in a repeating fashion without parent-elements separating them. Here is an example of whats requested:
<education>
<code>ENG24</code>
<percentage>25</percentage>
<code>ENG25</code>
<percentage>20</percentage>
<code>SPA50</code>
<percentage>30</percentage>
<code>SPA60</code>
<percentage>25</percentage>
</education>
I cannot figure out a way to represent this type of XML with JAXB Java XML Binding. Is it at all possible to represent the above XML with JAXB Java XML Binding?
I am aware that the XML above is poorly designed but I cannot change the third party's mind to use and tags instead.
If JAXB XML binding is not going to work that I would be very thankful for suggestions of what library/tool to use instead to produce XML and to do the marshal/un-marshaling.
Thanks!
Matt
Yes, it is possible. The simplest would be probably to use #XmlElements/#XmlElement combo:
#XmlElements({
#XmlElement(name="code", type=String.class),
#XmlElement(name="percentage", type=Integer.class)
})
public List<Serializable> items;
Alternatively you can also use #XmlElementRef/#XmlElementRef and have a List<JAXBElement<? extends Serializable>> items. Each item would be then a JAXBElement<? extends Serializable> carrying the value as well as name of the element.
But since you seem to have different types (String/Integer), #XmlElements/#XmlElement should work as well and is much easier to use.

JAXB with inheritance but without using child element names

I am working with XML from a vendor system that I cannot change and I am trying to use JAXB with it. The XML is used in a REST like API. See below for a couple message examples. Each request/message has the same root element name that is called MsgRequest and it contains a couple common elements that are in every request but it also contains elements that are dependent on the message type.
<!-- request 1 -->
<MsgRequest>
<SubType>GetUser</SubType>
<RequestID>1</RequestID>
<UserName>joe</UserName>
</MsgRequest>
<!-- request 2 -->
<MsgRequest>
<SubType>GetCompany</SubType>
<RequestID>2</RequestID>
<CompanyName>joe</CompanyName>
</MsgRequest>
From Java perspective I could model it like this using inheritance.
class BaseMessage {
String subType;
Integer requestID;
};
class GetUserMessage {
String userName;
};
class GetCompanyMessage {
String companyName;
};
I don't understand how I would use JAXB to represent this XML. I have done some research and found XMLElementRef but that will marshal the name of the referenced element which is not what I want.
Hopefully I am missing something obvious. Any suggestions appreciated.
XML wasn't designed to fit any particular language or even paradigm. This means thatbut you can design an XML that can be represented by a Java class hierarchy but there's no guarantee that some XML structure that comes your way can be mapped to a class hierarchy. Consider that an XML parser must be able to determine the (complex) type of an XML element from the element's tag name. So, if you have two elements tagged <MsgRequest>, they'll have to be mapped to a single Java type.
You can write an XML Schema for a single complex type with required fields subType and requestID, and optional (minOccurs=0) fields userName and companyName. It won't be good OO style, but it'll generate your XML.

Best practice: Java/XML serialization: how to determine to what class to deserialize?

I have an application that saves its context to XML. In this application, there is a hierarchy of classes, that all implement a common interface, and that represent different settings. For instance, a first setting class may be made of 4 public float fields, another one can be made of a sole HashMap.
I am trying to determine what is the best way to handle writing and reading to XML in a generic way. I read on this site a lot about JAXB and XStream for instance, which are able to make a specific class instance from XML.
However my question is related to the fact that the actual class can be anything that implement a given interface. When you read the XML file, how would you guess the actual class to instantiate from the XML data? How do you do that in your applications?
I thought that I could write the .class name in a XML attribute, read it and compare it to all possible class .class names, until I find a match. Is there a more sensible way?
Thanks
xstream should already take care of this and create the object of correct type.
The tutorial seems to confirm that:
To reconstruct an object, purely from the XML:
Person newJoe = (Person)xstream.fromXML(xml);
If you don't know the type, you will have to first assign it to the common interface type:
CommonInterface newObject = (CommonInterface)xstream.fromXML(xml);
// now you can either check its type or call virtual methods
In my case I just have a kind of header that stores the class name that is serialized and when de-serializing it I just use the header value to figure out to which class shall I de-serialize the values.
A best practice would to use an established, well documented XML parser/mapper. All of the serialization/deserialization work has been done, so you can worry about your business logic instead. Castor and Apache Axiom are two APIs that I have used to marshal/unmarshall(serialize/deserialize) Java Classes and XML.
http://www.castor.org
Apache Axiom

POJO requirement question

Reading some articles, it is best to have POJO object to do JSON or XML serialization. I am wondering whether POJO can have construtors or methods?
"POJO" is a terrible name, but basically, yes, a Javabean class representing an entity would be extremely helpful in doing the JSON or XML serialization since there are so many API's out which understands Javabeans and can convert between them and the desired format in a single code line. Last but not least, you can reuse the same Javabean class in all other layers of your application. E.g. to store data in a DB, or to transfer the data between layers, or to present the data to the enduser, etc.
And surely such a class can have constructors and methods.
See also:
Places where Javabeans are used
Converting JSON to Java

Simple Java Xml to POJO mapping/binding?

I'm trying to figure out the simplest way to map an xml file to to a plain old java object.
Note: That in my example the xml doesn't quite match up with my intended POJO.
///////// THE XML
<?xml version="1.0" encoding="UTF-8"?>
<Animal>
<standardName>
<Name>Cat</Name>
</standardName>
<standardVersion>
<VersionIdentifier>V02.00</VersionIdentifier>
</standardVersion>
</Animal>
////// THE INTENDED POJO
class Animal
{
private String name;
private String versionIdentifier;
}
Regular JAXB (with annotations) won't work as the JAXM Element name annotations don't allow me to specifiy nested elements. (i.e. standardName/Name).
I've looked at Jibx but it seems overly complicated, and no full examples are provided for what I want to do.
Castro seems like it would be able to do what I want (using mapping files), but I wonder if there are any other possible solutions. (Possibly that would allow me to skip mapping files, and just allow me to specify everything in annotations).
Thanks
EclipseLink JAXB (MOXy) allows you to do the path based mapping that you are looking for:
#XmlRootElement
class Animal
{
#XmlPath("standardName/Name/text()")
private String name;
#XmlPath("standardVersion/VersionIdentifier/text()");
private String versionIdentifier;
}
For more information see:
http://bdoughan.blogspot.com/2010/09/xpath-based-mapping-geocode-example.html
http://bdoughan.blogspot.com/2010/07/xpath-based-mapping.html
http://wiki.eclipse.org/EclipseLink/Examples/MOXy/GettingStarted/MOXyExtensions
EclipseLink also allows the metadata to be specified using an external configuration file:
http://wiki.eclipse.org/EclipseLink/Examples/MOXy/GettingStarted/ExternalizedMetadata
This article may help you... it only requires you to know xpath
http://onjava.com/onjava/2007/09/07/schema-less-java-xml-data-binding-with-vtd-xml.html
Jakarta Commons Digester should do what you want.
Alternatively, I would recommend writing a transformation class that uses XPath to retrieve elements from the XML.
I consider JiBX the best of the bunch (JAXB, Castor, XMLBeans, etc.), particularly because I favor mapping files over annotations. Admittedly it has a decent learning curve, but the website has a lot of good examples. You must have missed the tutorial.
If you are only going one way (XML --> POJO) you could use Digester.
Side comment: I prefer mapping files over annotations because annotations:
clutter the code (especially when using annotations from several products)
mix concerns (XML, database, etc. in domain layer)
can only bind to a single XML (or database, or web service, etc.) representation

Categories