[Java] LinkageError ... previously initiated loading

Pagina: 1
Acties:

Onderwerpen

Vraag


Acties:
  • 0 Henk 'm!

  • skandalouz
  • Registratie: Oktober 2010
  • Laatst online: 26-05 20:32
Hi!

Ik heb een Java project icm Spring framework en Maven. Het project is opgesplitst in een aantal submodules en ik wil nu een module toevoegen voor een Discord bot. Ik heb de volgende dependency toegevoegd voor Maven (incl de benodige repository):

XML: bot/pom.xml
1
2
3
4
5
<dependency>
    <groupId>com.github.austinv11</groupId>
    <artifactId>Discord4j</artifactId>
    <version>2.6.1</version>
</dependency>


Er wordt een bean gemaakt in een config class in de bot module:
Java: BotConfig.java
1
2
3
4
5
6
7
8
9
@Configuration
public class BotConfig {

    @Bean
    public IDiscordClient discordClient( ) throws DiscordException {
         //create and return client
    }

}


Deze wordt geimporteerd in the configuratie in de web module
Java: BotConfig.java
1
2
3
4
5
6
7
@Configuration
@Import({ BotConfig.class })
public class WebConfig extends WebMvcConfigurerAdapter {

    @Autowired
    private IDiscordClient client;
}


Ik draai de applicatie met een jetty plugin voor eclipse:
XML: web/pom.xml
1
2
3
4
5
6
7
8
9
10
11
12
<build>
    <plugins>
        <plugin>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-maven-plugin</artifactId>
            <version>9.3.11.v20160721</version>
            <configuration>
                <systemPropertiesFile>${properties.file}</systemPropertiesFile>
            </configuration>
        </plugin>
    </plugins>
</build>


Dit resulteert in de volgende error:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
java.lang.LinkageError: loader constraint violation: loader (instance of org/codehaus/plexus/classworlds/realm/ClassRealm) previously initiated loading for a different type with name "org/eclipse/jetty/util/ssl/SslContextFactory"
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:760)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
    at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClassFromSelf(ClassRealm.java:401)
    at org.codehaus.plexus.classworlds.strategy.SelfFirstStrategy.loadClass(SelfFirstStrategy.java:42)
    at org.codehaus.plexus.classworlds.realm.ClassRealm.unsynchronizedLoadClass(ClassRealm.java:271)
    at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClass(ClassRealm.java:247)
    at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClass(ClassRealm.java:239)
    at org.eclipse.jetty.websocket.client.io.WebSocketClientSelectorManager.newSSLEngine(WebSocketClientSelectorManager.java:129)
    at org.eclipse.jetty.websocket.client.io.WebSocketClientSelectorManager.newConnection(WebSocketClientSelectorManager.java:86)
    at org.eclipse.jetty.io.ManagedSelector.createEndPoint(ManagedSelector.java:422)
    at org.eclipse.jetty.io.ManagedSelector.access$1600(ManagedSelector.java:56)
    at org.eclipse.jetty.io.ManagedSelector$CreateEndPoint.run(ManagedSelector.java:605)
    at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.executeProduceConsume(ExecuteProduceConsume.java:303)
    at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.produceConsume(ExecuteProduceConsume.java:148)
    at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.execute(ExecuteProduceConsume.java:100)
    at org.eclipse.jetty.io.ManagedSelector.run(ManagedSelector.java:147)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:671)
    at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:589)
    at java.lang.Thread.run(Thread.java:745)


Hier loop ik vast. Van wat ik heb kunnen googelen ligt het mogelijk aan een jar die dubbel is, een class die in meerdere jars zit (SslContextFactory or ClassRealm?) of meerdere classloaders die dezelfde class proberen te laden? Ik heb geen dubbele jars kunnen vinden, en weet niet waar ik verder moet zoeken.

Is er iemand die mij hier mee kan helpen?

Mvg,
Skandalouz

Alle reacties


Acties:
  • 0 Henk 'm!

  • Sircuri
  • Registratie: Oktober 2001
  • Niet online

Sircuri

Volledig Appelig

Classloaders die dezelfde class laden is niet erg. Het probleem ontstaat wanneer om een of andere reden de geladen class uit de andere classloader wordt gebruikt.

Dit is normaal alleen van toepassing in applicaties die tijdens runtime nieuwe classes inladen in verschillende classloaders. Eenvoudige applicaties zul je dit probleem dus ook niet gauw aantreffen, omdat die slechts 1 classloader gebruiker.

Voorbeeld:

Alle code uit package "a" wordt geladen door ClassLoader A en alles uit package "b" door ClassLoader B.

code:
1
2
3
4
5
6
7
8
9
package a;

public interface IBaseObject {}

public class BaseObjectImpl extends b.BaseObject {}

package b;

public class BaseObject implements a.IBaseObect {}


Hierboven gaat het fout op het moment dat de runtime het object BaseObjectImpl wil gaan laden. BaseObject uit package "b" heeft namelijk ook de IBaseObject interface geladen in zijn eigen classloader. Op dat moment zit er dus in classloader A een geladen interface IBaseObject, maar ook in ClassLoader B. Bij het laden van class BaseObjectImpl komt de classloader een IBaseObject interface tegen uit een andere classloader terwijl hij die zelf ook al geladen had.
Op dat moment heb je dus die violation.

Signature van nature


Acties:
  • +1 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
Je probeert nu SslContextFactory 2x te laden binnen dezelfde hiërarchie, en dat kan niet. Met de JVM optie -verbose:class kun je zien wanneer de eerste keer was (en uit welke 2 jars).

Ik gok dat het door die AutoWired komt. Gezien dit berichtje van iemand die iets dergelijks heeft met Spring:
Thanks for your research! I may add, that due to my own singleton implementation of the factory, the FormulaKey class seemed to have been loaded when starting the app and then again by the @Autowire annotation. By moving the singleton initialization to Spring (and the classloading), the problem seemed to be solved because Spring could take care of all classloading.
Ik gok dat die Autowired plaatsvind voordat Jetty zelf aan de beurt is. Het laden van IDiscordClient exposed dan onterecht een andere versie van Jetty's SslContextFactory. En vervolgens kan Jetty zijn eigen SslContextFactory niet meer krijgen.

Mogelijke oplossing: aan maven vertellen dat jetty provided als scope heeft als je op jetty draait. Kan achteraf denk ik met een exclusion. Iets als:
XML:
1
2
3
4
5
6
7
8
9
10
11
<dependency>
    <groupId>com.github.austinv11</groupId>
    <artifactId>Discord4j</artifactId>
    <version>2.6.1</version>
    <exclusions>
        <exclusion>
          <groupId>org.eclipse.jetty.websocket</groupId>
          <artifactId>websocket-client</artifactId>
        </exclusion>
    </exclusions> 
</dependency>

(sbt heeft hier iets moois voor dat maven mist, namelijk ExclusionRule)

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • skandalouz
  • Registratie: Oktober 2010
  • Laatst online: 26-05 20:32
Excuus voor de late reactie. Ik heb de gesuggereerde oplossingen geprobeerd. Als ik de exclusion toevoeg, ook met

XML: bot/pom.xml
1
2
3
4
5
6
<dependency>
    <groupId>org.eclipse.jetty.websocket</groupId>
    <artifactId>websocket-client</artifactId>
    <version>9.3.11.v20160721</version>
    <scope>provided</scope>
</dependency>


krijg ik de error dat de class niet gevonden kan worden:

Java:
1
2
3
4
5
Caused by: java.lang.ClassNotFoundException: org.eclipse.jetty.util.ssl.SslContextFactory
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at org.eclipse.jetty.webapp.WebAppClassLoader.findClass(WebAppClassLoader.java:549)
    at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:475)
    at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:428)


Er lijkt geen andere dependency voor die jetty class aanwezig als ik mvn depedency:tree uitvoer.

Ook als ik de Autowired weghaal wordt de LinkageError gegooid zodra de Discord client probeert in te loggen. Ik zal -verbose:class morgen proberen om te zien wat daar uitkomt.

[ Voor 24% gewijzigd door skandalouz op 19-10-2016 03:57 ]


Acties:
  • 0 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
Hmm, dat is gek. Is die class nu wel of niet al aanwezig en zo ja in welke jars? Ik zie dat die jetty plugin nog wat dingen heeft waaronder useProvidedScope, misschien kun je daar wat mee spelen. Daarnaast kun je met -verbose:class debuggen wat er nu gebeurd (morgen is vandaag ;)).

Als last resort is er ook nog maven shade.

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • skandalouz
  • Registratie: Oktober 2010
  • Laatst online: 26-05 20:32
Voor de volledigheid. De class is aanwezig, maar wat ik uit de mvn dependency:tree haal is dat ie alleen in de discord4j jar zit. Dat is ieder geval waar de package org.eclipse.jetty.websocket:websocket-client:jar:9.3.11.v20160721:compile in zit.

Ik heb de applicatie gedraaid om het classloading te checken en als ik de discord bot niet laat inloggen word de SslContextFactory niet geladen. Als ik wel login doe is het resultaat het volgende (dit zijn alle SslContextFactory loads):
XML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
17966 [Loaded org.eclipse.jetty.util.ssl.SslContextFactory from file:/C:/Users/henkk/.m2/repository/org/eclipse/jetty/jetty-util/9.3.11.v20160721/jetty-util-9.3.11.v20160721.jar]
17969 [Loaded org.eclipse.jetty.util.ssl.SslContextFactory$1 from file:/C:/Users/henkk/.m2/repository/org/eclipse/jetty/jetty-util/9.3.11.v20160721/jetty-util-9.3.11.v20160721.jar]
18172 [Loaded org.eclipse.jetty.util.ssl.SslContextFactory from file:/C:/Users/henkk/.m2/repository/org/eclipse/jetty/jetty-util/9.3.11.v20160721/jetty-util-9.3.11.v20160721.jar]
23:30:49.659: [ERROR][WebSocketClient@343845012-36][sx.blah.discord.Discord4J] - Websocket error, disconnecting...
java.lang.LinkageError: loader constraint violation: loader (instance of org/codehaus/plexus/classworlds/realm/ClassRealm) previously initiated loading for a different type with name "org/eclipse/jetty/util/ssl/SslContextFactory"
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:760)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
    at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClassFromSelf(ClassRealm.java:401)
    at org.codehaus.plexus.classworlds.strategy.SelfFirstStrategy.loadClass(SelfFirstStrategy.java:42)
    at org.codehaus.plexus.classworlds.realm.ClassRealm.unsynchronizedLoadClass(ClassRealm.java:271)
    at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClass(ClassRealm.java:247)
    at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClass(ClassRealm.java:239)
    at org.eclipse.jetty.websocket.client.io.WebSocketClientSelectorManager.newSSLEngine(WebSocketClientSelectorManager.java:129)
    at org.eclipse.jetty.websocket.client.io.WebSocketClientSelectorManager.newConnection(WebSocketClientSelectorManager.java:86)
    [...]


Dit is een vrij interessant probleem, maar ik heb andere Discord clients geprobeerd en die geven geen problemen. Omdat ik nog een ander framework gebruik zijn de clients in mijn applicatie redelijk inwisselbaar en mijn oplossing op dit moment is dus Discord4J inruilen voor een ander. Mocht iemand nog interesse hebben in dit probleem dan wil ik best op verder onderzoek uit gaan overigens.
Pagina: 1