"Not so fast, young man! I have two more lessons for you!"

"Two? Wow. Well, okay. What wouldn't you do to enhance your own coolness! I'm all ears."

"XML, like JSON, is often used when passing data between different programs and computers. And there are several frameworks that greatly simplify the lives of Java programmers when working with XML. Today I will introduce you to one of them."

"JAXB is an excellent multipurpose framework for working with XML."

JAXB - 1

"JAXB is part of the JDK, so you don't need to download it separately."

"Let me first show you an example of how to use it, and then we'll analyze it. For example:"

Convert an object to XML
public static void main(String[] args) throws JAXBException
{
 // Create an object to be serialized into XML
 Cat cat = new Cat();
 cat.name = "Missy";
 cat.age = 5;
 cat.weight = 4;

 // Write the result of the serialization to a StringWriter
 StringWriter writer = new StringWriter();

 // Create a Marshaller object that will perform the serialization
 JAXBContext context = JAXBContext.newInstance(Cat.class);
 Marshaller marshaller = context.createMarshaller();
 marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
 // And here's the serialization itself:
 marshaller.marshal(cat, writer);

 // Convert everything written to the StringWriter
 String result = writer.toString();
 System.out.println(result);
}
A class whose objects convert to XML
@XmlType(name = "cat")
@XmlRootElement
public class Cat
{
 public String name;
 public int age;
 public int weight;

 public Cat()
 {
 }
}
Serialization result and screen output:
<cat>
<name>Missy</name>
<age>5</age>
<weight>4</weight>
</cat>

"For some reason, line for line, this code reminds me of JSON serialization. The same annotations, but JSON used an ObjectMapper, and this uses Context and Marshaller."

"Yep. They really are very similar. Jackson was modeled after JAXB. But JAXB was also copied from somewhere. You can't invent something genius from scratch."

"It seems that way."

"OK, here's what happening:"

"In lines 4-7, we create a Cat object and populate it with data."

"In line 10, we create a Writer object to write the result."

"In line 13, we create the 'context'. This is similar to ObjectMapper, but then two additional child objects are created from it. Marshaller is for serialization, and Unmarshaller is for deserialization. There are small differences from Jackson, but it isn't fundamentally different."

"In line 14, we create a Marshaller object. Marshalling is a synonym for serialization."

"In line 15, we set the FORMATTED_OUTPUT property to TRUE. This will add line breaks and spaces to the result, so that the code is human-readable, and doesn't just have all of the text on one line."

"In line 17, we serialize the object."

"In lines 20-21, we display the result of the serialization on the screen."

"What are the @XmlType(name = 'cat&') and @XmlRootElement annotations?"

"@XmlRootElement indicates that this object can be the 'root of a tree' of XML elements. In other words, it can be the highest level element, and can contain all other elements."

"@XmlType(name = 'cat') indicates that the class is involved in JAXB serialization, and also specifies the name of the XML tag for this class."

"All right, now I'll show you an example of XML deserialization:"

Convert an object from XML
public static void main(String[] args) throws JAXBException
{
 String xmldata = "<cat><name>Missy</name><age>5</age><weight>4</weight></cat>";
 StringReader reader = new StringReader(xmldata);

 JAXBContext context = JAXBContext.newInstance(Cat.class);
 Unmarshaller unmarshaller = context.createUnmarshaller();

 Cat cat = (Cat) unmarshaller.unmarshal(reader);
}
A class whose objects are deserialized from XML
@XmlType(name = "cat")
@XmlRootElement
public class Cat
{
 public String name;
 public int age;
 public int weight;

 public Cat()
 {
 }
}

"Everything is almost the same as with Jackson. But just in case, I'll explain everything that's going on here."

"In line 3, we pass a string that stores the XML to be deserialized."

"In line 4, we wrap the XML-string in a StringReader."

"In line 6, we create a JAXB context, to which we pass the list of classes."

"In line 7, we create an Unmarshaller—the object that will perform the deserialization."

"In line 9, we deserialize XML from the reader object and get a Cat object."

"Now it all seems almost obvious. But a couple of hours ago, I was racking my brain to figure out how it works."

"That always happens when you get smarter. Complex things become simple."

"I'm getting smarter? I can't help but be happy about that."

"Great. Then here's a list of annotations you can use to control the result of JAXB serialization:"

JAXB annotations Description
@XmlElement(name) Placed near a field.
The field will be stored in an XML element.
Lets you set the tag's name.
@XmlAttribute(name) Placed near a field.
The field will be stored as an XML attribute!
Lets you set the attribute's name.
@XmlElementWrapper(nillable = true) Placed near a field.
Lets you set a 'wrapper tag' for a group of elements.
@XmlType Placed near a class.
Lets you specify a method for creating an object if the default constructor is private.
@XmlJavaTypeAdapter Placed near a field.
Lets you specify the class that will convert the field to a string.

"How interesting! But can you provide me with an example that uses these annotations? An explanation is one thing, but a working example is something else."

"OK. I'll show you an example. I just wanted to add that JAXB lets you annotate getter/setter methods instead of fields."

"Here's that example I promised:"

Convert an object to XML
public static void main(String[] args) throws JAXBException
{
 // Create Cat and Zoo objects to be serialized into XML
 Cat cat = new Cat();
 cat.name = "Missy";
 cat.age = 5;
 cat.weight = 4;

 Zoo zoo = new Zoo();
 zoo.animals.add(cat);
 zoo.animals.add(cat);

 // Write the result of the serialization to a StringWriter
 StringWriter writer = new StringWriter();

 // Create a Marshaller object that will perform the serialization
 JAXBContext context = JAXBContext.newInstance(Cat.class, Zoo.class);
 Marshaller marshaller = context.createMarshaller();
 marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
 // Here's the serialization itself
 marshaller.marshal(zoo, writer);

 // Convert everything written to the StringWriter into a String
 System.out.println(writer.toString());
}
A class whose objects convert to XML
@XmlType(name = "zoo")
@XmlRootElement
public class Zoo
{
 @XmlElementWrapper(name = "wild-animals", nillable = true)
 @XmlElement(name = "tiger")
 public List<Cat> animals = new ArrayList<>();
}

public class Cat
{
 @XmlElement(name = "catname")
 public String name;
 @XmlAttribute(name = "age")
 public int age;
 @XmlAttribute(name = "w")
 public int weight;

 public Cat()
 {
 }
}
Serialization result and screen output:
<zoo>
<wild-animals>
<tiger age = "5" w = "4">
<catname>Missy</catname>
</tiger>
<tiger age = "5" w = "4">
<catname>Missy</catname>
</tiger>
</wild-animals>
</zoo>

"Notice that this time we aren't serializing a Cat object, but a Zoo object that stores a collection of Cat objects."

"The cat object was added to the collection twice, so it is in the XML twice."

"The collection has its own 'wild-animals' tag that wraps all of the collection's elements."

"The age & weight elements have become the age &w w attributes."

"Using an @XmlElement attribute, we changed the cat tag to a tiger tag."

"Pay attention to line 17. Here we pass two classes (Zoo and Cat) to the JAXB context, since they are both involved in the serialization."

"Today was a very interesting day. So much new information."

"Yes. I'm happy for you. Now, take a short break and we'll continue."