简体   繁体   English

如何使用 gradle、jaxb 和 xjc 从 xsd 生成 jaxb 类,类应该有 XmlRootElement

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

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.我们尝试使用 gradle、xsd 和 xjc 生成 JAXB 类,并且 JAXB 类应该具有 XmlRootElement 注释,以便它可以用于作为 Web 服务响应公开。 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.我们正在关注此链接http://azagorneanu.blogspot.com/2011/09/configure-maven-to-generate-classes.html ,它有很大帮助,但我们无法找到一个仅使用 gradle 的特定示例。 So we figured out few things what we will share as an answer.因此,我们想出了一些我们将作为答案分享的内容。

build.gradle should look like below build.gradle 应该如下所示

    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架构.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绑定.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下面的 binding.xjb 也可以使用

<?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.现在您可以运行任务 ' jaxb ',全部设置。 Cheers !干杯

User.java用户.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;
    }

}
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

My version use gradle native feature to generate jaxbclasses.我的版本使用 gradle 本机功能来生成 jaxbclasses。

Optionally, if case your schema depends on external xsd(s), use "Oasis Catalog" technique to resolve external XSD locally.或者,如果您的架构依赖于外部 xsd,请使用“Oasis Catalog”技术在本地解析外部 XSD。 Also in this case disable XML schema validations to prevent validation errors.同样在这种情况下,禁用 XML 架构验证以防止验证错误。

Optionally you can adjust your jaxbclasses with a custom jaxb binding.或者,您可以使用自定义 jaxb 绑定调整您的 jaxbclasses。 (Jaxb-bindings.xjb) (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.基本上是一个 gradle 自定义任务,它调用 Java VM 中可用的 XJCTask ant 任务,在我的示例库中来自 Java 8。任务名称是“generateSources”,需要根据您的模式位置进行调整。

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:如果您需要目录,请创建一个文件“catalog.xml”,它可能如下所示:

<?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对于 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.如果除了 jaxb 生成之外,还需要包含这些类来构建。 You need to adjust gradle source layout, and dependencies.您需要调整 gradle 源布局和依赖项。

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!就这样!

Gradle configuration for using gradle-jaxb-plugin使用gradle-jaxb-plugin 的Gradle 配置

The commented out values in the xjc configuration are the default values - change if required. xjc 配置中注释掉的值是默认值 - 如果需要可以更改。

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和 gradle.properties 文件

# 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并将其与 Intellij 链接,将以下内容添加到您的 build.gradle 文件中

idea.module.iml {
    whenMerged {
        dependsOn jaxb
    }
}

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 .由于 Java EE 更名为 Jakarta EE,因此 JAXB 现在由新工件jakarta.xml.bind:jakarta.xml.bind-api
  • JAXB runtime is given by org.glassfish.jaxb:jaxb-runtime . JAXB 运行时由org.glassfish.jaxb:jaxb-runtime
  • XJC compiler is given by org.glassfish.jaxb:jaxb-xjc . XJC 编译器由org.glassfish.jaxb:jaxb-xjc

Jakarta XML Binding (previously called JAXB) Reference Implementation . Jakarta XML 绑定(以前称为 JAXB)参考实现

xjc options . xjc 选项

Putting it all together, a complete working example using Kotlin DSL:综上所述,这是一个使用 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)
                }
            )
        }
    }
}

I've been using the Spring Boot Producing a SOAP web service guide for reference.我一直在使用 Spring Boot Producing a SOAP web service guide 作为参考。 Here's the link to the build.gradle file in GitHub.这是 GitHub 中 build.gradle 文件的链接。

https://github.com/spring-guides/gs-producing-web-service/blob/master/complete/build.gradle https://github.com/spring-guides/gs-production-web-service/blob/master/complete/build.gradle

Here is a solution that works for me with Java 11 / Gradle 6. After updating the build system on one of my projects recently I found some issues using XJC via Ant tasks in Gradle - this approach just uses plain Gradle, without Ant.这是一个适用于 Java 11/Gradle 6 的解决方案。最近在我的一个项目上更新构建系统后,我发现通过 Gradle 中的 Ant 任务使用 XJC 存在一些问题 - 这种方法只使用普通的 Gradle,没有 Ant。

UPDATE: Using the GlassFish implementation avoids issues with Sun internal dependencies, as per this question更新:根据这个问题,使用 GlassFish 实现避免了 Sun 内部依赖的问题

sourceSets {

    generated {
        java.srcDir "$generated_dir"
    }
}

dependencies {

    compile sourceSets.generated.output

    // Generated code depends on the JAXB API, which is removed from base Java in JDK 11
    compile "org.glassfish.jaxb:jaxb-runtime:2.3.3"
    generatedCompile "org.glassfish.jaxb:jaxb-runtime:2.3.3"
}


// XJC tasks

// JAXB configuration holds classpath for running the JAXB XJC compiler
configurations {
    jaxb
}

dependencies {

    jaxb "org.glassfish.jaxb:jaxb-xjc:2.3.3"
}

// Cookie cutter function for defining multiple XJC tasks
// (not necessary if you only have a single task)!
def addXjcTask(taskName, schema, pkg, dest) {

    // If you haven't already, create the generated output dir before running XJC or it will fail
    file(dest).mkdirs()

    // The main XJC task, calls XJCFacade which is the entry point of the XJC JAR
    tasks.create(name: taskName, type: JavaExec) {

        classpath configurations.jaxb
        main 'com.sun.tools.xjc.XJCFacade'

        // To explore available args, download the XJC JAR manually and run java -jar jaxb-xjc.jar --help
        args schema, "-p", pkg, "-d", dest
    }

    // Add a dependency on the new task so it gets invoked
    compileGeneratedJava.dependsOn tasks.getByName(taskName)
}

// Add all the XJC tasks you need

addXjcTask("xjcSchema1",
        "path/to/schema1.xsd",
        'com.example.generated.schema1',
        "$generated_dir")

addXjcTask("xjcSchema2",
        "path/to/schema2.xsd",
        'com.example.generated.schema2',
        "$generated_dir")

That's what worked for me with Java 14 and Gradle 6.7 My build.gradle file looks like this:这就是 Java 14 和 Gradle 6.7 对我有用的方法我的 build.gradle 文件如下所示:

buildscript {
  repositories {
    jcenter()
    mavenCentral()
    maven {
        url 'https://plugins.gradle.org/m2/'
    }
  }
  dependencies {
    classpath 'gradle.plugin.org.openrepose:gradle-jaxb-plugin:2.5.0'
  }
}

apply plugin: 'org.openrepose.gradle.plugins.jaxb'

dependencies {
    jaxb 'org.jvnet.jaxb2_commons:jaxb2-basics:1.11.1'
    jaxb 'org.jvnet.jaxb2_commons:jaxb2-basics-ant:1.11.1'
    jaxb 'org.jvnet.jaxb2_commons:jaxb2-basics-annotate:1.0.4'
    jaxb 'org.slf4j:slf4j-log4j12:1.7.25'
    jaxb 'org.glassfish.jaxb:jaxb-xjc:2.2.11'
    jaxb 'org.glassfish.jaxb:jaxb-runtime:2.2.11'
    jaxb 'javax.activation:activation:1.1.1'
}

jaxb {
  println 'Starting JAXB XJC...'
  xsdDir = "${projectDir}/src/main/resources/schemas/xsd"
  xjc {
     generateEpisodeFiles = false
     destinationDir  = "$buildDir/generated/sources/jaxb"
     taskClassname   = "org.jvnet.jaxb2_commons.xjc.XJC2Task"
     generatePackage = "your.own.package.name"
     args            = ["-Xinheritance", "-Xannotate"]
  }
}

// allow schemas with empty namespace
tasks.named("xsd-dependency-tree").configure {
    outputs.upToDateWhen { false }
}

compileJava.dependsOn xjc

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM