É incrÃvel como aprendemos algo novo todo dia, mesma que a lição venha de forma lenta e dolorosa… recentemente, em uma empresa onde presto serviços em Java, tivemos um problema com o DWR (tenho enorme paixão por este componente, o modo como fizeram a ponte entre Java e Javascript chega a ser mágico, é o estado da arte em uso de Javascript, mas isso fica pra outro ‘post’… =D)
Pois bem, o problema foi ocasionado durante testes de migração pra o JBoss 4.x, a inicialização do DWR estava falhando, não conseguia de forma alguma encontrar as classes informadas em seu arquivo de configuração xml, o famigerado NoClassDefFoundError, algo que não apresentava problemas no JBoss 3.x. Após olhar em empacotamento, meta-infs, jars, configurações do JBoss, nada, nenhuma pista, nem o Google ajudou. O jeito foi descer mais fundo, ler o código fonte do DWR. A linha onde o erro ocorre, executa apenas um carregamento de classe:
this.classDefinition = Class.forName(className) ;
A classe é guardada para que possa ser instanciada por reflexão posteriormente, o interessante é que tudo isso ocorre na inicialização do JBoss, depois que a aplicação levanta, tentamos via debugger, executar o mesmo comando e voilá… funcionava perfeitamente… o que raios estava acontecendo ? Não sabÃamos….
Bom, não teve jeito, a classe do DWR teve de ser alterada para testar outra possibilidade de carregamento. Com isso trocamos a linha para:
this.classDefinition = Thread.currentThread().getContextClassLoader().loadClass(className);
Linha monstruosa…. mas funcionou!
Boa prática aprendida: o Class.forName() não sobe na hierarquia de ClassLoader, fica apenas no ClassLoader local, enquanto o ClassLoader.loadClass() sim, ou seja, por questão de robustez e boa prática, sempre utilize a segunda forma, para não ficar com cara de “ué”, quando este tipo de problema surgir.
Mas por que no JBoss 3.x funcionava e no 4.x não ? A resposta é que o ClassLoader o 4.x foi reescrito para ficar mais aderente as especificações, com isso o Class.forName() pegou todo mundo desprevinido, houve claras reclamações da comunidade, mas temos que viver com isso…, existem práticas a serem seguidas.
Ainda bem que não tivemos que usar o código alterado do DWR, estávamos na versão 1.1.3, por curiosidade, baixei a versão estável mais recente (1.1.4) e pra minha grata surpresa essa linha já havia sido alterada do mesmo modo que fizemos :D, só fiquei chateado por essa alteração não estar presente no release notes, teria me economizado tempo durante busca por pistas…