Update, 2024
New Questions are being closed as duplicates of this one. While I hate to add another Answer to this long page, (a) most of these Answers are a bit old, and (b) most of these Answers are either terse or confusing. So, I will give it a shot.
tl;dr
- Obtain JARs for both API and implementation of Jakarta XML Binding specification.
- May or may not need to bundle with your final app.
Java EE is no more, long live Java EE
Understand that in recent years, Oracle Corp donated the Java EE technologies to the Eclipse Foundation. Oracle retains possession of the Java™ trademark. The new name became Jakarta EE.
By the way, in the Jakarta era, the acronyms like JAXB are discouraged. Use the newly shortened names instead.
Jakarta EE — specification & implementation
Jakarta XML Binding (formerly Java Architecture for XML Binding, JAXB) is a specification, found here. A Java JAR provides the interfaces (API) through which you will interact with an implementation of those specs.
An implementation was bundled with Java SE through Java 10. Java SE versions 11 and later come without the API, and without an implementation.
If you deploy to a Jakarta EE compliant app server, then you may find both the API and the implementation bundled there. If that is the case, you should not bundle either with your app.
If you deploy to a desktop app or a console app via Java SE 11 and later, you must bundle both the API and an implementation.
Know that you can skip the Jakarta XML Binding API, and instead call directly the methods defined in the implementation. But doing so means you give up the flexibility to swap out implementations without rewriting your app.
For the API, the open-source project is hosted here. Find the Maven coordinates for download at a Maven repository such as this. For example:
<!-- https://mvnrepository.com/artifact/jakarta.xml.bind/jakarta.xml.bind-api -->
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>4.0.1</version>
</dependency>
One implementation has the unimaginative name of Eclipse Implementation of JAXB™. The open-source project is hosted here. Find its Maven coordinates for download at a Maven repository such as this. For example:
<!-- https://mvnrepository.com/artifact/com.sun.xml.bind/jaxb-impl -->
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>4.0.4</version>
</dependency>
(The com.sun
naming dates back to when Sun Microsystems invented Java SE and Java EE.)
Related libraries are transitively pulled in.
- Dependencies
- jakarta.xml.bind:jakarta.xml.bind-api:4.0.1
- jakarta.activation:jakarta.activation-api:2.1.2
- com.sun.xml.bind:jaxb-impl:4.0.4
- com.sun.xml.bind:jaxb-core:4.0.4
- jakarta.xml.bind:jakarta.xml.bind-api:4.0.1 (duplicate omitted)
- org.eclipse.angus:angus-activation:2.0.1
- jakarta.activation:jakarta.activation-api:2.1.2 (duplicate omitted)
Another implementation is EclipseLink MOXy.
<!-- https://mvnrepository.com/artifact/org.eclipse.persistence/org.eclipse.persistence.moxy -->
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.moxy</artifactId>
<version>4.0.2</version>
</dependency>
In the example app below, I did swap out these two implementations just by changing the dependency
element of the POM — and it worked swimmingly!
I asked here for any other implementations.
Excluding a dependency
If you do not need to bundle the API & implementation in your final app artifact, add a <scope>
element to the <dependency>
elements seen above. See the documentation, this tutorial, and this Question.
Example app
Here is an example app. This app performs both import and export of an XML file, going through Jakarta XML Binding in both directions. This example is my modified version of an example app seen in the post JAXB (with Java 11) - Tutorial by Lars Vogel.
We start a new project with Maven archetype Quickstart. I modified the default Maven POM to utilize the latest versions.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>work.basil.example</groupId>
<artifactId>ExJakartaXmlBinding</artifactId>
<version>1.0-SNAPSHOT</version>
<name>ExJakartaXmlBinding</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.release>22</maven.compiler.release>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/jakarta.xml.bind/jakarta.xml.bind-api -->
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>4.0.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.sun.xml.bind/jaxb-impl -->
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>4.0.4</version>
</dependency>
<!-- <!– https://mvnrepository.com/artifact/org.eclipse.persistence/org.eclipse.persistence.moxy –>-->
<!-- <dependency>-->
<!-- <groupId>org.eclipse.persistence</groupId>-->
<!-- <artifactId>org.eclipse.persistence.moxy</artifactId>-->
<!-- <version>4.0.2</version>-->
<!-- </dependency>-->
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.3.2</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.3.1</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.1.2</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.3.0</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>3.1.1</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>3.1.1</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>4.0.0-M9</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.5.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
Define a class Book
as our business domain model.
package work.basil.example;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.annotation.XmlType;
@XmlRootElement ( name = "book" )
@XmlType ( propOrder = { "author" , "name" , "publisher" , "isbn" } ) // Order of the properties.
public class Book
{
private String name;
private String author;
private String publisher;
private String isbn;
@XmlElement ( name = "title" ) // Optional override of property identifier.
public String getName ( ) { return name; }
public void setName ( String name ) { this.name = name; }
public String getAuthor ( ) { return author; }
public void setAuthor ( String author ) { this.author = author; }
public String getPublisher ( ) { return publisher; }
public void setPublisher ( String publisher ) { this.publisher = publisher; }
public String getIsbn ( ) { return isbn; }
public void setIsbn ( String isbn ) { this.isbn = isbn; }
}
We keep instances of Book
in a Bookstore
, as a hierarchy.
package work.basil.example;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlElementWrapper;
import jakarta.xml.bind.annotation.XmlRootElement;
import java.util.Collection;
import java.util.List;
@XmlRootElement ( namespace = "work.basil.example.model" )
public class Bookstore
{
// Fields
@XmlElementWrapper ( name = "bookList" )
@XmlElement ( name = "book" )
private Collection < Book > bookList;
private String name;
// Mutators
public void setName ( final String name ) { this.name = name; }
public void setBookList ( final Collection < Book > bookList ) { this.bookList = List.copyOf( bookList ); }
// Accessors
public Collection < Book > getBooksList ( ) { return List.copyOf( bookList ); }
public String getName ( ) { return name; }
}
Utilize these classes in our main
method to export and import XML data in a file.
package work.basil.example;
import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.Marshaller;
import jakarta.xml.bind.Unmarshaller;
import java.io.FileReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class BookMain
{
public static void main ( String[] args ) throws JAXBException, IOException
{
// Business model.
Bookstore bookstore = getBookstore( );
// create JAXB context and instantiate marshaller
JAXBContext context = JAXBContext.newInstance( Bookstore.class );
Marshaller m = context.createMarshaller( );
m.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT , Boolean.TRUE );
// Write to System.out
m.marshal( bookstore , System.out );
// Write to File
final Path path = Files.createTempFile( "bookstore-jaxb" , "xml" );
m.marshal( bookstore , path.toFile( ) );
// Extract from our XML file.
System.out.println( );
System.out.println( "Output from our XML file: " );
Unmarshaller um = context.createUnmarshaller( );
Bookstore bookstore2 = ( Bookstore ) um.unmarshal( new FileReader( path.toFile( ) ) );
Collection < Book > books = bookstore2.getBooksList( );
for ( Book book : books )
{
System.out.println( "Book: " + book.getName( ) + " from " + book.getAuthor( ) );
}
}
private static Bookstore getBookstore ( )
{
Collection < Book > bookList = new ArrayList < Book >( );
// create books
var book1 = new Book( );
book1.setIsbn( "9781491910771" );
book1.setName( "Head First Java, 3rd Edition" );
book1.setAuthor( "Kathy Sierra, Bert Bates, Trisha Gee" );
book1.setPublisher( "O'Reilly Media, Inc." );
bookList.add( book1 );
var book2 = new Book( );
book2.setIsbn( "1-55750-446-6" );
book2.setName( "The Sand Pebbles" );
book2.setAuthor( "Richard McKenna" );
book2.setPublisher( "Harper & Row" );
bookList.add( book2 );
// create bookstore, assigning book
var bookstore = new Bookstore( );
bookstore.setName( "Third Place Books" );
bookstore.setBookList( List.copyOf( bookList ) );
return bookstore;
}
}
When run:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:bookstore xmlns:ns2="work.basil.example.model">
<bookList>
<book>
<author>Kathy Sierra, Bert Bates, Trisha Gee</author>
<title>Head First Java, 3rd Edition</title>
<publisher>O'Reilly Media, Inc.</publisher>
<isbn>9781491910771</isbn>
</book>
<book>
<author>Richard McKenna</author>
<title>The Sand Pebbles</title>
<publisher>Harper & Row</publisher>
<isbn>1-55750-446-6</isbn>
</book>
</bookList>
<name>Third Place Books</name>
</ns2:bookstore>
Output from our XML file:
Book: Head First Java, 3rd Edition from Kathy Sierra, Bert Bates, Trisha Gee
Book: The Sand Pebbles from Richard McKenna