Pergunta

O desenvolvimento de um Java aplicação fortemente baseada em XML, recentemente encontrou um problema interessante no Ubuntu Linux.

Meu aplicativo, usando o Java Plugin Framework, parece incapaz de converter um dom4j -Criado documento XML para Batik de implementação da especificação SVG.

No console, eu aprendo que um erro ocorre:

Exception in thread "AWT-EventQueue-0" java.lang.LinkageError: loader constraint violation in interface itable initialization: when resolving method "org.apache.batik.dom.svg.SVGOMDocument.createAttribute(Ljava/lang/String;)Lorg/w3c/dom/Attr;" the class loader (instance of org/java/plugin/standard/StandardPluginClassLoader) of the current class, org/apache/batik/dom/svg/SVGOMDocument, and the class loader (instance of <bootloader>) for interface org/w3c/dom/Document have different Class objects for the type org/w3c/dom/Attr used in the signature
    at org.apache.batik.dom.svg.SVGDOMImplementation.createDocument(SVGDOMImplementation.java:149)
    at org.dom4j.io.DOMWriter.createDomDocument(DOMWriter.java:361)
    at org.dom4j.io.DOMWriter.write(DOMWriter.java:138)

I figura que o problema é causado por um conflito entre o carregador de classe original a partir do JVM e o carregador de classe implantado pelo quadro plugin.

A meu conhecimento, não é possível especificar um carregador de classe para o quadro para uso. Pode ser possível cortá-lo, mas eu preferiria uma abordagem menos agressiva para resolver este problema, uma vez que (por qualquer motivo) só ocorre em sistemas Linux.

Tem um de vocês encontrou um problema e tem alguma idéia de como corrigi-lo ou, pelo menos, chegar ao cerne da questão?

Foi útil?

Solução

LinkageError é o que você vai entrar em um caso clássico onde você tem uma classe C carregado por mais de um carregador de classe e as classes estão sendo usados ??juntos no mesmo código (em comparação, elenco, etc). Não importa se é o mesmo nome da classe ou mesmo se ele é carregado a partir do frasco idêntico -. Uma classe de um carregador de classe é sempre tratada como uma classe diferente se carregado de outro carregador de classe

A mensagem (que melhorou muito ao longo dos anos) diz:

Exception in thread "AWT-EventQueue-0" java.lang.LinkageError: 
loader constraint violation in interface itable initialization: 
when resolving method "org.apache.batik.dom.svg.SVGOMDocument.createAttribute(Ljava/lang/String;)Lorg/w3c/dom/Attr;" 
the class loader (instance of org/java/plugin/standard/StandardPluginClassLoader) 
of the current class, org/apache/batik/dom/svg/SVGOMDocument, 
and the class loader (instance of ) for interface org/w3c/dom/Document 
have different Class objects for the type org/w3c/dom/Attr used in the signature

Então, aqui o problema é para resolver o método SVGOMDocument.createAttribute (), que usa org.w3c.dom.Attr (parte da biblioteca padrão DOM). Mas, a versão do Attr carregado com Batik foi carregado a partir de um carregador de classe diferente do que a instância de Attr você está passando para o método.

Você verá que a versão de Batik parece ser carregado a partir do plug-in Java. E seu está sendo carregado a partir de "", que é provavelmente um dos utilitários de carga JVM (classpath de inicialização, ESOM, ou classpath).

Os três modelos classloader proeminentes são:

  • delegação (o padrão no JDK - peça pai, então me)
  • pós-delegação (comum em plugins, servlets, e lugares onde você quer isolamento - pergunte-me, então controladora)
  • irmão (comum em modelos de dependência como OSGi, Eclipse, etc)

Eu não sei o que a delegação estratégia dos usos classloader JPF, mas a chave é que você quer uma versão da biblioteca dom para ser carregado e todos a fonte dessa classe a partir do mesmo local. Isso pode significar removê-lo do caminho de classe e carregamento como um plugin, ou prevenir Batik de carregá-lo, ou algo mais.

Outras dicas

soa como um problema hierarquia do carregador de classe. Eu não posso dizer que tipo de ambiente seu aplicativo é implantado, mas, por vezes, este problema pode ocorrer em um ambiente web - onde o servidor de aplicativos cria uma hierarquia de carregadores de classe, assemelhando-se algo como:

javahome / lib - como root
appserver / lib - como filho de raiz
webapp / WEB-INF / lib - como filho de filho de raiz
etc

Normalmente classloaders carregamento delegado ao seu carregador de classe pai (isto é conhecido como "parent-first"), e se esse carregador de classe não pode encontrar a classe, então as tentativas classloader criança para. Por exemplo, se uma classe implementado como um JAR em webapp / WEB-INF / tentativas lib para carregar uma classe, em primeiro lugar ele pede o carregador de classe correspondente ao appserver / lib para carregar a classe (que por sua vez solicita o carregador de classe correspondente ao javahome / lib para carregar a classe), e se essa pesquisa falhar, então WEB-INF / lib é procurado para uma partida para esta classe.

Em um ambiente web, você pode tiver problemas com esta hierarquia. Por exemplo, um erro / problema que eu tenho que correr para antes foi quando uma classe em WEB-INF / lib dependia de uma classe implantado em appserver / lib, que por sua vez dependia de uma classe implantado em WEB-INF / lib. Este falhas causadas porque enquanto classloaders são capazes de delegar ao carregador de classes pai, eles não podem delegar volta para baixo da árvore. Assim, o carregador de classe WEB-INF / lib pediria appserver / lib carregador de classe para uma classe, appserver / lib classloader iria carregar essa classe e tentar carregar a classe dependente, e falhar, uma vez que não poderia encontrar essa classe no appserver / lib ou javahome / lib.

Assim, quando você não pode ser implantando seu aplicativo em um ambiente de servidor web / app, o meu muito longa explicação pode se aplicar a você se o seu ambiente tem uma hierarquia de carregadores de classe criadas. Não é? JPF está fazendo algum tipo de magia carregador de classe para ser capaz de implementar as suas características plugin?

Pode ser isso vai ajudar alguém, porque ele funciona muito bem para mim. A questão pode ser resolver através da integração de suas próprias dependências. Siga esses passos simples

Primeiro verifique o erro que deve ser assim:

  • execução do método falhou:
  • java.lang.LinkageError: carregador de violação de restrição:
  • quando resolver método "org.slf4j.impl StaticLoggerBinder .getLoggerFactory () Lorg / slf4j / ILoggerFactory;".
  • o carregador de classe (instância de org / openmrs / módulo / ModuleClassLoader) da classe atual, org / slf4j / LoggerFactory ,
  • e o carregador de classe (instância de org / apache / Catalina / loader / WebappClassLoader) para a classe resolvido, org / slf4j / impl / StaticLoggerBinder ,
  • têm diferentes Classe objetos para o taticLoggerBinder.getLoggerFactory tipo () Lorg / slf4j / ILoggerFactory; utilizado na assinatura

  1. Veja a classe dois destacado. pesquisar no Google por eles como "jar StaticLoggerBinder.class de download" e "jar LoggeraFactory.class de download". Isto irá mostrar primeiro ou em alguns casos, segundo link (site é http://www.java2s.com ) que é um dos a versão frasco de ter incluído em seu projeto. Você pode inteligentemente identificá-lo a si mesmo, mas somos viciados do Google;)

  2. Depois que você vai saber o nome do arquivo jar, no meu caso, é como slf4j-log4j12-1.5.6.jar & slf4j-api-1.5.8

  3. Agora, a versão mais recente deste arquivo está disponível aqui http://mvnrepository.com/ (na verdade, toda a versão até à data, este é o local de onde Maven começar suas dependências).
  4. Agora adicione ambos arquivo como um dependências com a versão mais recente (ou manter tanto a versão do arquivo mesmo, a versão seja escolhido é de idade). A seguir é a dependência que você tem que incluir no pom.xml

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.7</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.7</version>
</dependency>

Como chegar ser dependente definição de Maven Site

Você pode especificar um carregador de classe? Se não, tente especificar o carregador de classe de contexto assim:

Thread thread = Thread.currentThread();
ClassLoader contextClassLoader = thread.getContextClassLoader();
try {
    thread.setContextClassLoader(yourClassLoader);
    callDom4j();
} finally {
    thread.setContextClassLoader(contextClassLoader);
}

Eu não estou familiarizado com o Java Plugin Framework, mas eu escrever código para Eclipse, e eu me deparo com problemas semelhantes ao longo do tempo. Eu não garanto que vai corrigi-lo, mas é provavelmente um tiro pena.

As respostas de Alex e Matt são muito úteis. Eu poderia beneficiar da sua análise também.

Eu tive o mesmo problema ao usar a biblioteca Batik num quadro Netbeans RCP, a biblioteca Batik ser incluído como uma "Biblioteca Wrapper Module". Se algumas outras módulo faz uso de APIs XML, e sem dependência de Batik é necessário e estabelecido para esse módulo, o carregador de classe problema violação de restrição surge com mensagens de erro semelhantes.

No NetBeans, módulos individuais usar carregadores de classe dedicados, ea relação de dependência entre os módulos implica encaminhamento delegação carregador de classe adequado.

Eu poderia resolver o problema simplesmente omitir a-apis xml arquivo jar do pacote biblioteca Batik.

Tal como especificado no esta pergunta , permitindo que o -verbose:class fará as informações de log JVM sobre todas as classes sendo carregado, o que pode ser extremamente útil para compreender onde as classes estão vindo em cenários e aplicações mais complexas.

A saída que você tem aparência mais ou menos assim (copiados de essa pergunta):

[Opened /usr/java/j2sdk1.4.1/jre/lib/rt.jar]
[Opened /usr/java/j2sdk1.4.1/jre/lib/sunrsasign.jar]
[Opened /usr/java/j2sdk1.4.1/jre/lib/jsse.jar]
[Opened /usr/java/j2sdk1.4.1/jre/lib/jce.jar]
[Opened /usr/java/j2sdk1.4.1/jre/lib/charsets.jar]
[Loaded java.lang.Object from /usr/java/j2sdk1.4.1/jre/lib/rt.jar]
[Loaded java.io.Serializable from /usr/java/j2sdk1.4.1/jre/lib/rt.jar]
[Loaded java.lang.Comparable from /usr/java/j2sdk1.4.1/jre/lib/rt.jar]
[Loaded java.lang.CharSequence from /usr/java/j2sdk1.4.1/jre/lib/rt.jar]
[Loaded java.lang.String from /usr/java/j2sdk1.4.1/jre/lib/rt.jar]
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top