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

时间:2017-01-26 18:33:39

标签: java gradle xsd jaxb xjc

我们尝试使用gradle,xsd和xjc生成JAXB类,而JAXB类应该具有XmlRootElement注释,因此它可以用于公开为Web服务响应。我们正在关注此链接http://azagorneanu.blogspot.com/2011/09/configure-maven-to-generate-classes.html,它提供了大量帮助,但我们无法找到仅使用gradle的一个特定示例。所以我们想出了一些我们将分享的答案。

8 个答案:

答案 0 :(得分:11)

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

    

    <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>

下面也可以使用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>

现在您可以运行任务' jaxb ',全部设置。的 干杯

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;
    }

}

答案 1 :(得分:5)

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

答案 2 :(得分:3)

我的版本使用gradle native功能生成jaxbclasses。

可选地,如果您的架构取决于外部xsd(s),请使用&#34; Oasis Catalog&#34;在本地解析外部XSD的技术。同样在这种情况下,禁用XML模式验证以防止验证错误。

您可以选择使用自定义jaxb绑定调整jaxbclasses。 (JAXB-bindings.xjb)

基本上是一个gradle自定义任务,它调用Java VM中可用的XJCTask ant任务,在我的示例库中是来自Java 8.任务名称是&#34; generateSources&#34;,需要调整到你的模式位置。

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')
                }
    }
}

如果您需要目录,请创建一个文件&#34; catalog.xml&#34;可能看起来像这样:

<?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>

用于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>

如果除了jaxb生成之外,还需要包含要构建的类。您需要调整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
}

这就是全部!

答案 3 :(得分:1)

使用gradle-jaxb-plugin

的分级配置

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
}

和gradle.properties文件

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

并与Intellij链接,将以下内容添加到您的build.gradle文件中

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

答案 4 :(得分:1)

在撰写本文时,所有其他答案都已过时。

  • 自从 Java EE 更名为 Jakarta EE 后,JAXB 现在由新工件 jakarta.xml.bind:jakarta.xml.bind-api 提供。
  • JAXB 运行时由 org.glassfish.jaxb:jaxb-runtime 提供。
  • XJC 编译器由 org.glassfish.jaxb:jaxb-xjc 给出。

Jakarta XML Binding (previously called JAXB) Reference Implementation

xjc options

综合起来,一个使用 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)
                }
            )
        }
    }
}

答案 5 :(得分:0)

我一直在使用Spring Boot 生产SOAP Web服务指南作为参考。这是GitHub中build.gradle文件的链接。

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

答案 6 :(得分:0)

这是一个适用于Java 11 / Gradle 6的解决方案。在更新了我的一个项目的构建系统后,最近我在Gradle中通过Ant任务使用XJC发现了一些问题-这种方法仅使用普通Gradle,而没有Ant

更新:根据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")

答案 7 :(得分:0)

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