Reputation: 53
This used to work with previous version of spring-boot v2.x with org.jvnet.jaxb2_commons dependencies but after upgrading to spring-boot v3.x and migrating to jakarta namespace the xjc compiler gives this error
Execution failed for task ':test-schema:generateTypes'.
> java.lang.AssertionError: jakarta.xml.bind.JAXBException
- with linked exception:
[org.glassfish.jaxb.runtime.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
org.glassfish.jaxb.core.api.impl.NameConverter is an interface, and JAXB can't handle interfaces.
this problem is related to the following location:
at org.glassfish.jaxb.core.api.impl.NameConverter
at public org.glassfish.jaxb.core.api.impl.NameConverter com.sun.tools.xjc.reader.xmlschema.bindinfo.BIGlobalBinding.nameConverter
at com.sun.tools.xjc.reader.xmlschema.bindinfo.BIGlobalBinding
]
This is my build.gradle file for running the xjc compilation task 'generateTypes'
configurations {
xsd
xjc
}
ext {
xsdDir = "${sourceSets.main.output.resourcesDir}/xsd"
pojoSourceXsd = '**/*efs*.xsd'
generatedSrcDir = "${projectDir}/src/generated/java"
}
if (project.hasProperty('libraryVersion')) {
project.version = project.getProperty('libraryVersion')
}
sourceSets {
main {
java {
srcDir 'src/main/java'
srcDir 'src/generated/java'
}
resources {
srcDir 'src/main/resources'
srcDir 'src/generated/resources'
}
}
}
apply plugin: "io.spring.dependency-management"
dependencyManagement {
resolutionStrategy {
cacheChangingModulesFor 0, 'seconds'
}
}
dependencies {
project.repositories.removeAll {
it instanceof MavenArtifactRepository && it.url.toString() == 'https://artylab.booking.cloud/public-maven-virtual'
}
xsd 'booking:com.booking.e3.data.financetypes.v4:4.9.11@xsd'
xsd 'booking:com.booking.e3.data.financetypes.v5:5.1.9@xsd'
xsd 'booking:com.booking.e3.data.basetypes.v4:4.4.5@xsd'
xsd 'booking:com.booking.e3.data.timetypes.v4:4.1.0@xsd'
xsd 'booking:com.booking.e3.data.placetypes.v4:4.1.3@xsd'
// XJC plugin to equals, hashCode and toString methods
//xjc 'org.jvnet.jaxb2_commons:jaxb2-basics-ant:1.11.1'
//xjc 'org.jvnet.jaxb2_commons:jaxb2-basics:1.11.1'
//xjc 'org.jvnet.jaxb2_commons:jaxb2-basics-annotate:1.0.3'
//xjc 'com.fillumina:krasa-jaxb-tools:2.3.5'
xjc ('org.jvnet.jaxb:jaxb-plugins:3.0.0') {
exclude (group: 'commons-beanutils')
exclude (group: 'commons-io')
}
xjc ('org.jvnet.jaxb:jaxb-plugin-annotate:3.0.0') {
exclude (group: 'commons-beanutils')
exclude (group: 'commons-io')
}
// XJC Runtime part to support plugins
// implementation 'org.jvnet.jaxb2_commons:jaxb2-basics-runtime:1.11.1'
// implementation 'jakarta.validation:jakarta.validation-api:3.0.2'
implementation 'jakarta.xml.bind:jakarta.xml.bind-api:3.0.0'
implementation 'org.glassfish.jaxb:jaxb-xjc:3.0.2'
implementation 'org.glassfish.jaxb:jaxb-runtime:3.0.2'
testImplementation 'junit:junit:4.13.2'
configurations.all {
exclude group: 'javax.xml.bind', module: 'jaxb-api'
exclude group: 'com.sun.xml.bind', module: 'jaxb-impl'
exclude group: 'com.sun.xml.bind', module: 'jaxb-core'
}
components {
all { details ->
if (details.id.group == "booking") {
details.statusScheme = ["continuousintegration", "directedbuilds", "releasecandidate", "release"]
}
}
}
}
clean.delete generatedSrcDir
tasks.register('copyXsdDependencies', Copy) {
description 'Copies imported XSDs to the build directory.'
println configurations.xsd.files
from configurations.xsd
into "$xsdDir/temp"
include '**/*.xsd'
// Strip version from file name for external XSDs
rename ~/(.*)-.*(\.\w+)/, '$1$2'
// Fixup any import naming issues due to case sensitivity (e.g. FinanceTypes should be changed to finance types).
doLast {
new File(xsdDir).list([accept: { d, file -> file ==~ /.*?\.xsd/ }] as FilenameFilter).toList().each { file ->
def xsdFile = new File(xsdDir, file);
def text = xsdFile.text
text = (text =~ /BaseTypes/).replaceAll('basetypes')
text = (text =~ /PlaceTypes/).replaceAll('placetypes')
text = (text =~ /PersonTypes/).replaceAll('persontypes')
text = (text =~ /FinanceTypes/).replaceAll('financetypes')
text = (text =~ /MessageTypes/).replaceAll('messagetypes')
text = (text =~ /TimeTypes/).replaceAll('timetypes')
xsdFile.write(text)
}
}
}
processResources.dependsOn copyXsdDependencies
tasks.register('generateTypes') {
dependsOn processResources
description "Generates POJOs from the XSDs."
inputs.files project.files(xsdDir)
outputs.dir(generatedSrcDir)
doLast {
mkdir generatedSrcDir
ant {
// fix schemaLocations: ensure all XSD names are in lowercase
println 'replacing files...'
xslt(extension: ".xsd", style: "src/main/resources/xsd/convert.xsl", force: "true", includes: "*.xsd",
basedir: "$xsdDir/temp", destdir: xsdDir) {
outputproperty(name: "method", value: "xml")
outputproperty(name: "standalone", value: "yes")
outputproperty(name: "indent", value: "yes")
}
delete(dir: "$xsdDir/temp")
// create custom JAXB bindings for xjc
path(id: "xsds.path") { fileset(dir: "$xsdDir", includes: "*.xsd") }
property(name: "xsds", refid: "xsds.path")
xslt(in: "src/main/resources/xsd/bindings.xml",
out: "$xsdDir/jaxb-binding.xml",
style: "src/main/resources/xsd/bindings.xsl") {
param(name: "xsds", expression: "${xsds}")
}
// run xjc compiler
taskdef(name: 'xjc', classname: 'com.sun.tools.xjc.XJCTask', classpath: sourceSets.main.runtimeClasspath.asPath)
xjc(extension: true, destdir: generatedSrcDir, binding: "$xsdDir/jaxb-binding.xml") {
schema(dir: xsdDir, includes: "*.xsd")
classpath(path: configurations.xjc.asPath)
arg(value: '-Xinheritance')
arg(value: '-Xannotate')
arg(value: '-XtoString')
arg(value: '-Xcopyable')
arg(value: '-Xfluent-api')
arg(value: "-nv")
arg(value: '-Xvalue-constructor')
}
}
}
}
compileJava.dependsOn generateTypes
jar {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
from sourceSets.main.allJava, copyXsdDependencies.outputs.files
// pack runtime dependencies in the same jar file, internally schema project is imported using *jar extension
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
}
def dists = [
[name: 'POE', artifactId: 'com.booking.efs.test.purchase.event.messages.v1'],
[name: 'PO', artifactId: 'com.booking.efs.test.purchaseorder.v1'],
[name: 'Common', artifactId: 'com.booking.efs.test.common.v1'],
[name: 'BE', artifactId: 'com.booking.efs.test.business.event.messages.v1'],
[name: 'Event', artifactId: 'com.booking.efs.test.event.v1'],
[name: 'Order', artifactId: 'com.booking.efs.test.order.v1'],
[name: 'Supply', artifactId: 'com.booking.efs.test.common.supplytypes.v1']
]
publishing {
publications {
dists.each { dist ->
//Every publication has name of the distibution
"xsd${dist.name}"(MavenPublication) {
groupId 'com.booking'
version project.version
artifactId = "${dist.artifactId}"
artifact("$xsdDir/${dist.artifactId}.xsd") {
extension "xsd"
}
}
}
//publishing task for test-schema project
maven(MavenPublication) {
groupId 'com.booking'
version project.version
artifact jar
}
}
repositories {
maven {
url System.getenv('PUBLISH_ARTIFACTORY_URL')
credentials {
if (project.hasProperty('ARTIFACTORY_USER')) {
username = "${project.'ARTIFACTORY_USER'}"
} else {
username = System.getenv("ARTIFACTORY_USER")?: "${ARTIFACTORY_USER}"
}
if (project.hasProperty('ARTIFACTORY_PASS')) {
password = "${project.'ARTIFACTORY_PASS'}"
} else if (project.hasProperty('ARTIFACTORY_PASSWORD')) {
password = "${project.'ARTIFACTORY_PASSWORD'}"
} else {
password = System.getenv("ARTIFACTORY_PASSWORD")?: "${ARTIFACTORY_PASS}"
}
}
}
}
}
task publishSnapshotXsd(dependsOn: [dists.collect { "publishXsd${it.name}ReleasePublicationToSnapshotRepository" }]) {
description 'Publishes XSD artifacts to the snapshot repostiory.'
}
task publishSnapshot() {
description 'Publishes artifacts to the snapshot repostiory.'
dependsOn publishSnapshotXsd
}
task publishReleaseXsd(dependsOn: [dists.collect { "publishXsd${it.name}ReleasePublicationToReleaseRepository" }]) {
description 'Publishes XSD artifacts to the snapshot repostiory.'
}
task publishRelease() {
dependsOn publishReleaseXsd
description 'Publishes artifacts to release.'
}
This is the bindings.xsl file
<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:jaxb="https://jakarta.ee/xml/ns/jaxb">
<xsl:param name="xsds" />
<xsl:template match="*">
<jaxb:bindings jaxb:version="3.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="https://jakarta.ee/xml/ns/jaxb"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc">
<jaxb:globalBindings>
<xjc:simple />
<jaxb:javaType name="java.time.ZonedDateTime" xmlType="xs:dateTime"
parseMethod="com.booking.efs.test.pojo.util.DateTimeSerializer.parseDateTime"
printMethod="com.booking.efs.test.pojo.util.DateTimeSerializer.printDateTime" />
<jaxb:javaType name="java.time.LocalTime" xmlType="xs:time"
parseMethod="com.booking.efs.test.pojo.util.DateTimeSerializer.parseTime"
printMethod="com.booking.efs.test.pojo.util.DateTimeSerializer.printTime" />
<jaxb:javaType name="java.time.LocalDate" xmlType="xs:date"
parseMethod="com.booking.efs.test.pojo.util.DateTimeSerializer.parseDate"
printMethod="com.booking.efs.test.pojo.util.DateTimeSerializer.printDate" />
</jaxb:globalBindings>
<xsl:call-template name="handleXsds">
<xsl:with-param name="xsdsLine" select="translate($xsds, '\', '/')" />
</xsl:call-template>
</jaxb:bindings>
</xsl:template>
<xsl:template name="handleXsds">
<xsl:param name="xsdsLine" />
<xsl:choose>
<xsl:when test="contains($xsdsLine, ';')">
<xsl:call-template name="handleXsd">
<xsl:with-param name="xsd" select="substring-before($xsdsLine, ';')" />
</xsl:call-template>
<xsl:call-template name="handleXsds">
<xsl:with-param name="xsdsLine" select="substring-after($xsdsLine, ';')" />
</xsl:call-template>
</xsl:when>
<xsl:when test="contains($xsdsLine, ':')">
<xsl:call-template name="handleXsd">
<xsl:with-param name="xsd" select="substring-before($xsdsLine, ':')" />
</xsl:call-template>
<xsl:call-template name="handleXsds">
<xsl:with-param name="xsdsLine" select="substring-after($xsdsLine, ':')" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="handleXsd">
<xsl:with-param name="xsd" select="$xsdsLine" />
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="handleXsd">
<xsl:param name="xsd" />
<xsl:variable name="xsdFilename">
<xsl:call-template name="substring-after-last">
<xsl:with-param name="string" select="$xsd" />
<xsl:with-param name="substring" select="'/'" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="packageName">
<xsl:call-template name="buildPackageFromFilename">
<xsl:with-param name="xsdFilename" select="$xsdFilename" />
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="string-length($xsdFilename) > 1">
<jaxb:bindings node="/xsd:schema">
<xsl:attribute name="schemaLocation">
<xsl:value-of select="$xsdFilename" />
</xsl:attribute>
<jaxb:schemaBindings>
<jaxb:package>
<xsl:attribute name="name">
<xsl:value-of select="$packageName" />
</xsl:attribute>
</jaxb:package>
</jaxb:schemaBindings>
</jaxb:bindings>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template name="substring-after-last">
<xsl:param name="string" />
<xsl:param name="substring" />
<xsl:variable name="substringAfter" select="substring-after($string, $substring)" />
<xsl:choose>
<xsl:when test="string-length($substringAfter) > 0">
<xsl:call-template name="substring-after-last">
<xsl:with-param name="string" select="$substringAfter" />
<xsl:with-param name="substring" select="$substring" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$string" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="buildPackageFromFilename">
<xsl:param name="xsdFilename" />
<xsl:value-of select="substring-before($xsdFilename, '.xsd')" />
</xsl:template>
</xsl:stylesheet>
Upvotes: 1
Views: 85