Estou recebendo um NoClassDefFoundError
quando executo meu aplicativo Java. Qual é tipicamente a causa disso?
Estou recebendo um NoClassDefFoundError
quando executo meu aplicativo Java. Qual é tipicamente a causa disso?
Respostas:
Isso é causado quando há um arquivo de classe do qual seu código depende e está presente no tempo de compilação, mas não encontrado no tempo de execução. Procure diferenças no tempo de construção e nos caminhos de classe do tempo de execução.
Embora seja possível que isso ocorra devido a uma incompatibilidade de caminho de classe entre o tempo de compilação e o tempo de execução, isso não é necessariamente verdade.
É importante manter duas ou três exceções diferentes em mente neste caso:
java.lang.ClassNotFoundException
Essa exceção indica que a classe não foi encontrada no caminho de classe. Isso indica que estávamos tentando carregar a definição de classe e a classe não existia no caminho de classe.
java.lang.NoClassDefFoundError
Essa exceção indica que a JVM procurou em sua estrutura de dados de definição de classe interna a definição de uma classe e não a encontrou. Isso é diferente de dizer que não foi possível carregar o caminho de classe. Normalmente, isso indica que anteriormente tentamos carregar uma classe do caminho de classe, mas ela falhou por algum motivo - agora estamos tentando usar a classe novamente (e, portanto, precisamos carregá-la, pois ela falhou da última vez), mas nós ' nem vamos tentar carregá-lo, porque falhamos ao carregá-lo mais cedo (e suspeitamos razoavelmente que falharíamos novamente). A falha anterior pode ser um ClassNotFoundException ou um ExceptionInInitializerError (indicando uma falha no bloco de inicialização estática) ou qualquer número de outros problemas. O ponto é que um NoClassDefFoundError não é necessariamente um problema de caminho de classe.
Error: Could not find or load main class
, ele será classificado em qual categoria de erro?
Aqui está o código para ilustrar java.lang.NoClassDefFoundError
. Por favor, veja a resposta de Jared para uma explicação detalhada.
NoClassDefFoundErrorDemo.java
public class NoClassDefFoundErrorDemo {
public static void main(String[] args) {
try {
// The following line would throw ExceptionInInitializerError
SimpleCalculator calculator1 = new SimpleCalculator();
} catch (Throwable t) {
System.out.println(t);
}
// The following line would cause NoClassDefFoundError
SimpleCalculator calculator2 = new SimpleCalculator();
}
}
SimpleCalculator.java
public class SimpleCalculator {
static int undefined = 1 / 0;
}
SimpleCalculator
após a divisão por zero? Alguém tem uma referência à documentação oficial para esse comportamento?
new SimpleCalculator()
você chama, você obtém um ExceptionInInitializerError causado por ArithmeticException. Na segunda vez que você liga, new SimpleCalculator()
você obtém um NoClassDefFoundError tão puro quanto qualquer outro. O ponto é que você pode obter um NoClassDefFoundError por um motivo diferente de SimpleCalculator.class que não esteja no caminho de classe no tempo de execução.
NoClassDefFoundError em Java
Definição:
O Java Virtual Machine não consegue encontrar uma classe específica em tempo de execução que estava disponível no momento da compilação.
Se uma classe estava presente durante o tempo de compilação, mas não estava disponível no caminho de classe java durante o tempo de execução.
Exemplos:
Um exemplo simples de NoClassDefFoundError is class pertence a um arquivo JAR ausente ou o JAR não foi adicionado ao caminho de classe ou, às vezes, o nome do jar foi alterado por alguém como no meu caso, um dos meus colegas alterou tibco.jar para tibco_v3.jar e o programa é falhando com java.lang.NoClassDefFoundError e eu queria saber o que há de errado.
Apenas tente executar com a opção explicitamente -classpath com o caminho de classe que você acha que funcionará e, se estiver funcionando, é um pequeno sinal claro de que alguém está substituindo o caminho de classe java.
Soluções possíveis:
Recursos:
Descobri que às vezes recebo um erro NoClassDefFound quando o código é compilado com uma versão incompatível da classe encontrada no tempo de execução. A instância específica que me lembro é da biblioteca de eixos apache. Na verdade, havia duas versões no meu caminho de classe em tempo de execução e ele pegava a versão desatualizada e incompatível e não a correta, causando um erro NoClassDefFound. Isso estava em um aplicativo de linha de comando em que eu estava usando um comando semelhante a este.
set classpath=%classpath%;axis.jar
Consegui fazê-lo pegar a versão correta usando:
set classpath=axis.jar;%classpath%;
Esta é a melhor solução que encontrei até agora.
Suponha que tenhamos um pacote chamado org.mypackage
contendo as classes:
e os arquivos que definem este pacote são armazenados fisicamente no diretório D:\myprogram
(no Windows) ou /home/user/myprogram
(no Linux).
A estrutura do arquivo ficará assim:
Quando invocamos Java, que especifique o nome do aplicativo para executar: org.mypackage.HelloWorld
. No entanto, também devemos informar ao Java onde procurar os arquivos e diretórios que definem nosso pacote. Então, para iniciar o programa, precisamos usar o seguinte comando:
Eu estava usando o Spring Framework com o Maven e resolvi esse erro no meu projeto.
Houve um erro de tempo de execução na classe. Eu estava lendo uma propriedade como número inteiro, mas quando leu o valor do arquivo de propriedades, seu valor foi duplo.
O Spring não me deu um rastreamento completo da pilha em qual linha o tempo de execução falhou. Simplesmente disse NoClassDefFoundError
. Mas quando eu o executei como um aplicativo Java nativo (removendo-o do MVC), ele forneceu ExceptionInInitializerError
qual era a causa verdadeira e qual foi a maneira como eu rastreei o erro.
A resposta da @ xli me deu uma ideia do que pode estar errado no meu código.
NoClassDefFoundError
na verdade, foi causado por ExceptionInInitalizerError
, o que foi causado por DateTimeParseException
). É um pouco enganador, não é? Eu sei que eles provavelmente tiveram suas razões para fazer dessa maneira, mas seria muito bom ter pelo menos uma pequena dica, que NoClassDefFoundError
foi o resultado de outra exceção, sem a necessidade de deduzi-la. Apenas jogar de ExceptionInInitializerError
novo seria muito mais claro. Às vezes, a conexão entre os dois pode não ser tão óbvia.
Recebo NoClassFoundError quando as classes carregadas pelo carregador de classes de tempo de execução não podem acessar as classes já carregadas pelo java rootloader. Como os diferentes carregadores de classes estão em domínios de segurança diferentes (de acordo com java), a jvm não permitirá que as classes já carregadas pelo rootloader sejam resolvidas no espaço de endereço do carregador de tempo de execução.
Execute seu programa com 'java -javaagent: tracer.jar [YOUR java ARGS]'
Produz saída mostrando a classe carregada e o env do carregador que carregou a classe. É muito útil rastrear por que uma classe não pode ser resolvida.
// ClassLoaderTracer.java
// From: https://blogs.oracle.com/sundararajan/entry/tracing_class_loading_1_5
import java.lang.instrument.*;
import java.security.*;
// manifest.mf
// Premain-Class: ClassLoadTracer
// jar -cvfm tracer.jar manifest.mf ClassLoaderTracer.class
// java -javaagent:tracer.jar [...]
public class ClassLoadTracer
{
public static void premain(String agentArgs, Instrumentation inst)
{
final java.io.PrintStream out = System.out;
inst.addTransformer(new ClassFileTransformer() {
public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
String pd = (null == protectionDomain) ? "null" : protectionDomain.getCodeSource().toString();
out.println(className + " loaded by " + loader + " at " + new java.util.Date() + " in " + pd);
// dump stack trace of the thread loading class
Thread.dumpStack();
// we just want the original .class bytes to be loaded!
// we are not instrumenting it...
return null;
}
});
}
}
Um caso interessante no qual você pode ver muitos NoClassDefFoundErrors
é quando:
throw
um RuntimeException
no static
bloco da sua turmaExample
Example
static class Example {
static {
thisThrowsRuntimeException();
}
}
static class OuterClazz {
OuterClazz() {
try {
new Example();
} catch (Throwable ignored) { //simulating catching RuntimeException from static block
// DO NOT DO THIS IN PRODUCTION CODE, THIS IS JUST AN EXAMPLE in StackOverflow
}
new Example(); //this throws NoClassDefFoundError
}
}
NoClassDefError
será lançado acompanhado ExceptionInInitializerError
pelo bloco estático RuntimeException
.
Este é um caso especialmente importante quando você vê NoClassDefFoundErrors
seus TESTES UNITÁRIOS .
De certa forma, você está "compartilhando" a static
execução do bloco entre os testes, mas a inicial ExceptionInInitializerError
será apenas em um caso de teste. O primeiro que usa a Example
classe problemática . Outros casos de teste que usam a Example
classe serão lançados NoClassDefFoundErrors
.
A técnica abaixo me ajudou muitas vezes:
System.out.println(TheNoDefFoundClass.class.getProtectionDomain().getCodeSource().getLocation());
onde TheNoDefFoundClass é a classe que pode ser "perdida" devido a uma preferência por uma versão mais antiga da mesma biblioteca usada pelo seu programa. Isso ocorre com mais freqüência nos casos em que o software cliente está sendo implantado em um contêiner dominante, armado com seus próprios carregadores de classes e toneladas de versões antigas das bibliotecas mais populares.
Caso você tenha gerado código (EMF, etc.), pode haver muitos inicializadores estáticos que consomem todo o espaço da pilha.
Consulte a pergunta Estouro de pilha Como aumentar o tamanho da pilha Java? .
NoClassDefFoundError
também pode ocorrer quando um inicializador estático tenta carregar um pacote configurável de recursos que não está disponível em tempo de execução, por exemplo, um arquivo de propriedades que a classe afetada tenta carregar do META-INF
diretório, mas não existe. Se você não capturar NoClassDefFoundError
, às vezes não poderá ver o rastreamento completo da pilha; Para superar isso, você pode usar temporariamente uma catch
cláusula para Throwable
:
try {
// Statement(s) that cause the affected class to be loaded
} catch (Throwable t) {
Logger.getLogger("<logger-name>").info("Loading my class went wrong", t);
}
for example a properties file that the affected class tries to load from the META-INF directory
. Isso realmente aconteceu comigo e eu pude resolver isso NoClassDefFoundError
adicionando o arquivo de propriedades que estava faltando. Eu adicionei esta resposta exatamente porque não se esperaria esse erro nas circunstâncias mencionadas.
static
inicialização ... o que acionou uma exceção não verificada e causou a classe init falhar. Qualquer exceção desmarcada propagada da inicialização estática faria isso.
static
inicialização), eu estaria interessado em ver um exemplo real (isto é, um MCVE) que demonstra o comportamento.
Eu recebi esse erro ao adicionar a dependência do Maven de outro módulo ao meu projeto, o problema foi finalmente resolvido com a adição -Xss2m
da opção JVM do meu programa (é um megabyte por padrão desde o JDK5.0). Acredita-se que o programa não tenha pilha suficiente para carregar a classe.
Se alguém vier aqui por causa de java.lang.NoClassDefFoundError: org/apache/log4j/Logger
erro, no meu caso, foi produzido porque usei o log4j 2 (mas não adicionei todos os arquivos que o acompanham) e alguma biblioteca de dependência utilizou o log4j 1. A solução foi adicionar o Log4j 1.x bridge: o jar log4j-1.2-api-<version>.jar
que acompanha o log4j 2. Mais informações na migração do log4j 2 .
No meu caso, o problema era a incapacidade do Eclipse de diferenciar entre duas cópias diferentes do mesmo projeto. Eu tenho um bloqueado no tronco (controle de versão SVN) e o outro trabalhando em uma ramificação por vez. Tentei uma alteração na cópia de trabalho como um caso de teste JUnit, que incluía extrair uma classe interna privada para ser uma classe pública por conta própria e enquanto ele estava funcionando, abro a outra cópia do projeto para procurar outras parte do código que precisava de alterações. Em algum momento, o grupo NoClassDefFoundError
apareceu reclamando que a classe interna privada não estava lá; clicar duas vezes no rastreamento da pilha levou-me ao arquivo de origem na cópia incorreta do projeto.
Fechar a cópia de tronco do projeto e executar o caso de teste novamente se livrou do problema.
Este erro pode ser causado por requisitos de versão Java não verificados .
No meu caso, consegui resolver esse erro, ao criar um projeto de código aberto de alto perfil, alternando do Java 9 para o Java 8 usando o SDKMAN! .
sdk list java
sdk install java 8u152-zulu
sdk use java 8u152-zulu
Em seguida, faça uma instalação limpa, conforme descrito abaixo.
Ao usar o Maven como sua ferramenta de criação, às vezes é útil - e geralmente gratificante, fazer uma compilação limpa de 'instalação' com o teste desativado .
mvn clean install -DskipTests
Agora que tudo foi construído e instalado, você pode prosseguir e executar os testes.
mvn test
Eu recebi erros NoClassDefFound quando não exportei uma classe na guia "Ordem e exportação" no caminho de compilação Java do meu projeto. Certifique-se de marcar a guia "Ordem e exportação" de todas as dependências adicionadas ao caminho de criação do projeto. Consulte Aviso do Eclipse: XXXXXXXXXXX.jar não será exportado ou publicado. O tempo de execução ClassNotFoundExceptions pode resultar .
No meu caso, eu estava recebendo esse erro devido a uma incompatibilidade nas versões do JDK. Quando tentei executar o aplicativo da Intelij, ele não estava funcionando, mas funcionou na linha de comando. Isso ocorre porque o Intelij estava tentando executá-lo com o Java 11 JDK que estava configurado, mas na linha de comando estava em execução com o Java 8 JDK. Depois de alternar essa configuração em Arquivo> Estrutura do projeto> Configurações do projeto> SDK do projeto, funcionou para mim.
Todo mundo fala aqui sobre algumas coisas de configuração Java, problemas de JVM etc., no meu caso, o erro não estava relacionado a esses tópicos e tinha uma razão muito trivial e fácil de resolver: eu tinha uma anotação errada no meu endpoint no meu Controller ( Aplicativo Spring Boot).
Eu tive um problema interessante com o NoClassDefFoundError no JavaEE, trabalhando com o servidor Liberty. Eu estava usando adaptadores de recursos IMS e meu server.xml já tinha um adaptador de recursos para imsudbJXA.rar. Quando adicionei um novo adaptador para imsudbXA.rar, eu começava a receber esse erro para objetos de instância para DLIException, IMSConnectionSpec ou SQLInteractionSpec. Não consegui entender o motivo, mas resolvi criando um novo server.xml para o meu trabalho usando apenas imsudbXA.rar. Estou certo de que o uso de vários adaptadores de recursos no server.xml é bom, mas não tive tempo de analisar isso.
Java não conseguiu encontrar a classe A em tempo de execução. A Classe A estava no projeto ArtClient de um novo espaço de trabalho. Portanto, importei o ArtClient para o meu projeto Eclipse. Dois dos meus projetos estavam usando o ArtClient como dependência. Alterei a referência da biblioteca para a referência do projeto para esses (Build Path -> Configure Build Path).
E o problema foi embora.
Eu tive o mesmo problema e fiquei em estoque por muitas horas.
Eu encontrei a solução. No meu caso, havia o método estático definido devido a isso. A JVM não pode criar o outro objeto dessa classe.
Por exemplo,
private static HttpHost proxy = new HttpHost(proxyHost, Integer.valueOf(proxyPort), "http");
Recebi essa mensagem depois de remover dois arquivos da biblioteca SRC e, quando os trouxe de volta, continuei vendo essa mensagem de erro.
Minha solução foi: Reinicie o Eclipse. Desde então, eu não vi essa mensagem novamente :-)
Verifique se isso corresponde ao module:app
e module:lib
:
android {
compileSdkVersion 23
buildToolsVersion '22.0.1'
packagingOptions {
}
defaultConfig {
minSdkVersion 17
targetSdkVersion 23
versionCode 11
versionName "2.1"
}
{s
e dois }
). Consegues consertar isso?