spring-projects / spring-boot

Spring Boot
https://spring.io/projects/spring-boot
Apache License 2.0
74.52k stars 40.53k forks source link

Entry BOOT-INF/lib/jaxb-core-4.0.1.jar is a duplicate but no duplicate handling strategy has been set #33659

Closed naihil closed 1 year ago

naihil commented 1 year ago

Simple gradle Spring Boot 3 project with Spring Data and Spring Web Services:

build.gradle:

plugins {
      id 'java'
      id 'org.springframework.boot' version '3.0.1'
      id 'io.spring.dependency-management' version '1.1.0'
}

group = 'com.ws'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-web-services'

    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
    useJUnitPlatform()
}

Error:

Execution failed for task ':bootJar'.
> Entry BOOT-INF/lib/jaxb-core-4.0.1.jar is a duplicate but no duplicate handling strategy has been set. Please refer to https://docs.gradle.org/7.6/dsl/org.gradle.api.tasks.Copy.html#org.gradle.api.tasks.Copy:duplicatesStrategy for details.
HououinKyouma2000 commented 1 year ago

org.hibernate:hibernate-envers:6 . i have the same problem. In the course of the conflict in the libraries inside. Below is one of the possible solutions, but it is not the best. Write it in gradle bootJar.enabled = false

naihil commented 1 year ago

Another workaround:

tasks.named('bootJar') { duplicatesStrategy = DuplicatesStrategy.EXCLUDE }

bclozel commented 1 year ago

@HououinKyouma2000 Disabling boot repackaging will prevent the application from runnning as an executable jar and won't solve the underlying problem.

@naihil I'm not sure excluding the dependency will solve the issue here, as excluding duplicates will exclude one of the jaxb-core jars: in this case, they're holding different content with classes located under different packages. This could lead to missing classes at runtime.

It looks like spring-ws-core has a hard dependency on com.sun.xml.bind:jaxb-core:

./gradlew dependencyInsight --dependency jaxb-core --configuration runtimeClasspath

> Task :dependencyInsight
com.sun.xml.bind:jaxb-core:4.0.1 (selected by rule)
  Variant runtime:
    | Attribute Name                 | Provided     | Requested    |
    |--------------------------------|--------------|--------------|
    | org.gradle.status              | release      |              |
    | org.gradle.category            | library      | library      |
    | org.gradle.libraryelements     | jar          | jar          |
    | org.gradle.usage               | java-runtime | java-runtime |
    | org.gradle.dependency.bundling |              | external     |
    | org.gradle.jvm.environment     |              | standard-jvm |
    | org.gradle.jvm.version         |              | 17           |

com.sun.xml.bind:jaxb-core:4.0.1
\--- com.sun.xml.bind:jaxb-impl:4.0.1
     \--- org.springframework.ws:spring-ws-core:4.0.0 (requested com.sun.xml.bind:jaxb-impl:4.0.0)
          \--- org.springframework.boot:spring-boot-starter-web-services:3.0.1
               \--- runtimeClasspath (requested org.springframework.boot:spring-boot-starter-web-services)

org.glassfish.jaxb:jaxb-core:4.0.1 (selected by rule)
  Variant runtime:
    | Attribute Name                 | Provided     | Requested    |
    |--------------------------------|--------------|--------------|
    | org.gradle.status              | release      |              |
    | org.gradle.category            | library      | library      |
    | org.gradle.libraryelements     | jar          | jar          |
    | org.gradle.usage               | java-runtime | java-runtime |
    | org.gradle.dependency.bundling |              | external     |
    | org.gradle.jvm.environment     |              | standard-jvm |
    | org.gradle.jvm.version         |              | 17           |

org.glassfish.jaxb:jaxb-core:4.0.1
\--- org.glassfish.jaxb:jaxb-runtime:4.0.1
     \--- org.hibernate.orm:hibernate-core:6.1.6.Final (requested org.glassfish.jaxb:jaxb-runtime:3.0.2)
          \--- org.springframework.boot:spring-boot-starter-data-jpa:3.0.1
               \--- runtimeClasspath (requested org.springframework.boot:spring-boot-starter-data-jpa)

Spring Boot has been using the Glassfish RI for a while now, so I'm wondering if this is an oversight or even needed in spring-ws?

Does the following work for your applications @naihil ?

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation ('org.springframework.boot:spring-boot-starter-web-services') {
        exclude group: "com.sun.xml.bind"
    }

    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
naihil commented 1 year ago

implementation ('org.springframework.boot:spring-boot-starter-web-services') { exclude group: "com.sun.xml.bind" }

Checked this variant, application builds and tests fine, fat jar contains jaxb-core-4.0.1.jar and jaxb-runtime-4.0.1.jar

Variant with DuplicatesStrategy.EXCLUDE compiles and tests fine too, but fat jar contains jaxb-core-4.0.1.jar, jaxb-runtime-4.0.1.jar and jaxb-impl-4.0.1.jar

naihil commented 1 year ago

Oops, close accidentally, reopen.

anbusampath commented 1 year ago

Spring Boot has been using the Glassfish RI for a while now, so I'm wondering if this is an oversight or even needed in spring-ws?

spring-ws can migrate to org.glassfish.jaxb:jaxb-runtime from com.sun.xml.bind:jaxb-impl, as both contain same classes only differs with packing style. https://eclipse-ee4j.github.io/jaxb-ri/4.0.1/docs/release-documentation.html#deployment-maven-coordinates

but fat jar contains jaxb-core-4.0.1.jar, jaxb-runtime-4.0.1.jar and jaxb-impl-4.0.1.jar

In contrast to org.glassfish.jaxb artifacts, these(com.sun.xml.bind:jaxb-impl) jars have all dependency classes included inside.

bclozel commented 1 year ago

We've discussed this as a team and we've created a Spring WS issue to address this problem. See spring-projects/spring-ws#1305

dev4sep commented 1 year ago

Hi @everyone, Spring Boot 3.0.5 with Gradle 7.6.1 I still get this issuse

Execution failed for task ':war'.

Entry WEB-INF/lib/jaxb-core-4.0.2.jar is a duplicate but no duplicate handling strategy has been set. Please refer to https://docs.gradle.org/7.6.1/dsl/org.gradle.api.tasks.Copy.html#org.gradle.api.tasks.Copy:duplicatesStrategy for details.

I try to add this below in build.gradle, but still not work for me:

bootWar { duplicatesStrategy = DuplicatesStrategy.EXCLUDE }

wilkinsona commented 1 year ago

@yisivlay Your error occurred when running the war task but you've changed the configuration of the bootWar task.

dev4sep commented 1 year ago

@wilkinsona could you pls suggestion me clearly about this?

wilkinsona commented 1 year ago

The issue tracker isn't really the right place for this sort of support as it creates too much noise for those watching the repository. If you have further questions, please follow up on Stack Overflow. As mentioned in the guidelines for contributing, we prefer to use GitHub issues only for bugs and enhancements.

dev4sep commented 1 year ago

@wilkinsona Thanks for your suggestions!

TheNullablePrototype commented 10 months ago

I have a similar problem when generating a service from a wsdl tutorials: https://spring.io/guides/gs/consuming-web-service/#initial

and generate by xsd https://spring.io/guides/gs/producing-web-service/

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.1.5'
    id 'io.spring.dependency-management' version '1.1.3'
}

group = 'group'
version = '0.0.1-SNAPSHOT'

java {
    sourceCompatibility = '21'
}

ext.jaxwsSourceDir = "${buildDir}/generated/sources/jaxws"

configurations {
    jaxb
    jaxws
    compileOnly {
        extendsFrom annotationProcessor
    }
}

sourceSets {
    main {
        java {
            srcDir 'src/main/java'
            srcDir 'build/generated/sources/jaxb'
            srcDir jaxwsSourceDir
        }
    }
}

task genJaxb {
    ext.sourcesDir = "${buildDir}/generated/sources/jaxb"
    ext.schema = "src/main/resources/xsd/catalogs.xsd"
    ext.binding = "src/main/resources/jxb/bindings.xjb"

    outputs.dir sourcesDir

    doLast() {
        project.ant {
            taskdef name: "xjc", classname: "com.sun.tools.xjc.XJCTask",
                    classpath: configurations.jaxb.asPath
            mkdir(dir: sourcesDir)

            xjc(destdir: sourcesDir, schema: schema, binding: ext.binding) {
                arg(value: "-wsdl")
                produces(dir: sourcesDir, includes: "**/*.java")
            }
        }
    }
}

task wsimport {
    description = 'Generate classes from wsdl using wsimport'

    doLast {
        project.mkdir(jaxwsSourceDir)
        ant {
            taskdef(name: 'wsimport',
                    classname: 'com.sun.tools.ws.ant.WsImport',
                    classpath: configurations.jaxws.asPath
            )
            wsimport(
                    keep: true,
                    destdir: jaxwsSourceDir,
                    extension: "true",
                    verbose: true,
                    wsdl: "https://secret.com/SERVICEWS/soap?wsdl",
                    xnocompile: true,
                    package: "com.mos.ehd") {
                xjcarg(value: "-XautoNameResolution")
            }
        }
    }
}

compileJava.dependsOn genJaxb
compileJava.dependsOn wsimport

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web-services'
    implementation 'org.springframework.boot:spring-boot-starter-validation'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-cache'
    implementation 'org.flywaydb:flyway-core'

    // support xml/xsd/wsdl
    implementation 'wsdl4j:wsdl4j'
    implementation 'com.sun.xml.ws:jaxws-rt:4.0.2'

    jaxb('org.glassfish.jaxb:jaxb-xjc:4.0.4')

    jaxws 'com.sun.xml.ws:jaxws-tools:4.0.2',
            'jakarta.xml.ws:jakarta.xml.ws-api:3.0.0',
            'jakarta.xml.bind:jakarta.xml.bind-api:4.0.1',
            'jakarta.activation:jakarta.activation-api:2.1.2'

    compileOnly 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    runtimeOnly 'org.postgresql:postgresql'
    annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

bootJar {
    setDuplicatesStrategy(DuplicatesStrategy.WARN)
}

tasks.named('test') {
    useJUnitPlatform()
}
Executing 'dependencyInsight --dependency jaxb-core --configuration runtimeClasspath'...

> Task :dependencyInsight
com.sun.xml.bind:jaxb-core:4.0.3 (selected by rule)
  Variant runtime:
    | Attribute Name                 | Provided     | Requested    |
    |--------------------------------|--------------|--------------|
    | org.gradle.status              | release      |              |
    | org.gradle.category            | library      | library      |
    | org.gradle.libraryelements     | jar          | jar          |
    | org.gradle.usage               | java-runtime | java-runtime |
    | org.gradle.dependency.bundling |              | external     |
    | org.gradle.jvm.environment     |              | standard-jvm |
    | org.gradle.jvm.version         |              | 21           |

com.sun.xml.bind:jaxb-core:4.0.3
\--- com.sun.xml.bind:jaxb-impl:4.0.3
     \--- com.sun.xml.ws:jaxws-rt:4.0.2 (requested com.sun.xml.bind:jaxb-impl:4.0.4)
          \--- runtimeClasspath

org.glassfish.jaxb:jaxb-core:4.0.3 (selected by rule)
  Variant runtime:
    | Attribute Name                 | Provided     | Requested    |
    |--------------------------------|--------------|--------------|
    | org.gradle.status              | release      |              |
    | org.gradle.category            | library      | library      |
    | org.gradle.libraryelements     | jar          | jar          |
    | org.gradle.usage               | java-runtime | java-runtime |
    | org.gradle.dependency.bundling |              | external     |
    | org.gradle.jvm.environment     |              | standard-jvm |
    | org.gradle.jvm.version         |              | 21           |

org.glassfish.jaxb:jaxb-core:4.0.3
\--- org.glassfish.jaxb:jaxb-runtime:4.0.3
     +--- org.springframework.ws:spring-ws-core:4.0.6 (requested org.glassfish.jaxb:jaxb-runtime:4.0.1)
     |    \--- org.springframework.boot:spring-boot-starter-web-services:3.1.5
     |         \--- runtimeClasspath (requested org.springframework.boot:spring-boot-starter-web-services)
     \--- org.hibernate.orm:hibernate-core:6.2.13.Final (requested org.glassfish.jaxb:jaxb-runtime:4.0.2)
          \--- org.springframework.boot:spring-boot-starter-data-jpa:3.1.5
               \--- runtimeClasspath (requested org.springframework.boot:spring-boot-starter-data-jpa)

So far, I have no idea how to deal with this problem without setting a duplication strategy, which is incorrect.

Execution failed for task ':bootJar'.
> Entry BOOT-INF/lib/jaxb-core-4.0.3.jar is a duplicate but no duplicate handling strategy has been set. Please refer to ...

UPD: Problem solved:

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web-services'
    implementation 'org.springframework.boot:spring-boot-starter-validation'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-cache'
    implementation 'org.flywaydb:flyway-core'

    // support xml/xsd/wsdl
    implementation 'wsdl4j:wsdl4j'
    implementation 'com.sun.xml.ws:rt:4.0.2'

    jaxb('org.glassfish.jaxb:jaxb-xjc:4.0.4')
    jaxb('org.glassfish.jaxb:jaxb-core:4.0.4')
    jaxb('org.glassfish.jaxb:jaxb-runtime:4.0.4')

    jaxws 'com.sun.xml.ws:jaxws-tools:4.0.2',
            'jakarta.xml.ws:jakarta.xml.ws-api:3.0.0',
            'jakarta.xml.bind:jakarta.xml.bind-api:4.0.1',
            'jakarta.activation:jakarta.activation-api:2.1.2',
            'com.sun.xml.ws:jaxws-rt:4.0.2'

    compileOnly 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    runtimeOnly 'org.postgresql:postgresql'
    annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
chkpnt commented 7 months ago

So it's just about replacing com.sun.xml.ws:jaxws-rt with com.sun.xml.ws:rt, which indirectly depends on org.glassfish.jaxb:jaxb-core instead of com.sun.xml.bind:jaxb-core? It seems to work here, too.

com.sun.xml.ws:rt has additional dependencies on com.sun.xml.ws:policyand org.glassfish.jaxb:jaxb-runtime, but is missing com.sun.xml.fastinfoset:FastInfoSet.

grafik

You might want to add com.sun.xml.fastinfoset:Fastinfoset as well as com.sun.xml.ws:rt-fi(which contains com.sun.xml.ws.encoding.fastinfoset.FastInfosetCodec that is included in jaxws-rt but no in rt), otherwise the following is logged:

2024-02-12 13:49:11.960  INFO com.sun.xml.ws.util.FastInfosetUtil      : Unable to locate compatible implementation of Fast Infoset in classpath

But other classes are also missing in rt, so additional dependencies like com.sun.xml.ws:httpspi-servlet, com.sun.xml.ws:servlet might be needed, too:

grafik

So in my opinion, an easier drop-in replacement is just to exclude com.sun.xml.bind:jaxb-core from com.sun.xml.ws:jaxws-rt, until something like org.glassfish.ws:jaxws-rt gets available:

    implementation("com.sun.xml.ws:jaxws-rt") {
        exclude(group = "com.sun.xml.bind", module = "jaxb-impl")
    }
    runtimeOnly("org.glassfish.jaxb:jaxb-runtime")