1

So I am able to generate classes from ONE xsd in the contract jar, using ant xjc. How can I generate classes from multiple schemas from this jar without unpacking it

 ant.xjc(package: packageName, destdir: project.ext.generatedSrcDir,    
 extension: 'true',
 schema: "jar:file:///$pathToContractJar!/MySchema.xsd")
arseniyandru
  • 760
  • 1
  • 7
  • 16
  • Don't have time for a full answer, just a quick hint. You can use a catalog file to rewrite absolute schema URLs to other URLs. So you can write a catalog file to rewrite URLs of your schemas info `jar:fille:///..` URLs and then use XJC to compile absolute URLs. I use this trick with Maven, but it should work with Gradle as well. – lexicore Nov 01 '16 at 20:51
  • Catalog file? Like windows catalog file? I didn't get that – arseniyandru Nov 02 '16 at 02:18
  • No, like XML catalog file. See [this](https://github.com/highsource/maven-jaxb2-plugin/wiki/Using-Catalogs) or [this](http://blog.bdoughan.com/2011/10/jaxb-xjc-imported-schemas-and-xml.html). – lexicore Nov 02 '16 at 09:57
  • I found an alternative XJC task: https://github.com/urbic/ant-xjc – Ondra Žižka Jul 22 '20 at 14:47

2 Answers2

7
configurations {
    jaxb
}
dependencies {
    jaxb 'com.sun.xml.bind:jaxb-xjc:2.2.6'
    jaxb 'com.sun.xml.bind:jaxb-impl:2.2.6'
    jaxb 'javax.xml.bind:jaxb-api:2.2.6'    
}
task xjc {
    def xsds = zipTree(pathToContractJar).matching { 
        include: '*.xsd' 
    }
    inputs.dir "src/main/resources/bindings"
    inputs.files xsds
    outputs.dir "$buildDir/xjc"
    doLast {
        System.setProperty('javax.xml.accessExternalSchema', 'all')
        mkdir "$buildDir/xjc/result"
        mkdir "$buildDir/xjc/xsd"

        copy {
            from xsds
            into "$buildDir/xjc/xsd"
        }
        ant.taskdef(name: 'xjc', classname: 'com.sun.tools.xjc.XJCTask', classpath: configurations.jaxb.asPath)
        ant.xjc(
            destdir: "$buildDir/xjc/result",
            package: packageName,
        ) {
            schema(dir: "$buildDir/xjc/xsd", includes: '*.xsd')
            binding(dir: "src/main/resources/bindings", includes: '*.xjb')
            arg(value: '-verbose')
        }
    }
}
lance-java
  • 25,497
  • 4
  • 59
  • 101
  • Thanks @lance-java. I'm searching the entire Internet for a way to add this parameter in `System.setProperty('javax.xml.accessExternalSchema', 'all')`, found it in your snippet. – tuan.dinh Aug 19 '20 at 02:35
3

I was using this for a long time, but I found moving to Java 11 / Gradle 6 it didn't work any more. Java 11 does not have the JAXB API so it needs to be added as a dependency. Also the mechanism of calling XJC using Ant inside Gradle didn't want to work, possibly I just didn't find the magic combination of flags! Instead it is possible to call the XJC main class listed in the JAR manifest, cutting out Ant altogether. The configuration here is working for me using Gradle 6.3 and Java 11.

I haven't tried using this approach with a JAR + binding file, but the parameters are available according to the usage info so it should work!

UPDATE: Using the GlassFish implementation avoids issues with Sun internal dependencies, as per this question

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