Stefano Bossi
Stefano Bossi

Reputation: 1437

Jetty AnnotationParser scanned from multiple locations warning

I have a project build with Gradle, it's actually a Vaadin project, with a servlet where I use Jetty. At the startup (i.e gradle run) I have a lot of different warning message from AnnotationParser about duplication of classes. I copy only one because the log is quite verbose:

[INFO ] 11:22:50.375 org.eclipse.jetty.server.Server.doStart() - jetty-9.4.31.v20200723; built: 2020-07-23T17:57:36.812Z; git: 450ba27947e13e66baa8cd1ce7e85a4461cacc1d; jvm 13.0.2+8
[WARN ] 11:22:50.777 org.eclipse.jetty.annotations.AnnotationParser.addParsedClass() - javax.websocket.ClientEndpoint scanned from multiple locations: jar:file:///Users/fox/.gradle/caches/modules-2/files-2.1/javax.websocket/javax.websocket-api/1.0/fc843b649d4a1dcb0497669d262befa3918c7ba8/javax.websocket-api-1.0.jar!/javax/websocket/ClientEndpoint.class, jar:file:///Users/fox/.gradle/caches/modules-2/files-2.1/javax.websocket/javax.websocket-client-api/1.0/afcf19e889d8725576811f8d47ab6c65d9dcbd78/javax.websocket-client-api-1.0.jar!/javax/websocket/ClientEndpoint.class

In this line AnnotationParser warns me that the ClientEndpoint.class is present in two jar, the javax.websocket-api-1.0.jar and the javax.websocket-client-api-1.0.jar. With the command gradle dependencies I could see:

...
     +--- org.eclipse.jetty.websocket:javax-websocket-client-impl:9.4.31.v20200723
     |    +--- org.eclipse.jetty.websocket:websocket-client:9.4.31.v20200723 (*)
     |    \--- javax.websocket:javax.websocket-client-api:1.0
     +--- org.eclipse.jetty.websocket:websocket-server:9.4.31.v20200723 (*)
     \--- javax.websocket:javax.websocket-api:1.0

In my gradle.build I only have:

dependencies {

    // Vaadin
    implementation enforcedPlatform('com.vaadin:vaadin-bom:18.0.6')
    implementation("com.vaadin:vaadin-core")
    implementation group: 'com.github.appreciated', name: 'vaadin-css-grid', version: '2.0.0'

    // Logging
    implementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.13.1'
    implementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.13.1'
    implementation group: 'org.apache.logging.log4j', name: 'log4j-slf4j-impl', version: '2.13.1'
    
    // Testing
    testImplementation group: 'junit', name: 'junit', version: '4.12'
    testImplementation group: 'org.skyscreamer', name: 'jsonassert', version: '1.5.0'

    // Jetty
    implementation group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.4.31.v20200723'
    implementation group: 'org.eclipse.jetty', name: 'jetty-webapp', version: '9.4.31.v20200723'
    implementation group: 'org.eclipse.jetty.websocket', name: 'websocket-server', version: '9.4.31.v20200723'
    implementation group: 'org.eclipse.jetty.websocket', name: 'javax-websocket-server-impl', version: '9.4.31.v20200723'
}

All these logs are really annoying (they slow down the start up really much) and I can't understand if they are dangerous or not.

Which is the right way to avoid duplications ? Is there a technique to instruct AnnotationParser to scan only some dependencies? I know this topic is present in different questions but I didn't find a solution for gradle or a common solution strategy.

Thanks, Stefano

Upvotes: 0

Views: 1267

Answers (1)

Joakim Erdfelt
Joakim Erdfelt

Reputation: 49515

Having the same class name in multiple locations on your classpath is a bad idea.

This is the most common form of unstable operation on Java there is!

The classloaders in Java have no guarantee of load order behavior if the same class is present in multiple locations within the classloader.

In one run you might accidentally load the classes in the order you intend, and have it run properly, then at a future date you run the same program and the load order is different, now you are running with a different class version and you have unexpected behavior.

The only way to fix this is to clean up your classloader and ensure that you only have 1 version of the class you intend to use.

This is what Jetty is telling you.

As for this specific one, javax.websocket-api and javax.websocket-client-api, you want to exclude javax.websocket-client-api at the gradle level, as all of the websocket client classes are also present in the javax.websocket-api.

The javax.websocket-client-api jar is only intended for projects that only use the javax.websocket Client, without a javax.websocket Server.


Following the suggestion of joakim-erdfelt I have modified my build.gradle and this prevent the problem:

    implementation ('org.eclipse.jetty.websocket:javax-websocket-server-impl:9.4.31.v20200723')  {
        exclude module: 'javax.websocket-client-api' 
    }

The Gradle documentation is here: Excluding transitive dependencies

Upvotes: 2

Related Questions