Skip to Content
Course content

256: Working with XML: JAXB Basics

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Think about how IKEA ships furniture. You don't get a fully assembled wardrobe delivered to your door—that would be a logistical nightmare. Instead, they give you a "flat pack": a box of disassembled parts and a set of instructions. When you follow those instructions to build the wardrobe, you're essentially recreating a physical object from a structured description. When you take that wardrobe apart to move house, you're doing the opposite.

In Java, JAXB (Java Architecture for XML Binding) does exactly this with your data. The "assembled furniture" is your Java object, and the "flat pack" is the XML file. The process of turning an object into XML is called marshalling, and turning XML back into an object is unmarshalling. It saves you from the headache of manually parsing tags with a DOM or SAX parser, which, frankly, is a chore I avoid whenever possible.

Telling Java how to read the XML layout

JAXB doesn't just guess how your class maps to XML; you have to give it a few hints using annotations. If we're building a simple system to track project tasks, we can't just use a plain POJO. We need to mark the "root" of our document.

import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "task")
public class ProjectTask {
    private int id;
    private String title;
    private String priority;

    // JAXB requires a no-arg constructor
    public ProjectTask() {}

    public ProjectTask(int id, String title, String priority) {
        this.id = id;
        this.title = title;
        this.priority = priority;
    }

    @XmlElement
    public int getId() { return id; }
    public void setId(int id) { this.id = id; }

    @XmlElement
    public String getTitle() { return title; }
    public void setTitle(String title) { this.title = title; }

    @XmlElement
    public String getPriority() { return priority; }
    public void setPriority(String priority) { this.priority = priority; }
}

Notice the @XmlRootElement. That tells JAXB that when this object is the top level of an XML file, the tag should be <task>. I've put the @XmlElement annotations on the getters here—it's a common pattern that keeps the fields private while telling JAXB, "Yes, this piece of data belongs in the XML." Also, don't forget that no-arg constructor; JAXB uses it to instantiate the object before filling it with data. If you leave it out, the code will crash at runtime, and you'll spend twenty minutes wondering why.

Shipping your data out (Marshalling)

To get your object into an XML file, you need a JAXBContext. Think of the context as the "brain" that knows about your ProjectTask class. Once you have the context, you create a Marshaller to handle the actual writing.

import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.Marshaller;
import java.io.File;

public class TaskExporter {
    public static void main(String[] args) throws Exception {
        ProjectTask task = new ProjectTask(101, "Fix memory leak in cache", "High");

        JAXBContext context = JAXBContext.newInstance(ProjectTask.class);
        Marshaller mar = context.createMarshaller();

        // This makes the XML human-readable instead of one long line
        mar.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

        mar.marshal(task, new File("task.xml"));
        System.out.println("Task exported successfully!");
    }
}

The JAXB_FORMATTED_OUTPUT property is a lifesaver. Without it, JAXB generates a single, massive line of text that is impossible to read. Always turn it on during development.

Reconstructing the object (Unmarshalling)

Bringing the data back is just as straightforward. You use the same JAXBContext, but instead of a Marshaller, you ask for an Unmarshaller. This reads the file and "inflates" it back into a Java object.

import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.Unmarshaller;
import java.io.File;

public class TaskImporter {
    public static void main(String[] args) throws Exception {
        File file = new File("task.xml");
        JAXBContext context = JAXBContext.newInstance(ProjectTask.class);
        Unmarshaller unmar = context.createUnmarshaller();

        ProjectTask task = (ProjectTask) unmar.unmarshal(file);
        System.out.println("Imported Task: " + task.getTitle() + " [" + task.getPriority() + "]");
    }
}

One thing I'll warn you about: unmarshalling returns a generic Object, so you'll have to cast it to ProjectTask. It's a bit clunky, but that's just the way the API was designed years ago. Since you're the one controlling the file input, you know exactly what type you're expecting.




📋 Practical Task

Building a Persistent User Profile Saver

Your goal is to create a small utility that saves and loads a user's application preferences using JAXB. This mimics how many desktop apps store their settings in an .xml config file.

Requirements:

  • Create a UserProfile class with the following fields: username (String), theme (String), and fontSize (int).
  • Annotate the class so the root XML element is named <user_profile>.
  • Implement a PreferenceManager class with two methods:
    • saveProfile(UserProfile profile, String filename): Marshals the object to a file with formatted output.
    • loadProfile(String filename): Unmarshals the file back into a UserProfile object.
  • In your main method, create a profile (e.g., "DevUser", "Dark Mode", 14), save it to prefs.xml, and then load it back to verify the data is identical.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.