MOXy is configured but is being ignored

29 Jun 2020

Table of Contents


info
Jump to the final section to see notes about MOXy v3 configuration with Jakarta.

Check the Implementation

The first time I tried to use MOXy, I was not able to tell whether I had actually configured it correctly. So, first of all, you may want to check which implementation of JAXB is being used for the domain classes you are trying to handle.

The following code checks to see which implementation is used to handle YourDomainClass.

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
static final String MOXY_JAXB_CONTEXT = "org.eclipse.persistence.jaxb.JAXBContext";
static final String METRO_JAXB_CONTEXT = "com.sun.xml.bind.v2.runtime.JAXBContextImpl";

private void checkProvider() throws JAXBException {
    JAXBContext jc = JAXBContext.newInstance(YourDomainClass.class);

    String jaxbContextImpl = jc.getClass().getName();
    if(MOXY_JAXB_CONTEXT.equals(jaxbContextImpl)) {
        System.out.println("EclipseLink MOXy");
    } else if(METRO_JAXB_CONTEXT.equals(jaxbContextImpl)) {
        System.out.println("Metro");
    } else {
        System.out.println("Other");
    }
}

Set Up MOXy

Create a jaxb.properties file containing this:

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

This file needs to be placed in the same packages as the domain classes you want MOXy to handle.

What does that mean?

Let’s say you have a class called Customer and you want that class to use MOXy. Let’s assume the class is in the org.myself.myapp.mybeans package. Then you must also place the jaxb.properties file in the same location as your Customer.java file - i.e. in the org.myself.myapp.mybeans package.

Later on we will see that you may also need to configure your build process to ensure that this properties file is copied to the same location as the compiled Customer.class file - because that is where the properties file ultimately needs to be located: alongside its related class files.

JAXB Libraries and JARs

The module java.se.ee was removed from Java 11. See JEP-320. This module includes JAXB (and JAX-WS and others). To use JAXB in Java 11 and newer, you therefore need to add it to your project as a separate library. This is shown below, using a Maven POM example.

warning
Jump to the final section to see notes about MOXy v3 configuration with Jakarta, where this situation has changed slighty.

The contents of my pom.xml are shown below - note that only two dependencies are needed: the JAXB API and an implementation (in our case, MOXy from the EclipseLink project):

XML
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<dependency>  
    <groupId>org.eclipse.persistence</groupId>  
    <artifactId>eclipselink</artifactId>  
    <version>2.7.6</version>  
</dependency>  

<!--   
     Use 2.3.1 below to prevent "illegal   
     reflective access operation" warnings.  
-->  
<dependency>  
    <groupId>javax.xml.bind</groupId>  
    <artifactId>jaxb-api</artifactId>  
    <version>2.3.1</version>  
</dependency>  

<!--

<dependency>  
    <groupId>com.sun.xml.bind</groupId>  
    <artifactId>jaxb-core</artifactId>  
    <version>2.3.0.1</version>  
</dependency>

<dependency>
    <groupId>org.glassfish.jaxb</groupId>
    <artifactId>jaxb-runtime</artifactId>
    <version>2.3.1</version>
    <scope>runtime</scope>
</dependency>

<dependency>  
    <groupId>com.sun.xml.bind</groupId>  
    <artifactId>jaxb-impl</artifactId>  
    <version>2.3.1</version>  
</dependency>  
-->

In the above POM, the following artifacts are shown:

Library Notes
eclipselink Contains MOXy classes as well as other libraries provided by the EclipseLink project.
jaxb-api Version 2.3.1 of the JAXB API, containing javax.xml.bind. Remember, JAXB is just an API! Maven tells me there is a newer version: 2.4.0-b180830.0359. But I have never used it.
jaxb-core This contains core classes required by some runtime modules.
jaxb-runtime This is the Glassfish reference implementation of JAXB. But not the only implementation, of course. It is part of Project Metro - which also includes the JAX-WS reference implementation, among other libraries.
jaxb-impl The old JAXB Runtime module. Version 2.3.1 is from 2018. YOU DO NOT NEED IT TO RUN MOXy. If you don’t use MOXy, You should probably be using the Metro jaxb-runtime, rather than this.

There is also this:

XML
1
2
3
4
5
6
<dependency>
    <groupId>com.sun.xml.bind</groupId>
    <artifactId>jaxb-ri</artifactId>
    <version>2.3.3</version>
    <type>pom</type>
</dependency>

This is a standalone bundle of the Glassfish (Metro) JAXB reference implementation. You can find the xjc and schemagen tools inside this JAR, since these tools are also no longer a part of the core Java distribution. You can download the JAR from here, unzip it, and then look in the bin directory to find the tools’ binaries.

Deploy MOXy

Remember to ensure the MOXy properties file is copied from the source folder to the correct target, as part of the Maven/Ant/Gradle build process.

For a Maven-based project, the following section will ensure the properties file is copied correctly:

XML
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<build>  
    <resources>  
        <resource>  
            <directory>src/main/java</directory>  
            <excludes>  
                <exclude>**/*.java</exclude>  
            </excludes>  
        </resource>  
    </resources>  
</build>  

MOXy v3+ and Jakarta

The above documentation relates to MOXy version 2.7. However, newer versions exist. As of this update, the latest available version is 3.0.0.

To use MOXy v3+, you need to account for the recent migration of several JEE products to the Jakarta project. As part of this migration, many packages which used to be part of javax are now part of jakarta.

You can read more about the background to these changes here: Transition from Java EE to Jakarta EE.

To update an older (v2) version of MOXy using javax to a newer (v3) version of MOXy using jakarta, you need to make the following changes:

Step 1)

Change the contents of the jaxb.properties file to the following:

jakarta.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

Note the changed reference to jakarta, for the bind context.

Step 2)

Change all of your jaxb imports to refer to jakarta instead of javax. So, for example, change this:

Java
1
import javax.xml.bind.JAXBContext; // old import

to this:

Java
1
import jakarta.xml.bind.JAXBContext; // new import

Step 3)

Use the following two dependencies in your pom.xml:

XML
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<dependency>
    <groupId>jakarta.xml.bind</groupId>
    <artifactId>jakarta.xml.bind-api</artifactId>
    <version>3.0.1</version>
</dependency>

<dependency>
    <groupId>org.eclipse.persistence</groupId>
    <artifactId>eclipselink</artifactId>
    <version>3.0.0</version>
</dependency>

These two dependencies are sufficient to support an updated version of the code example presented in the following example:

XPath Based Mapping using MOXy

The code in that example is a good test case, since it uses MOXy’s support for XPath-based mapping (a feature not available in the Metro implementation of JAXB).