java.lang.NoClassDefFoundError: Não foi possível inicializar a classe XXX

165
public class PropHolder {
  public static Properties prop;

  static {
    //code for loading properties from file
  }
}

// Referencing the class somewhere else:
Properties prop = PropHolder.prop;

class PropHolderé uma classe minha. A classe reside no mesmo arquivo JAR da classe principal. Portanto, isso não deve ocorrer porque algum JAR está ausente no caminho de classe.

Quando olho para o arquivo JAR jar tf myjarfile, posso ver os PropHolder.classlistados lá.

Btw: o código está funcionando bem na minha máquina local. Mas não funcionou quando o implantei com algum script em um servidor Linux. Então eu acho que não é o problema do código. Mas por algum motivo. o processo de implantação é muito difícil de rastrear.

Qual poderia ser o problema?

Leon
fonte
A estrutura de diretórios apropriada no seu jar corresponde ao pacote da classe?
John B #
precisa ver alguma fonte, muitas coisas podem causar isso. por exemplo, uma instrução 'package', mas o arquivo não reside no caminho correspondente
jcomeau_ictx
3
Uma causa é uma exceção durante a inicialização - há outra saída de erro?
Michael Brewer-Davis

Respostas:

210

Minha melhor aposta é que há um problema aqui:

static {
    //code for loading properties from file
}

Parece que alguma exceção não capturada ocorreu e se propagou até o ClassLoader real que tentava carregar a classe. No entanto, precisaríamos de um rastreamento de pilha para confirmar isso.

Isso ocorreu ou ocorreu ao criar PropHolder.propvariável estática.

John Vint
fonte
Eu tenho enfrentado o mesmo problema várias vezes. Estou certo de que é por causa do staticproblema. O que precisa ser feito para resolver o problema?
víbora
1
Você precisará identificar qual exceção está sendo lançada do staticbloco. Para depurá-lo, coloque um try/catch(Exception e)bloco inteiro e registre a exceção. Você terá que corrigir essa exceção. Normalmente, a exceção será registrada, mas pode ser difícil de encontrar, uma vez que o ser registrada durante classloading que pode acontecer muito cedo
John Vint
Sim, eu mantive o código em try catchbloco e ele disse Failed to initialize ClassA. Eu acho que é o problema de JVM. Eu reiniciei meu sistema e tudo funcionou bem. Como resolver esse problema no futuro sem reiniciar o sistema e resolvê-lo com uma solução simples.
víbora
Falha ao inicializar a ClassA é um efeito colateral de outra coisa. Você vai querer ver causese disponível. Um NoClassDefFoundErrorestá sempre associado a outro erro, você vai precisar de olhar para ele nos logs ou tentar registrá-lo mais apropriadamente (como força o registro em um novo arquivo no sistema de arquivos)
John Vint
Seria mais fácil rastreá-lo se o Java lançasse um erro CouldNotInitializeStaticPartOfClassError ou algo assim. Então, como desenvolvedor, saberíamos onde procurar.
Maarten
126

Você está recebendo um java.lang.NoClassDefFoundErrorque NÃO significa que sua classe está faltando (nesse caso, você obteria um java.lang.ClassNotFoundException). O ClassLoader encontrou um erro ao ler a definição de classe ao tentar ler a classe.

Coloque um try / catch dentro do seu inicializador estático e observe a exceção. Se você ler alguns arquivos lá e diferir do ambiente local, é muito provável que seja a causa do problema (talvez o arquivo não possa ser encontrado, sem permissões etc.).

jeha
fonte
1
Um esclarecimento é que, embora NoClassDefFoundError não implique uma ClassNotFoundException, ainda é uma possível causa do NoClassDefFoundError.
precisa saber é o seguinte
1
buf se você tivesse uma ClassNotFoundException, o ClassLoader nunca tentaria carregar a classe, certo?
jeha 6/09/11
4
Uma classe pode estar carregando outra classe que não foi encontrada. A causa nesse caso ainda é uma ClassNotFoundException
John Vint 6/11
1
Eu deveria ter esclarecido, eu só queria dizer uma exception.getCause ()
John Vint
1
Este foi realmente útil aqui, pois passei cerca de 20 minutos verificando o JAR (a classe relatada pertence) está incluído. Depois que percebi que estou olhando na direção errada, entendi facilmente que alguma classe de anotação está ausente e pronto, a relatada foi declarada como @Stateless, então, apenas adicionei a dependência correspondente e fui capaz de prosseguir. Obrigado pela dica!
RAM237 13/04
33

NoClassDefFoundError não dá muita pista do que deu errado dentro do bloco estático. É uma boa prática sempre ter um bloco como esse dentro do código de inicialização estático {...}:

static {
  try {

    ... your init code here

  } catch (Throwable t) {
    LOG.error("Failure during static initialization", t);
    throw t;
  }
}
Mark Hansen
fonte
Como fazer isso no kotlin?
Marlon
Obrigado por dar a dica. No meu caso, eu estava recebendo o NPE na inicialização de linha estática.
Abhishek
3

Eu tive a mesma exceção, foi assim que resolvi o problema:

Condições prévias:

  1. Classe Junit (e teste), que estendeu outra classe.

  2. ApplicationContext inicializado usando spring, que inicia o projeto.

  3. O contexto do aplicativo foi inicializado no método @Before

Solução:

Inicie o contexto do aplicativo a partir do método @BeforeClass, pois a classe pai também exigiu algumas classes que foram inicializadas no contexto do aplicativo.

Espero que isso ajude.

KerenSi
fonte
2

Como mencionado acima, isso pode ser uma série de coisas. No meu caso, eu tinha uma variável inicializada estaticamente que contava com uma entrada ausente no meu arquivo de propriedades. Adicionada a entrada ausente ao arquivo de propriedades e o problema foi resolvido.

TriMix
fonte
1

Apenas alguns dias atrás, eu encontrei a mesma pergunta como a sua. Todo o código funciona bem na minha máquina local, mas resulta em erro (noclassdeffound & initialize). Então, posto minha solução, mas não sei por que, apenas proponho uma possibilidade. Espero que alguém saiba explique isso. @ John Vint Em primeiro lugar, mostrarei meu problema. Meu código tem variável estática e bloco estático. Quando conheci esse problema, tentei a solução de John Vint e tentei capturar a exceção. No entanto, eu não peguei nada. Então eu pensei que é porque a variável estática (mas agora eu sei que eles são a mesma coisa) e ainda não encontrei nada. Então, eu tento encontrar a diferença entre a máquina linux e o meu computador. Então eu descobri que esse problema ocorre apenas quando vários threads são executados em um processo (a propósito, a máquina linux tem núcleos duplos e processos duplos). Isso significa que, se duas tarefas (ambas usam o código que possui bloco ou variáveis ​​estáticas) executadas no mesmo processo, dá errado, mas se executadas em processos diferentes, as duas estão ok. Na máquina Linux, eu uso

mvn -U clean  test -Dtest=path 

para executar uma tarefa e como minha variável estática é iniciar um contêiner (ou talvez você inicialize um novo carregador de classes), ele permanecerá até que a jvm pare e a jvm pare apenas quando todas as tarefas em um processo pararem. Toda tarefa iniciará um novo contêiner (ou carregador de classe) e isso deixará a jvm confusa. Como resultado, o erro acontece. Então, como resolver isso? Minha solução é adicionar um novo comando ao comando maven e fazer com que cada tarefa vá para o mesmo contêiner.

-Dxxx.version=xxxxx #sorry can't post more

Talvez você já tenha resolvido esse problema, mas ainda espero que ajude outras pessoas que enfrentam o mesmo problema.

Rei Macaco
fonte
Além disso, quando o código é executado na máquina Linux, siga o erro acima, há outro problema java.lang.ExceptionInInitializerError: null:, significa que não é possível encontrar a classe no carregador de classes ou não sabe carregar qual (eu acho). Você conheceu isso?
MonkeyKing
1

Eu tive a mesma exceção - mas apenas durante a execução no modo de depuração, foi assim que resolvi o problema (após 3 dias inteiros): no build.gradle eu tinha: "multiDexEnabled true" definido na seção defaultConfig.

        defaultConfig {
    applicationId "com.xxx.yyy"
    minSdkVersion 15
    targetSdkVersion 28
    versionCode 5123
    versionName "5123"
    // Enabling multidex support.
    multiDexEnabled true
}

mas aparentemente isso não foi suficiente. mas quando mudei:

public class MyAppClass  extends Application 

para:

public class MyAppClass  extends MultiDexApplication 

isso resolveu. espero que isso ajude alguém

Elad
fonte
0

Se você estiver trabalhando em um projeto Android, verifique se não está chamando nenhum método estático em nenhuma classe do Android. Estou usando apenas o JUnit + Mockito, então talvez outras estruturas possam ajudá-lo a evitar o problema completamente, não tenho certeza.

Meu problema foi chamar Uri.parse(uriString)como parte de um inicializador estático para um teste de unidade. A classe Uri é uma API do Android, e é por isso que o teste de unidade não conseguiu encontrá-lo. Alterei esse valor para em nullvez disso e tudo voltou ao normal.

lifeson106
fonte
0

Eu tive os mesmos problemas: java.lang.NoClassDefFoundError: Não foi possível inicializar a classe com.xxx.HttpUtils

static {
    //code for loading properties from file
}

é o problema do ambiente. Isso significa que as propriedades em application.yml estão incorretas ou vazias!

user8503957
fonte
0

Eu encontro o mesmo problema. Eu iniciei um objeto de bean no bloco estático como abaixo:

static {
    try{
        mqttConfiguration = SpringBootBeanUtils.<MqttConfiguration>getBean(MqttConfiguration.class);
    }catch (Throwable e){
        System.out.println(e);
    }
 }

Só porque o processo em que o meu bean obedeceu causou um NPE, eu tenho problemas. Então, acho que você deve verificar seu bloco de código estático com cuidado.

lai nan
fonte