Showing posts with label XML. Show all posts
Showing posts with label XML. Show all posts

Marshalling derived classes with JAXB

When I have to convert Java objects to XML strings, I normally use JAXB, the nice standard library included in the Java Standard Edition since version 1.6. I have already written in the past about marshaling and unmarshaling (that means, transform an object to an XML stream, and vice-versa), but I have recently used JAXB to marshal a class that has a polymorphic data member. There are a few differences from the standard behavior that I think they deserve some extra words.

I have a hierarchy of classes, that I want to use polimorphically in another class. Something like this:
@XmlRootElement // 1
public class Data {
  @XmlElement
  private String a;

  // ...
}

@XmlRootElement 
public class DataExt extends Data {
  @XmlElement
  private String b;

  // ...
}

@XmlRootElement
public class Phone {
  @XmlElement
  private String type;
  @XmlElement // 2
  private Data data;

  // ...
}
1. This is not enough. When JAXB performs the binding, it doesn't care about the runtime class associated to the current object, but it goes straight to the compile time type. We should explicitly say which other classes are part of the hierarchy, using the XmlSeeAlso annotation.
2. We need also to tell to JAXB that it should check the runtime type for this object. This is done by replacing the XmlElement annotation with @XmlElementRef. Actually, at least in my case, this is not a strict necessity. Once specified @XmlSeeAlso on the class definition, JAXB is smart enough to deduce that it has to polimorphically treat the related objects. Still, it adds an attribute to element, in my case xsi:type="dataExt", to show which is the actual type it is using.

So, we'd better change an annotation, and add another one:
@XmlRootElement
public class Phone {
  @XmlElement
  private String type;
  @XmlElementRef
  private Data data;

  // ...
}

@XmlRootElement
@XmlSeeAlso(DataExt.class)
public class Data {
  @XmlElement
  private String a;

  // ...
}
Besides, I also wanted to keep transparent to the XML user which kind of actual class I used. Meaning that I want the same tag for elements referring to the Data hierarchy. That's very easy. I specify the same name for both XmlRootElement's:
@XmlRootElement(name="data")
public class DataExt extends Data {
  @XmlElement
  private String b;

  // ...
}

Go to the full post

From XML to object

We have seen how easy is to marshal a Java object to XML when using JAXB, now I am showing you how to unmarshal an XML in a (compatible) Java object using the same library.

We have this XML fragment:
<user id="42" rating="4.2">Bill</user>
And we want to get from it an instance of the class User, as defined in the previous post. The (minor) nuisance is that I have to annotate User so that JAXB knows how it should map its data member to the XML elements, values, and attributes. Once this is done, we get the job done in a matter of few lines:
public User xml2Obj(String xml) { // 1
    try {
        JAXBContext ctx = JAXBContext.newInstance(User.class); // 2
        Unmarshaller um = ctx.createUnmarshaller(); // 3

        StringReader sr = new StringReader(xml);
        User user = (User) um.unmarshal(sr); // 4
        return user;
    } catch (JAXBException e) {
        e.printStackTrace();
        return null;
    }
}
1. This function gets in input the XML to be unmarshalled, and gives back the resulting User object (or null, in case of error).
2. A JAXB context is needed to do the magic, and it should know on which class it operates.
3. A JAXB marshaller is the guy that is going to do the dirty job.
4. To keep the unmarshaller code simple, it has been designed to operate on readers. So, the XML String is passed to a StringReader to adapt it to the JAXB expectations.

The full Java source code for the User class and a Main class using it are on github. The example includes both marshalling (as seen in the previous post) and unmarshalling.

Go to the full post

From object to XML

JAXB (Java Architecture for XML Binding) provides an easy way of converting Java objects to XML. In the JAXB jargon, this is know as marshalling, where unmarshalling means the opposite action of extracting a Java object from an XML.

As a first example, let's see how to create an XML fragment like this:
<user id="42" rating="4.2">Bill</user>
from a Java class named User that has the user name, id, and rating as data member.

Even if this looks like a pretty simple job, still there are a couple of points that it could be interesting to pay attention to. Large part of the JAXB job is done by annotations, with the result that the code looks quite simple to understand at first sight, once you know what it is going on.

In this case, I want my class User to have a couple of annotations, one to state that it represents a root XML element, and the second one to let JAXB know that I want to put an annotation to the data fields, and not to their getters, to specify their XML role.

The result is something like this:
@XmlRootElement // 1
@XmlAccessorType(XmlAccessType.FIELD) // 2
public class User {
    @XmlValue
    private String name;
    @XmlAttribute
    private int id;
    @XmlAttribute
    private float rating;

    // getters and setters follow ...
}
1. This class is the root element for my XML
2. If you don't explicitly say that the accessor type should be found in the field definition, JAXB gets confused. If you comment this line out, you get an IllegalAnnotationsException, and a message saying that "Class has two properties of the same name".

Once you have defined your JAXB annotated class, it is just a matter of creating an object, and marshalling:
public String obj2xml(User user) {  
    try {
        JAXBContext ctx = JAXBContext.newInstance(User.class); // 1
        Marshaller marshaller = ctx.createMarshaller(); // 2
        marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE); // 3

        StringWriter sw = new StringWriter();
        marshaller.marshal(user, sw); // 4
        return sw.toString();
    }
    catch (JAXBException e) { // 5
        e.printStackTrace();
        return "<bad />";
    }
}
1. Create a JAXB context that knows about the User class.
2. Then from the context we get a marshaller.
3. Here I want to generate just an XML fragment, if I want to generate a full XML document, I would remove this line, and the generated XML would have this header:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
4. Ask the marshaller to send its output to a StringWriter, from which the resulting XML could be extracted as a String.
5. In case of anything goes wrong, give an alarming feedback to the user (not a very polite thing to do, but here it will suffices) but still return a valid XML.

The full Java source code for the User class and a Main class using it are on github.

Go to the full post

Unable to access jarfile

I wrote this post while I was working with the Java implementation of Saxon, a collection of tools for processing XML documents, and I bumped in a misleading piece of information while reading Beginning XML (surprisingly, because it is a book that I'd warmly suggest you to read) about executable JARs and their relation with the system CLASSPATH variable.

They say that you should put the Saxon JAR in system CLASSPATH so that you can run it in any folder. But this is not true, if you do it, you get a disappointing error: "Unable to access jarfile".

This is because, as said in the Java documentation about the -jar option: "When you use this option, the JAR file is the source of all user classes, and other user class path settings are ignored."

So, you should disregard what written in Beginning XML, and specify the fully qualified named for the executable JAR, something like this:
java -jar \dev\saxon\saxon9he.jar p293.xml p293.xslt

Go to the full post