How to generate jaxb classes from xsd using gradle, jaxb and xjc, classes should have XmlRootElement

51,666

Solution 1

build.gradle should look like below

    buildscript {
    repositories {
    mavenCentral()
        jcenter()
    }
    dependencies {
        classpath "net.saliman:gradle-cobertura-plugin:2.2.4"
        classpath 'com.github.jacobono:gradle-jaxb-plugin:1.3.5'

    }
}
apply plugin: 'com.github.jacobono.jaxb'
dependencies {
    jaxb 'com.sun.xml.bind:jaxb-xjc:2.2.7'
    jaxb "org.jvnet.jaxb2_commons:jaxb2-basics-ant:0.6.5"
    jaxb "org.jvnet.jaxb2_commons:jaxb2-basics:0.6.4"
    jaxb "org.jvnet.jaxb2_commons:jaxb2-basics-annotate:0.6.4"
}
configurations {
    jaxb
}
task jaxb(){
    description 'Converts xsds to classes'
    def jaxbTargetDir = file("generated")
    doLast {
    jaxbTargetDir.mkdirs()
    ant.taskdef(name: 'xjc', classname: 'org.jvnet.jaxb2_commons.xjc.XJC2Task', classpath: configurations.jaxb.asPath)
    ant.jaxbTargetDir = jaxbTargetDir 
    ant.xjc(destdir: '${jaxbTargetDir}', package: 'com.sample.jaxbclasses', schema:'generated/schema.xsd', binding:'generated/binding.xjb', extension:'true'){
        arg(value: "-Xannotate")
        }
    }
}

schema.xsd

    <xs:element name="user" type="user" />
    <xs:element name="userList" type="userList" />

    <xs:complexType name="user">
        <xs:all>
            <xs:element name="id" type="xs:long" minOccurs="0" />
            <xs:element name="name" type="xs:string" />
            <xs:element name="registrationDate" type="xs:dateTime" />
        </xs:all>
    </xs:complexType>

    <xs:complexType name="userList">
        <xs:sequence>
            <xs:element name="user" type="user" minOccurs="0" maxOccurs="unbounded" />
        </xs:sequence>
    </xs:complexType>

</xs:schema>

binding.xjb

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:annox="http://annox.dev.java.net" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd"
    version="2.1">
    <jaxb:globalBindings>
        <!-- Use java.util.Calendar instead of javax.xml.datatype.XMLGregorianCalendar for xs:dateTime -->
        <jaxb:javaType name="java.util.Calendar" xmlType="xs:dateTime"
                parseMethod="javax.xml.bind.DatatypeConverter.parseDateTime" 
                printMethod="javax.xml.bind.DatatypeConverter.printDateTime" />

        <!-- Force all classes implements Serializable -->
        <xjc:serializable uid="1" />
    </jaxb:globalBindings>

    <!-- Annotate the following classes with XmlRootElement -->
    <jaxb:bindings schemaLocation="schema.xsd" node="/xs:schema">
        <jaxb:bindings node="xs:complexType[@name='user']">
            <annox:annotate>
                <annox:annotate annox:class="javax.xml.bind.annotation.XmlRootElement" name="user" />
            </annox:annotate>
        </jaxb:bindings>
        <jaxb:bindings node="xs:complexType[@name='userList']">
            <annox:annotate>
                <annox:annotate annox:class="javax.xml.bind.annotation.XmlRootElement" name="userList" />
            </annox:annotate>
        </jaxb:bindings>
    </jaxb:bindings>
</jaxb:bindings>

below binding.xjb could be used as well

<?xml version="1.0"?>
<jxb:bindings version="1.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" jxb:extensionBindingPrefixes="xjc" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <jxb:bindings schemaLocation="schema.xsd" node="/xs:schema">
    <jxb:globalBindings>
      <xjc:simple />
    </jxb:globalBindings>
  </jxb:bindings>
</jxb:bindings>

Now you can run the task 'jaxb', All set. Cheers!

User.java

//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.7 
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// Any modifications to this file will be lost upon recompilation of the source schema. 
// Generated on: 2017.01.26 at 11:59:18 AM EST 
//


package com.sample.jaxbclasses;

import java.io.Serializable;
import java.util.Calendar;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSchemaType;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;


/**
* <p>Java class for user complex type.
* 
 * <p>The following schema fragment specifies the expected content contained within this class.
* 
 * <pre>
* &lt;complexType name="user">
*   &lt;complexContent>
*     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
*       &lt;all>
*         &lt;element name="id" type="{http://www.w3.org/2001/XMLSchema}long" minOccurs="0"/>
*         &lt;element name="name" type="{http://www.w3.org/2001/XMLSchema}string"/>
*         &lt;element name="registrationDate" type="{http://www.w3.org/2001/XMLSchema}dateTime"/>
*       &lt;/all>
*     &lt;/restriction>
*   &lt;/complexContent>
* &lt;/complexType>
* </pre>
* 
 * 
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "user", propOrder = {

})
@XmlRootElement(name = "user")
public class User
    implements Serializable
{

    private final static long serialVersionUID = 1L;
    protected Long id;
    @XmlElement(required = true)
    protected String name;
    @XmlElement(required = true, type = String.class)
    @XmlJavaTypeAdapter(Adapter1 .class)
    @XmlSchemaType(name = "dateTime")
    protected Calendar registrationDate;

    /**
     * Gets the value of the id property.
     * 
     * @return
     *     possible object is
     *     {@link Long }
     *     
     */
    public Long getId() {
        return id;
    }

    /**
     * Sets the value of the id property.
     * 
     * @param value
     *     allowed object is
     *     {@link Long }
     *     
     */
    public void setId(Long value) {
        this.id = value;
    }

    /**
     * Gets the value of the name property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getName() {
        return name;
    }

    /**
     * Sets the value of the name property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setName(String value) {
        this.name = value;
    }

    /**
     * Gets the value of the registrationDate property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public Calendar getRegistrationDate() {
        return registrationDate;
    }

    /**
     * Sets the value of the registrationDate property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setRegistrationDate(Calendar value) {
        this.registrationDate = value;
    }

}

Solution 2

group 'com.example'
version '1.0-SNAPSHOT'

apply plugin: 'java'

sourceCompatibility = 1.8
targetCompatibility = 1.8


repositories {
    mavenCentral()
}

project.ext {
    jaxbTargetDir = file("src/generated/java")

}


configurations {
    xsd2java
}

dependencies {
    xsd2java "com.sun.xml.bind:jaxb-xjc:2.2.6"
    xsd2java "com.sun.xml.bind:jaxb-impl:2.2.6"
}

task xsd2java() {

    doLast {
        jaxbTargetDir.mkdirs()

        ant.taskdef(name: 'xjc', classname: 'com.sun.tools.xjc.XJCTask', classpath: configurations.xsd2java.asPath)
        ant.jaxbTargetDir = jaxbTargetDir


        ant.xjc(
                destdir: '${jaxbTargetDir}',
                package: 'com.example.request',
                schema: 'src/main/resources/XMLreq.xsd'
        )

        ant.xjc(
                destdir: '${jaxbTargetDir}',
                package: 'com.example.response',
                schema: 'src/main/resources/XMLres.xsd'
        )

    }
}
compileJava.dependsOn xsd2java

Solution 3

My version use gradle native feature to generate jaxbclasses.

Optionally, if case your schema depends on external xsd(s), use "Oasis Catalog" technique to resolve external XSD locally. Also in this case disable XML schema validations to prevent validation errors.

Optionally you can adjust your jaxbclasses with a custom jaxb binding. (Jaxb-bindings.xjb)

Basically is a gradle custom task, which invoke the XJCTask ant task available in Java VM, in my example libraries are from Java 8. Task name is "generateSources", and need to be adjusted to your schema location.

configurations {
    jaxb // Only for generation purpose
}

dependencies {
    jaxb  'javax.xml.bind:jaxb-api:2.2.11' 
    jaxb  'com.sun.xml.bind:jaxb-xjc:2.2.11'    
    jaxb  'com.sun.xml.bind:jaxb-impl:2.2.11'
    jaxb  'com.sun.xml.bind:jaxb-osgi:2.2.11'
}

task generateSources() {
    doLast {
        def jaxbTargetDir = file("$buildDir/generated/src/main/java")

        if (!jaxbTargetDir.exists()) {
            jaxbTargetDir.mkdirs()
        }

        ant.taskdef(name: 'xjc', classname: 'com.sun.tools.xjc.XJCTask', classpath: configurations.jaxb.asPath)

        ant.xjc(
                destdir: "${jaxbTargetDir}",
                schema: "${projectDir}/src/main/resources/MySchema.xsd",
                binding: "${projectDir}/src/main/resources/jaxb-bindings.xjb",
                catalog: "${projectDir}/src/main/resources/catalog.xml",
                removeOldOutput: 'yes', extension: 'true'
        )
                {
                    arg(line: '-nv -disableXmlSecurity')
                }
    }
}

In case you need catalog create a file "catalog.xml" which might look like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE catalog
    PUBLIC "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN"
           "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd">
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
    <system systemId="http://www.w3.org/TR/2002/REC-xmlenc-core-20021210/xenc-schema.xsd" uri="xenc-schema.xsd" />
    <system systemId="http://www.w3.org/TR/xmlenc-core/xenc-schema.xsd" uri="xenc-schema.xsd" />
    <system systemId="http://www.w3.org/TR/2002/REC-xmldsig-core-20020212/xmldsig-core-schema.xsd" uri="xmldsig-core-schema.xsd" />
</catalog>

For jaxbinding

<?xml version="1.0" encoding="UTF-8"?>
<bindings xmlns="http://java.sun.com/xml/ns/jaxb" version="2.1"
    xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <globalBindings>
        <xjc:javaType
            adapter="org.gazpachoquest.sample.JodaLocalDateTimeConverter"
            name="org.joda.time.LocalDateTime" xmlType="xs:dateTime" />
    </globalBindings>
</bindings>

If in addition to jaxb generation, you need to include those classes to build. You need to adjust gradle source layout, and dependencies.

apply plugin: 'java'

def generatedSourcesOutput = "$buildDir/generated/main/java"

sourceSets {
    main {
        java.srcDirs "$generatedSourcesOutput"
    }
}

configurations {
    jaxb
}

dependencies {
    jaxb  'javax.xml.bind:jaxb-api:2.2.11' 
    jaxb  'com.sun.xml.bind:jaxb-xjc:2.2.11'    
    jaxb  'com.sun.xml.bind:jaxb-impl:2.2.11'
    jaxb  'com.sun.xml.bind:jaxb-osgi:2.2.11'

    compile 'com.sun.xml.bind:jaxb-xjc:2.2.11'
    compile 'com.sun.xml.bind:jaxb-impl:2.2.11'
    compile 'javax.xml.bind:jaxb-api:2.2.11'
}

compileJava {
    dependsOn generateSources
}

That's all!

Solution 4

All of the other answers are outdated as of the time of this writing.

  • Since Java EE was rebranded to Jakarta EE, JAXB is now provided by new artifact jakarta.xml.bind:jakarta.xml.bind-api.
  • JAXB runtime is given by org.glassfish.jaxb:jaxb-runtime.
  • XJC compiler is given by org.glassfish.jaxb:jaxb-xjc.

Jakarta XML Binding (previously called JAXB) Reference Implementation.

xjc options.

Putting it all together, a complete working example using Kotlin DSL:

val jaxb: Configuration by configurations.creating

val jaxbVersion: String by project    
val schemaDir = "src/main/resources"
val xjcOutputDir = "$buildDir/generated/source/xjc/main"

dependencies {
    jaxb("org.glassfish.jaxb:jaxb-xjc:$jaxbVersion")
    implementation("jakarta.xml.bind:jakarta.xml.bind-api:$jaxbVersion")
    runtimeOnly("org.glassfish.jaxb:jaxb-runtime:$jaxbVersion")
}

val createXjcOutputDir by tasks.register("createXjcOutputDir") {
    doLast {
        mkdir(xjcOutputDir)
    }
}

val xjc by tasks.registering(JavaExec::class) {
    // Directory needs to exist 
    dependsOn(createXjcOutputDir)
    classpath = jaxb
    mainClass.set("com.sun.tools.xjc.XJCFacade")
    args = listOf(
        "-d",
        xjcOutputDir,
        "-p",
        project.group.toString(),
        "-encoding",
        "UTF-8",
        "-no-header",
        "-quiet",
        schemaDir
    )
}

tasks.withType<JavaCompile>().configureEach {
    dependsOn(xjc)
}

sourceSets {
    main {
        java {
            srcDirs(
                files(xjcOutputDir) {
                    builtBy(xjc)
                }
            )
        }
    }
}

Solution 5

Gradle configuration for using gradle-jaxb-plugin

The commented out values in the xjc configuration are the default values - change if required.

buildscript {
    repositories gradle.repos

    dependencies {
    }
}

plugins {
    id "org.openrepose.gradle.plugins.jaxb" version "2.5.0"
    id 'groovy'
    id 'java'
    id "org.springframework.boot" version "2.1.2.RELEASE"
    id 'checkstyle'
}

apply plugin: 'io.spring.dependency-management'
apply plugin: "org.openrepose.gradle.plugins.jaxb"
apply plugin: 'idea'
apply plugin: 'maven-publish'

repositories gradle.repos

configurations {
    jaxb
    codeq
    compile.exclude module: "spring-boot-starter-tomcat"
}

jaxb {
    xjc {
        //taskClassname        = 'com.sun.tools.xjc.XJC2Task'
        //xsdDir               = "${project.projectDir}/src/main/resources/schema"
        generateEpisodeFiles = false
        generatePackage      = 'com.mycompany.mypackage'
        destinationDir       = "${buildDir}/generated/src/main/java"
        args                 = ["-Xannotate"]
    }
}

compileJava.dependsOn {
    'xjc'
}

sourceSets {
    main {
        java {
            srcDirs jaxb.xjc.destinationDir
        }
        resources {
            srcDirs 'src/main/resources'
        }
    }
}

dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudDependenciesVersion}"
    }
}

dependencies {

    // Jaxb dependencies
    jaxb group: 'org.glassfish.jaxb', name: 'jaxb-xjc', version: jaxbxjcVersion
    jaxb 'org.jvnet.jaxb2_commons:jaxb2-basics-annotate:1.0.4'
    jaxb 'org.slf4j:slf4j-log4j12:1.7.25'
    implementation group: 'javax.xml.bind', name: 'jaxb-api', version: jaxbApiVersion
}

and gradle.properties file

# JAXB Processing Properties
jaxbPluginVersion = 2.5.0
jaxbxjcVersion = 2.3.2
jaxbApiVersion = 2.3.1

and to link it with Intellij add the following to your build.gradle file

idea.module.iml {
    whenMerged {
        dependsOn jaxb
    }
}
Share:
51,666

Related videos on Youtube

Aamir
Author by

Aamir

Software developer

Updated on July 29, 2021

Comments

  • Aamir
    Aamir almost 3 years

    We were trying to generate JAXB classes using gradle, xsd and xjc, and JAXB classes should have XmlRootElement annotations so it could be used to expose as web service reponse. We were following this link http://azagorneanu.blogspot.com/2011/09/configure-maven-to-generate-classes.html, it helped in great deal but we were unable to find one particular example with gradle only. So we figured out few things what we will share as an answer.

    • user3470953
      user3470953 about 6 years
      jeejava.com/generating-jaxb-classes-from-xsd-using-gradle/
    • lunicon
      lunicon almost 3 years
      Good instruction found on plugin site github.com/dmak/jaxb-xew-plugin
  • tuan.dinh
    tuan.dinh over 3 years
    In case you have multple .xsd files, one reference to these other, you need to add this System.setProperty('javax.xml.accessExternalSchema', 'all') to your doLast()
  • donny
    donny over 3 years
    Hello @Martin Traverse do you have git repo for this issue ? Since i'm facing same issue on JDK 11 and Gradle 6
  • Abhijit Sarkar
    Abhijit Sarkar about 3 years
    @donny Check my answer using Java 11 and Gradle 6.8.