Master JAXB in Spring Boot 3: From XML Binding to Validation
This article explains how to use JAXB with Spring Boot 3 for XML binding, custom adapters, schema generation, validation, and seamless integration, providing step‑by‑step code examples and best‑practice tips for handling XML in Java backend applications.
1. Introduction
Processing XML API responses is common in legacy systems, government platforms, and finance. While Spring Boot’s default Jackson XML can quickly convert XML and Java objects, it has limitations in complex scenarios. JAXB, a JDK native technology (requires a dependency after JDK 11), integrates deeply with XML Schema, automatically generates strong‑typed Java classes and supports data validation.
2. Practical Cases
2.1 Add Dependencies
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
</dependency>2.2 Common JAXB Annotations
@XmlRootElement – defines the XML root element.
@XmlType – controls the order of fields in the generated XML.
@XmlElement – maps a Java field or property to an XML element.
@XmlAttribute – maps a field to an XML attribute.
@XmlTransient – excludes a field from XML serialization.
@XmlAccessorType – sets the access strategy (FIELD, PROPERTY, NONE).
2.3 Object to XML (Marshalling)
Define a POJO with JAXB annotations:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "user")
@XmlType(propOrder = {"id", "name", "age", "birthday"})
public class User {
@XmlAttribute(name = "id")
private Long id;
@XmlElement(name = "name")
private String name;
@XmlElement(name = "age")
private Integer age;
@XmlElement(name = "birthday")
private Date birthday;
}Marshalling example:
JAXBContext context = JAXBContext.newInstance(User.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
User user = new User(1L, "Spring Boot3实战案例200讲", 33, new Date());
StringWriter writer = new StringWriter();
marshaller.marshal(user, writer);
String xmlString = writer.toString();
System.out.println(xmlString);Output:
2.4 Custom Adapter for LocalDate
JAXB does not support Java 8 date types by default. Create an adapter:
public class LocalDateAdapter extends XmlAdapter<String, LocalDate> {
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
@Override
public LocalDate unmarshal(String v) throws Exception { return LocalDate.parse(v, FORMATTER); }
@Override
public String marshal(LocalDate v) throws Exception { return v.format(FORMATTER); }
}Apply the adapter to the field:
@XmlJavaTypeAdapter(LocalDateAdapter.class)
@XmlElement(name = "birthday")
private LocalDate birthday;Running the marshaller now produces a correctly formatted date.
2.5 XML to Object (Unmarshalling)
String xmlString = """
<user id=\"1\">
<name>Spring Boot3实战案例200讲</name>
<age>33</age>
<birthday>2025-08-08</birthday>
</user>
""";
JAXBContext context = JAXBContext.newInstance(User.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
StringReader reader = new StringReader(xmlString);
User user = (User) unmarshaller.unmarshal(reader);
System.err.println(user);Output:
User [id=1, name=Spring Boot3实战案例200讲, age=33, birthday=2025-08-09]2.6 Generate Schema & Validate XML
Generate XSD from the annotated class:
JAXBContext context = JAXBContext.newInstance(User.class);
context.generateSchema(new SchemaOutputResolver() {
@Override
public Result createOutput(String namespaceUri, String suggestedFileName) throws IOException {
return new StreamResult(new File("user.xsd"));
}
});Validate XML against the generated schema:
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema(new File("user.xsd"));
unmarshaller.setSchema(schema);
// use xmlString with a wrong element name to see validation error2.7 Integrate with Spring Boot
Spring Boot automatically registers Jaxb2RootElementHttpMessageConverter. Expose XML via a controller:
@GetMapping(value = "/query", produces = "application/xml")
public ResponseEntity<?> query() {
return ResponseEntity.ok(new User(1L, "Spring Boot3实战案例200讲", 33, LocalDate.now()));
}
@PostMapping("/save")
public ResponseEntity<?> save(@RequestBody User user) {
return ResponseEntity.ok(user);
}For custom validation, extend the converter and set the schema in customizeUnmarshaller:
@Component
public class PackJaxb2RootElementHttpMessageConverter extends Jaxb2RootElementHttpMessageConverter {
@Override
protected void customizeUnmarshaller(Unmarshaller unmarshaller) {
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
try {
Schema schema = sf.newSchema(new File("user.xsd"));
unmarshaller.setSchema(schema);
} catch (SAXException e) {
throw new RuntimeException("XSD parsing failed", e);
}
}
}Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
