¿Es posible tener archivos de la carga del sistema ClassLoader .class especificado en tiempo de ejecución?

StackOverflow https://stackoverflow.com/questions/1873916

Pregunta

Estoy escribiendo una herramienta de análisis estático para una asignación, se analiza el código de bytes de Java utilizando la biblioteca ASM. Una de las partes de ASM que utilizamos requiere (o al menos, parece requerir) que la clase puede cargar desde el cargador de clases.

Esperábamos la herramienta sería capaz de analizar archivos .class sin que tengan en la ruta de clase. Ya Descargando .classes desde un directorio especificado en tiempo de ejecución y leerlos en el uso de un InputStream. Esto es aceptable para ASM en la mayoría de los casos. Hay algunas clases, como SimpleVerifier, que tratan de cargar las clases embargo.

¿Es posible, en este escenario, para registrar los archivos .class para ser cargados para que las llamadas a Class.forName() los cargará? ¿O hay una manera fácil de extender el cargador de clases para permitir esto?


Editar: La información de URLClassLoader era útil. Desafortunadamente, el uso Thread.currentThread().setContextClassLoader() a una instancia de que no funcionó en este escenario. El código de la biblioteca que estoy poniendo en utiliza un cargador que recupera la instancia de inicialización utilizando getClass().getClassLoader().

Por el momento me puse la URLClassLoader la clase no se ha inicializado por lo que supongo que la contextClassLoader no se carga esa clase.

¿He entendido correctamente las respuestas? Sería usar el URLClassLoader para cargar la clase tercera parte sea una posibilidad?

¿Fue útil?

Solución

Casi.

Si ha compilado clases en alguna parte, puede cargarlos con un URLClassLoader . A continuación, puede configurar este cargador de clases para ser el cargador de clases para el proceso actual: Thread.setContextClassLoader (ClassLoader)

Los usuarios pueden conseguir que el cargador de hilos actuales clase de contexto y usarlo para acceder a la definición de clase.

Otros consejos

En primer lugar, ASM se puede utilizar de forma tal que no va a usar cargador de clases para obtener información sobre las clases.

Hay varios lugares en el marco ASM donde se carga clases por defecto, pero todos esos lugares puede suprimirse en sus propias subclases. Fuera de la parte superior de mi cabeza:

  • ClassWriter.getCommonSuperClass () método se llama sólo cuando se utiliza la bandera ClassWriter.COMPUTE_FRAMES y se puede overwriten no usar cargador de clases para obtener inforamtion sobre las clases. Se puede encontrar un ejemplo de que, en ClassWriterComputeFramesTest que introduce una abstracción ClassInfo
  • método mismo modo SimpleVerifier.getClass () es usado por SimpleVerifier.isAssignableFrom () y se puede sobrescribir este último y el uso de la abstracción ClassInfo para encontrar el común supertipo. Si no me equivoco, proyecto AspectWerkz había puesto en práctica algo similar en su código de tipo de coincidencia de patrones. También tenga en cuenta que hay SimpleVerifier.setClassLoader () método, que se puede utilizar si todavía quiere cargar sus propias clases.

En una nota lateral, en las JVM de Sun, las clases cargadas llega a PermGen área y no se puede descargar, por lo que no es una buena idea para cargar las clases sólo para fines de análisis de código estático si se puede evitar que, sobre todo si herramienta se integra en un proceso a largo vivo, tales como IDE.

No se puede, por lo que yo sé, extender el cargador de clases de sistema en tiempo de ejecución, pero se puede cargar dinámicamente las clases desde una ubicación arbitraria (frasco o directorio) utilizando URLClassLoader .

Se podría tratar de configurar un "lanzador" en el inicio de la aplicación que crea un URLClassLoader pasándole los lugares de la ruta de clases y sus propias ubicaciones .class e iniciar la aplicación de ese cargador de clases.

Cuando el SimpleVerifier se carga por el URLClassLoader también será capaz de cargar las clases de los lugares adicionales.

Sí, puede utilizar URLClassLoader

Tengo una prueba en la que yo no cargar la clase en tiempo de ejecución. Esta clase no está en la ruta de clase (ni siquiera existir cuando se realiza la prueba para el caso), después se cargó y funciona muy bien.

Aquí está el código.

void testHello() throws MalformedURLException, ClassNotFoundException {
    URL[] url = {
            new URL("file:/home/oreyes/testwork/")
    };

    try {
        new URLClassLoader(url).loadClass("Hello");
        throw new AssertionError("Should've thrown ClassNotFoundException");
    } catch ( ClassNotFoundException cnfe ){}


    c.process();// create the .class file 

    new URLClassLoader(url).loadClass("Hello");

    // it works!!
}

.

He creado mi propio cargador de clases es bastante simple.

 /**
 * Used to hold the bytecode for the class to be loaded.
 */
private final static ThreadLocal<byte[]> BYTE_CODE = new ThreadLocal<byte[]>();

@Override
protected Class<?> findClass(final String name) throws ClassNotFoundException {
    final byte[] bytes = BYTE_CODE.get();
    if (null == bytes) {
        throw new ClassNotFoundException(name);
    }
    return this.defineClass(null, bytes, 0, bytes.length);
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top