Isso não responde à pergunta original, mas como a pergunta é altamente classificada e vinculada a qualquer ContextClassLoader
consulta, acho importante responder à pergunta relacionada de quando o carregador de classes de contexto deve ser usado. Resposta curta: nunca use o carregador de classes de contexto ! Mas defina-o como getClass().getClassLoader()
quando você precisar chamar um método que está faltando um ClassLoader
parâmetro.
Quando o código de uma classe pede para carregar outra classe, o carregador de classes correto a ser usado é o mesmo carregador de classe que a classe do chamador (ou seja, getClass().getClassLoader()
). É assim que as coisas funcionam 99,9% do tempo, porque é isso que a JVM faz na primeira vez em que você constrói uma instância de uma nova classe, invoca um método estático ou acessa um campo estático.
Quando você deseja criar uma classe usando reflexão (como desserializar ou carregar uma classe nomeada configurável), a biblioteca que faz a reflexão sempre deve perguntar ao aplicativo qual carregador de classes usar, recebendo o ClassLoader
parâmetro como do aplicativo. O aplicativo (que conhece todas as classes que precisam ser construídas) deve ser aprovado getClass().getClassLoader()
.
Qualquer outra maneira de obter um carregador de classes está incorreta. Se uma biblioteca usos hacks como Thread.getContextClassLoader()
, sun.misc.VM.latestUserDefinedLoader()
ou sun.reflect.Reflection.getCallerClass()
é um erro causado por uma deficiência na API. Basicamente, Thread.getContextClassLoader()
existe apenas porque quem projetou a ObjectInputStream
API esqueceu de aceitar o ClassLoader
parâmetro, e esse erro assombrou a comunidade Java até hoje.
Dito isto, muitas classes JDK usam um dos poucos hacks para adivinhar o uso de um carregador de classes. Alguns usam o ContextClassLoader
(que falha quando você executa aplicativos diferentes em um pool de encadeamentos compartilhados ou quando você sai ContextClassLoader null
), outros andam na pilha (que falha quando o chamador direto da classe é uma biblioteca), outros usam o carregador de classes do sistema (o que é bom, desde que esteja documentado para usar apenas classes no CLASSPATH
) ou carregador de classes de autoinicialização e alguns usam uma combinação imprevisível das técnicas acima (o que apenas torna as coisas mais confusas). Isso resultou em muito choro e ranger de dentes.
Ao usar essa API, primeiro, tente encontrar uma sobrecarga do método que aceite o carregador de classes como parâmetro . Se não houver um método sensato, tente definir a ContextClassLoader
chamada antes da API (e redefini-la depois):
ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
// call some API that uses reflection without taking ClassLoader param
} finally {
Thread.currentThread().setContextClassLoader(originalClassLoader);
}
ClassB
deve estar no caminho de classe doClassA
carregador (ouClassA
dos pais do carregador)? Não é possívelClassA
substituir o carregadorloadClass()
, de forma que ele possa carregar com êxitoClassB
mesmo quandoClassB
não estiver no caminho de classe?