Estou empacotando uma biblioteca Java como um JAR, e está lançando muitos java.lang.IncompatibleClassChangeError
s quando tento invocar métodos a partir dela. Esses erros parecem aparecer aleatoriamente. Que tipos de problemas podem estar causando esse erro?
218
Respostas:
Isso significa que você fez algumas alterações binárias incompatíveis na biblioteca sem recompilar o código do cliente. A Especificação da Linguagem Java §13 detalha todas essas alterações, principalmente, alterando
static
campos / métodos não privados para seremstatic
ou vice-versa.Recompile o código do cliente com a nova biblioteca e você deve estar pronto.
ATUALIZAÇÃO: Se você publicar uma biblioteca pública, evite fazer alterações binárias incompatíveis o máximo possível para preservar o que é conhecido como "compatibilidade com versões anteriores binárias". Atualizar os jars de dependência sozinho, idealmente, não deve interromper o aplicativo ou a compilação. Se você precisar interromper a compatibilidade binária com versões anteriores, é recomendável aumentar o número da versão principal (por exemplo, de 1.xy para 2.0.0) antes de liberar a alteração.
fonte
*.class
arquivos) e recompilar? Arquivos de edição têm efeito semelhante.Sua biblioteca recém-empacotada não é compatível com binários anteriores (BC) com a versão antiga. Por esse motivo, alguns dos clientes da biblioteca que não são recompilados podem lançar a exceção.
Este é um completo lista das alterações na API da biblioteca Java que podem fazer com que os clientes criados com uma versão antiga da biblioteca atinjam java.lang. IncompatibleClassChangeError se eles rodarem em um novo (por exemplo, quebrando o BC):
Nota : Existem muitas outras exceções causadas por outras alterações incompatíveis: NoSuchFieldError , NoSuchMethodError , IllegalAccessError , InstantiationError , VerifyError , NoClassDefFoundError e AbstractMethodError .
O melhor artigo sobre BC é "Evoluindo APIs baseadas em Java 2: Atingindo a compatibilidade binária da API" escrito por Jim des Rivières.
Existem também algumas ferramentas automáticas para detectar essas alterações:
Uso do japi-compliance-checker na sua biblioteca:
Uso da ferramenta clirr:
Boa sorte!
fonte
Embora todas essas respostas estejam corretas, resolver o problema geralmente é mais difícil. Geralmente, é o resultado de duas versões ligeiramente diferentes da mesma dependência no caminho de classe e quase sempre é causada por uma superclasse diferente do que foi originalmente compilado contra estar no caminho de classe ou por alguma importação do fechamento transitivo ser diferente, mas geralmente na classe instanciação e invocação de construtor. (Após o carregamento bem-sucedido da classe e a chamada do ctor, você receberá
NoSuchMethodException
ou não.)Se o comportamento parecer aleatório, é provável que o resultado de um programa multithread carregue diferentes dependências transitivas com base em qual código foi atingido primeiro.
Para resolvê-los, tente iniciar a VM
-verbose
como argumento e observe as classes que estavam sendo carregadas quando a exceção ocorre. Você deve ver algumas informações surpreendentes. Por exemplo, ter várias cópias da mesma dependência e versões que você nunca esperava ou aceitaria se soubesse que elas estavam sendo incluídas.A resolução de jarros duplicados com o Maven é melhor feita com uma combinação do maven-dependency-plugin e do maven-enforcer-plugin no Maven (ou no Dependency Graph Plugin do SBT , adicionando esses jars a uma seção do seu POM de nível superior ou como dependência importada elementos no SBT (para remover essas dependências).
Boa sorte!
fonte
Também descobri que, ao usar JNI, invocando um método Java do C ++, se você passar parâmetros para o método Java invocado na ordem errada, você receberá esse erro ao tentar usar os parâmetros dentro do método chamado (porque eles não será do tipo certo). Inicialmente, fiquei surpreso que o JNI não faça essa verificação para você como parte da verificação de assinatura de classe quando você invoca o método, mas presumo que eles não fazem esse tipo de verificação porque você pode estar passando parâmetros polimórficos e eles precisam suponha que você saiba o que está fazendo.
Exemplo de código JNI C ++:
Código Java de exemplo:
fonte
Eu tive o mesmo problema e, mais tarde, descobri que estou executando o aplicativo no Java versão 1.4 enquanto o aplicativo é compilado na versão 6.Na verdade, o motivo foi ter uma biblioteca duplicada, uma localizada no caminho de classe e a outra incluída em um arquivo jar localizado no caminho de classe.
fonte
Outra situação em que esse erro pode aparecer é com a Emma Code Coverage.
Isso acontece ao atribuir um objeto a uma interface. Eu acho que isso tem algo a ver com o objeto sendo instrumentado e não é mais compatível com binário.
http://sourceforge.net/tracker/?func=detail&aid=3178921&group_id=177969&atid=883351
Felizmente, esse problema não ocorre com o Cobertura, então eu adicionei o cobertura-maven-plugin nos meus plugins de relatórios do meu pom.xml
fonte
Eu enfrentei esse problema ao remover e reimplementar uma guerra com o glassfish. Minha estrutura de classe era assim,
e foi alterado para
Depois de parar e reiniciar o domínio, funcionou bem. Eu estava usando o glassfish 3.1.43
fonte
Eu tenho um aplicativo da Web que implanta perfeitamente no tomcat da minha máquina local (8.0.20). No entanto, quando o coloquei no ambiente qa (tomcat - 8.0.20), ele continuou fornecendo o IncompatibleClassChangeError e estava reclamando que eu estava estendendo uma interface. Essa interface foi alterada para uma classe abstrata. E eu compilei as classes pai e filho e continuava recebendo o mesmo problema. Finalmente, eu queria depurar, então mudei a versão no pai para x.0.1-SNAPSHOT e compilei tudo, e agora está funcionando. Se alguém ainda estiver enfrentando o problema após seguir as respostas fornecidas aqui, verifique se as versões do pom.xml também estão corretas. Mude as versões para ver se isso funciona. Nesse caso, corrija o problema da versão.
fonte
Acredito que minha resposta seja específica da Intellij.
Eu havia reconstruído o clean, chegando a excluir manualmente os diretórios "out" e "target". O Intellij possui um "invalidar caches e reiniciar", que às vezes limpa erros estranhos. Desta vez não funcionou. Todas as versões de dependência pareciam corretas no menu Configurações do Projeto -> Módulos.
A resposta final foi excluir manualmente minha dependência do problema do meu repo maven local. Uma versão antiga do bouncycastle era a culpada (eu sabia que tinha acabado de alterar as versões e esse seria o problema) e, embora a versão antiga não aparecesse onde estava sendo construído, resolveu o meu problema. Eu estava usando a versão 14 do intellij e, em seguida, atualizei para 15 durante esse processo.
fonte
No meu caso, encontrei esse erro dessa maneira.
pom.xml
do meu projeto definiu duas dependênciasA
eB
. E ambosA
eB
dependência definida no mesmo artefato (chame-oC
), mas em versões diferentes (C.1
eC.2
). Quando isso acontece, para cada classe noC
maven, só é possível selecionar uma versão da classe entre as duas versões (durante a construção de um uber-jar ). Ele selecionará a versão "mais próxima" com base em suas regras de mediação de dependência e emitirá um aviso "Temos uma classe duplicada ..." Se uma assinatura de método / classe for alterada entre as versões, poderá causar umajava.lang.IncompatibleClassChangeError
exceção se a versão incorreta for usado em tempo de execução.Avançado: Se
A
deve usar v1 deC
eB
deve usar v2 deC
, então devemos mudarC
emA
eB
's poms para conflito de classes evitar (temos uma advertência classe duplicado) ao construir o projeto final que depende tantoA
eB
.fonte
No meu caso, o erro apareceu quando adicionei a
com.nimbusds
biblioteca no meu aplicativo implantadoWebsphere 8.5
.Ocorreu a exceção abaixo:
A solução foi excluir o jar asm da biblioteca:
fonte
Verifique se o seu código não consiste em dois projetos de módulo que possuem os mesmos nomes de classes e definição de pacotes. Por exemplo, isso poderia acontecer se alguém usasse copiar e colar para criar uma nova implementação de interface com base na implementação anterior.
fonte
Se este é um registro de possíveis ocorrências desse erro, então:
Acabei de receber esse erro no WAS (8.5.0.1), durante o carregamento do CXF (2.6.0) da configuração de primavera (3.1.1_release) em que um BeanInstantiationException acumulou um CXF ExtensionException, acumulando um IncompatibleClassChangeError. O seguinte trecho mostra a essência do rastreamento de pilha:
Nesse caso, a solução foi alterar a ordem do caminho de classe do módulo no meu arquivo war. Ou seja, abra o aplicativo war no console do WAS e selecione o (s) módulo (s) do cliente. Na configuração do módulo, defina o carregamento da classe como "último pai".
Isso é encontrado no console do WAS:
fonte
Documentar outro cenário depois de gastar muito tempo.
Verifique se você não possui um jar de dependência com uma classe com uma anotação EJB.
Tínhamos um arquivo jar comum que tinha uma
@local
anotação. Mais tarde, essa classe foi removida desse projeto comum para o nosso projeto principal do ejb jar. Nosso jarro ejb e nosso jarro comum estão ambos dentro do ouvido. A versão da nossa dependência de jar comum não foi atualizada. Assim, 2 classes tentando ser algo com alterações incompatíveis.fonte
Tudo isso - por qualquer motivo, eu estava fazendo um grande refator e começando a entender isso. Renomeei o pacote em que minha interface estava e isso foi liberado. Espero que ajude.
fonte
Por alguma razão, a mesma exceção também é lançada ao usar JNI e transmitir o argumento jclass em vez do jobject ao chamar a
Call*Method()
.Isso é semelhante à resposta do Ogre Salmo33.
Sei que é um pouco tarde para responder a essa pergunta cinco anos depois de ser perguntado, mas esse é um dos principais hits ao pesquisar,
java.lang.IncompatibleClassChangeError
então eu queria documentar esse caso especial.fonte
Se você estiver usando scala e sbt e scala-logging como dependência; isso pode acontecer porque a versão anterior do scala-logging tinha o nome scala-logging-api.So; essencialmente, as resoluções de dependência não acontecem devido a diferentes nomes que levam a erros de tempo de execução ao iniciar o aplicativo scala.
fonte
Uma causa adicional desse problema é se você
Instant Run
ativou o Android Studio.O conserto
Se você começar a receber esse erro, desative
Instant Run
.Por quê
Instant Run
modifica um grande número de coisas durante o desenvolvimento, para agilizar o fornecimento de atualizações para o aplicativo em execução. Daí a execução instantânea. Quando funciona, é realmente útil. No entanto, quando ocorre um problema como esse, a melhor coisa a fazer é desativarInstant Run
até a próxima versão do Android Studio.fonte