2011-08-16 12 views
6

Tengo dos ClassLoaders que cargan la misma clase. Entonces, obviamente, estos no se pueden enviar el uno al otro. Pero necesito acceder a un objeto creado en el otro ClassLoader.Solución para ClassCastException debido al problema de ClassLoader

Tengo acceso a ambos ClassLoaders. ¿Cómo puedo usar ese objeto en la otra clase? No necesito convertir el objeto para que coincida con el ClassLoader actual.

Pero el problema es que el tipo del objeto devuelto es Object. Entonces, tengo que rechazar ese objeto para acceder a algunos métodos. ¿Cómo puedo hacer eso? El lanzamiento normal como el siguiente causa ClassCastException, que ya sé.

Mojo mojo = (Mojo) descriptor.getMojo(); 

descriptor#getMojo() devuelve un objeto de tipo Mojo pero el método devuelve Object. ¿Cómo puede hacer esto?

Deseo saber si necesita más información.

He leído todas las teorías sobre la carga de clases, pero ninguna ha especificado una solución adecuada para esto.

+0

En su caso, ¿qué ocurre si lo hace: 'Object o = descriptor.getMojo(); System.out.println (o.getClass); 'con los dos cargadores de clases diferentes? – Bringer128

+0

La pregunta más importante aquí sería: ¿qué estás * realmente * tratando de lograr aquí? ¿Es este un ejercicio académico o hay un caso de uso real que respalda esta situación? –

+0

@ Bringer128 Devuelve el mismo paquete de nombre de clase.Mojo. Estaba pensando si es posible realizar dicho casting a través de los métodos getClass() y #cast (Object o). – ravana

Respuesta

7

AFAIK, no, no se puede convertir un objeto de una clase cargada por un cargador de clases en otro cargador de clases.

  • Una solución sería crear un cargador de clases "común" que cargue las clases que utilizarán los cargadores de clases personalizados. Entonces, en tu caso, tendrías un nuevo cargador de clases que cargaría la clase dada y tus cargadores de clases personalizados ampliarían este cargador de clases.
  • Otra solución sería pasar el estado "serializado" entre los dos cargadores de clases. Serialice una instancia a una matriz de bytes y reconstruya el objeto en el otro cargador de clases deserializando la secuencia de objetos.
+0

No quiero transmitirlo de un cargador de clases a otro. Pero eso es lo que sucede aquí cuando hago el casting. ¿Cómo puedo hacer esto mediante el mismo cargador de clases? (Mojo)) descriptor.getMojo() simplemente no funciona! – ravana

+0

Esto se debe a que la instancia "Mojo" dentro del descriptor fue cargada por un cargador de clases diferente al que está tratando de recuperar. Necesito más contexto aquí. ¿Qué tipo de una aplicación es esta? Aplicación web? ¿Hay varios hilos implicados aquí? –

+0

Es una aplicación de Java que se ejecuta en un solo hilo. Utiliza classworld 1.1 para la carga de clases. – ravana

0

¿Por qué tiene 2 CloassLoaders, que carga la misma clase? Esto podría ser un problema programático. Parece que está almacenando en caché ClassLoader en alguna parte y reutilizándolos de forma incorrecta. Si este no es el caso, pruebe un MultiClassLoader.

Crea un MultiClassLoader que incluye varios otros cargadores de clases. Estos MultiClassLoader se pueden usar para cargar todas las clases que desee. Pero tiene que crear estos MultiClassLoader desde el principio y no cuando se cargan las clases.

public class MultiClassLoader extends ClassLoader 

Se podría tener una colección de cargadores de clases y en el FindClass (...) que iterar sobre todos estos cargadores registrados.

protected Class findClass(String aName) throws ClassNotFoundException { 
    for (Iterator iter = multiLoaders.iterator(); iter.hasNext();) { 
     ClassLoader tmpLoader = (ClassLoader)iter.next(); 
     try { 
     return tmpLoader.loadClass(aName); 
     } catch (ClassNotFoundException e) { 
     } 
    } 
    throw new ClassNotFoundException(aName); 
} 
+0

lamentablemente no tengo la capacidad de cambiar los cargadores de la clase. Tengo acceso a ambos, ¡pero no puedo crear algo como MultipleClassloader! – ravana

+0

¿El método getClass() devuelve una clase que contiene tanto la clase como su cargador de clases? Si es así, ¿hay alguna manera de hacerlo utilizando un mecanismo como ese? – ravana

+0

He estado buscando esta solución. Podría usarlo de otra manera. Me gustaría saber un detalle más. Diga, tengo el objeto Class a través de su método findClass. Entonces, ¿qué debería hacer? Como dije antes, necesito enviar mi objeto a esta clase devuelta. Mojo = class.cast (object) me da errores de compilación porque cree que la clase # cast devuelve un objeto de tipo Object. – ravana

0

La manera más fácil es usar la reflexión. Esto le permite copiar cualquier cosa que pueda en código "normal".

+0

Ya veo. El código dado usa reflexión. Pero tengo un conocimiento muy limitado sobre la reflexión. ¿Sería capaz de agregar una solución simple a la respuesta? ¡Eso será de mucha ayuda! – ravana

+0

No hay una solución simple al usar la reflexión. Es bastante tedioso :( –

1

La reflexión no es tan mala, y es apropiada aquí.
¿Es este un plugin Maven, BTW?

Usted querrá algo como:

Mojo mojo = (Mojo)descriptor.getClass().getMethod("getMojo").invoke(descriptor); 

estoy dejando fuera mucho - sobre todo el manejo de excepciones - pero esto debe conducir a la Javadoc que necesita. Es bastante bueno, pero lee atentamente.

Si también tiene dos clases de Mojo, el yeso se romperá, y tendrá que hacer más reflexión para hacer lo que tenga que hacer con el malvado gemelo Mojo.

+0

Es de hecho un plugin maven. Intentaré esto y te contaré cómo va ¿A qué se refería javadoc? – ravana

+0

La clase y el método relevantes javadoc. –

0

Creo que es mejor opción que simplemente almacenar la matriz de bytes en lugar de objetos. Mientras deservista, recupera la matriz de bytes y conviértela en objeto.

Tuve el mismo problema y funcionó el enfoque de matriz de bytes.

ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
    ObjectOutput out = null; 
    try { 
     out = new ObjectOutputStream(bos); 
     out.writeObject(cachedValue); 
     byte b[] = bos.toByteArray(); 

     //Store in DB, file wherever here using b[]. I am not writing code to store it as it may vary in your requirement. 

    } catch (IOException e) { 
     e.printStackTrace(); 
    } 

leer desde el conjunto de bytes:

ByteArrayInputStream bis = new ByteArrayInputStream(<<read byte[] where you stored earlier>>); 
    ObjectInput in = null; 

    try { 
     in = new ObjectInputStream(bis); 
     <Your Class >cachedRes = (Your Class) in.readObject(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } catch (ClassNotFoundException e) { 
     e.printStackTrace(); 
    } 
Cuestiones relacionadas