2011-08-16 12 views
6

Ho due ClassLoaders che caricano la stessa classe. Quindi, ovviamente questi non possono essere scambiati l'uno con l'altro. Ma ho bisogno di accedere a un oggetto creato nell'altro ClassLoader.Soluzione per ClassCastException a causa del problema ClassLoader

Ho accesso a entrambi i ClassLoaders. Come posso usare quell'oggetto nell'altra classe? Non è necessario eseguire il cast dell'oggetto per farlo corrispondere al ClassLoader corrente.

Ma il problema è che il tipo dell'oggetto restituito è Object. Quindi, devo abbattere quell'oggetto per accedere ad alcuni metodi. Come lo posso fare? Cast normale come le seguenti cause ClassCastException, che già conosco.

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

descriptor#getMojo() restituisce un oggetto di tipo Mojo ma il metodo restituisce Object. Come può fare questo?

Fatemi sapere se avete bisogno di ulteriori informazioni.

Ho letto tutte le teorie sul caricamento delle classi, ma nessuno ha specificato una soluzione adeguata per questo.

+0

Nel vostro esempio, cosa succede se si fa: 'oggetto o = descriptor.getMojo(); System.out.println (o.getClass); 'con i due diversi classloader? – Bringer128

+0

La domanda più importante qui sarebbe: cosa stai * effettivamente * cercando di ottenere qui? Si tratta di un esercizio accademico o esiste un vero caso d'uso a sostegno di questa situazione? –

+0

@ Bringer128 Restituisce lo stesso pacchetto nome classe.Mojo. Stavo pensando se è possibile eseguire il suddetto casting tramite il metodo getClass() e #cast (Object o)? – ravana

risposta

7

AFAIK, no, non è possibile eseguire il cast di un oggetto di una classe caricato da un caricatore di classi in un altro caricatore di classi.

  • Una soluzione potrebbe essere quella di creare un caricatore di classi "comune" che carica le classi da utilizzare dai propri programmi di caricamento di classi personalizzati. Nel tuo caso, avresti un nuovo classloader che caricherà la classe data e i tuoi programmi di caricamento personalizzati estenderanno questo programma di caricamento classi.
  • Un'altra soluzione sarebbe quella di passare attorno allo stato "serializzato" tra i due classloader. Serializzare un'istanza in una matrice di byte e ricostruire l'oggetto nell'altro classloader deserializzando il flusso di oggetti.
+0

Non voglio lanciarlo da un caricatore di classi a un altro, ma questo è ciò che accade qui quando eseguo il casting specificato. Come posso eseguire questo cast all'interno dello stesso classloader?) descriptor.getMojo() non funziona! – ravana

+0

Questo perché l'istanza "Mojo" nel descrittore è stata caricata da un classloader diverso da quello in cui si sta cercando di recuperarlo. Ho bisogno di più contesto qui. un'applicazione è questa? applicazione Web? Sono coinvolte più discussioni qui? –

+0

È un'app java in esecuzione su un singolo thread, utilizzando Classworlds 1.1 per il caricamento delle classi. – ravana

0

Perché hai 2 Cloass Loader, che carica la stessa classe? Questo potrebbe essere un problema programmatico. Sembra che tu stia memorizzando nella cache ClassLoader da qualche parte e riusarli in un modo sbagliato. Se questo non è il caso prova un MultiClassLoader.

Creare un MultiClassLoader che include più altro classloader. Questi MultiClassLoader puoi usare per caricare tutte le Classi che desideri. Ma devi creare questi MultiClassLoader all'inizio e non quando le classi vengono caricate.

public class MultiClassLoader extends ClassLoader 

Si avrebbe una collezione di classloader e nel findClass (...) di eseguire iterazioni su tutti questi caricatori registrati.

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

sfortunatamente non ho la possibilità di cambiare i caricatori di classe. Ho accesso a entrambi, ma non riesco a creare qualcosa come MultipleClassloader! – ravana

+0

Il metodo getClass() restituisce una classe che contiene sia la classe che il classloader? Se è così, c'è un modo per farlo usando un meccanismo del genere? – ravana

+0

Ho visto questa soluzione. Potrei usarlo in un altro modo. Mi piacerebbe sapere un altro dettaglio. Di ', ho ottenuto l'oggetto Class tramite il metodo findClass. Allora cosa dovrei fare? Come ho detto prima, ho bisogno di trasmettere il mio oggetto a questa classe restituita. Mojo = class.cast (object) mi dà errori di compilazione perché pensa che il cast della classe # restituisca un oggetto di tipo Object. – ravana

0

Il modo più semplice è utilizzare la riflessione. Questo ti permette di dó qualsiasi cosa tu possa dó nel codice "normale".

+0

Capisco. Il codice indicato utilizza la riflessione. Ma ho una conoscenza molto limitata della riflessione. Sareste in grado di aggiungere una soluzione semplice alla risposta? Sarà molto utile! – ravana

+0

Non esiste una soluzione semplice quando si utilizza la riflessione. È abbastanza noioso :( –

1

La riflessione non è male ed è appropriata qui.
È un plug-in Maven, BTW?

Si vorrà qualcosa di simile:

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

che sto lasciando fuori un sacco - in particolare la gestione delle eccezioni - ma questo si dovrebbe portare alla Javadoc è necessario. È abbastanza buono, ma leggi attentamente.

Se hai anche due classi di Mojo, il cast si interromperà e dovrai fare più riflessioni per fare tutto ciò che devi fare con il gemello Mojo.

+0

È davvero un plug-in maven. Proverò questo e ti faccio sapere come va Cosa intendevi per javadoc? – ravana

+0

La relativa classe e il metodo javadoc. –

0

Penso che l'opzione migliore sia semplicemente memorizzare array di byte anziché oggetto. Durante la deserializzazione, recuperare l'array di byte e convertirlo in oggetto.

Ho avuto lo stesso problema e l'approccio di array di byte ha funzionato.

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(); 
    } 

leggere da array di byte:

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(); 
    } 
Problemi correlati