ClassCastException quando si esegue il casting sulla stessa class

Ho 2 diversi progetti Java, uno ha 2 classi: dynamicbeans.DynamicBean2 e dynamic.Validator .

Nell’altro progetto, carico entrambe le classi dynamicmente e le memorizzo su un Object

 class Form { Class beanClass; Class validatorClass; Validator validator; } 

Quindi vado avanti e creo un object Validator usando validatorClass.newInstance() e lo memorizzo su validator quindi creo anche un object bean usando beanClass.newInstance() e lo aggiungo alla sessione.

 portletRequest.setAttribute("DynamicBean2", bean); 

Durante il ciclo di vita del progetto Form , chiamo validator.validate() che carica l’object bean precedentemente creato dalla sessione (sto eseguendo Websphere Portal Server). Quando provo a restituire questo object in un DynamicBean2 , fallisce con una ClassCastException.

Quando estraggo l’object dalla sessione usando

     faces.getApplication().createValueBinding("#{DynamicBean2}").getValue(faces); 

    e controlla la class usando .getClass() Ricevo dynamicbeans.DynamicBean2 . Questa è la class che voglio lanciare, tuttavia quando cerco di ottenere ClassCastException.

    Qualche ragione per cui sto ricevendo questo?

    Non sto seguendo la tua descrizione del stream del programma, ma di solito quando ottieni ClassCastExceptions non puoi spiegare che hai caricato la class con un classloader, quindi prova a lanciarlo sulla stessa class caricata da un altro classloader. Questo non funzionerà – sono rappresentati da due oggetti Class diversi all’interno della JVM e il cast fallirà.

    C’è un articolo sul caricamento di classi in WebSphere . Non posso dire come si applica alla tua applicazione, ma ci sono un certo numero di possibili soluzioni. Posso almeno pensare:

    1. Modificare manualmente il caricatore delle classi di contesto. Richiede che tu possa effettivamente ottenere un riferimento a un programma di caricamento classi appropriato, che potrebbe non essere ansible nel tuo caso.

       Thread.currentThread().setContextClassloader(...); 
    2. Assicurati che la class sia caricata da un caricatore di classi più in alto nella gerarchia.

    3. Serializza e deserializza l’object. (Che schifo!)

    C’è probabilmente un modo più appropriato per la tua situazione particolare però.

    Gli oggetti di class sono stati caricati in diversi classloader, pertanto le istanze create da ciascuna delle classi sono considerate “incompatibili”. Questo è un problema comune in un ambiente in cui ci sono molti diversi classloader in uso e oggetti vengono passati in giro. Questi problemi possono facilmente sorgere in Java EE e negli ambienti del portale.

    La trasmissione di un’istanza di una class richiede che la class collegata all’object da trasmettere sia uguale a quella caricata dal classloader di contesto corrente del thread.

    Ho ottenuto il problema A2AClassCastException quando provo a creare un elenco di oggetti da XML usando Apache Commons Digester.

     List templates = new ArrayList(); Digester digester = new Digester(); digester.addObjectCreate("/path/to/template", MyTemplate.class); digester.addSetNext("/path/to/template", "add"); // Set more rules... digester.parse(f); // f is a pre-defined File for(MyTemplate t : templates) { // ClassCastException: Cannot cast mypackage.MyTemplate to mypackage.MyTemplate // Do stuff } 

    Come detto sopra, la causa è che il digestore non usa lo stesso ClassLoader come il resto del programma. L’ho eseguito in JBoss, e si è scoperto che commons-digester.jar non era nella directory lib di JBoss, ma piuttosto nella directory lib di una webapp. Anche la copia del barattolo in mywebapp / WEB-INF / lib ha risolto il problema. Un’altra soluzione era casll digester.setClassLoader (MyTemplate.class.getClassLoader ()), ma in questo contesto sembra una soluzione abbastanza brutta.

    Ho avuto lo stesso problema con una ricerca EJB da un altro EJB. Ho risolto l’aggiunta di @Remote (MyInterface.class) alla configurazione della class EJB

    Ho avuto lo stesso problema durante l’utilizzo di diverse istanze di JBoss su macchine diverse. Per il male non mi sono imbattuto in questo post prima.
    C’erano artefatti distribuiti su macchine diverse, due di loro hanno dichiarato caricatori di classi con nome identico. Ho cambiato uno dei nomi di classloader e tutto ha funzionato bene => Attenzione a copia e incolla!

    Perché l’eccezione ClassCastException non menziona i caricatori di class coinvolti? – Penso che sarebbe un’informazione molto utile.
    Qualcuno sa se ci sarà qualcosa di simile disponibile in futuro? La necessità di controllare i caricatori di class di 20-30 artefatti non è così piacevole. O c’è qualcosa che mi è mancato nel testo dell’eccezione?

    EDIT : ho modificato il file META-INF / jboss-app.xml e ho cambiato il nome del loader, l’idea è di avere un nome univoco. Al lavoro usiamo l’id artefatto (unico) combinato con la versione inserita da Maven ({$ versione}) durante la compilazione.
    L’utilizzo di campi dinamici è facoltativo ma aiuta se si desidera distribuire versioni diverse della stessa applicazione.

       com.example:archive=unique-archive-name-{$version}   

    Puoi trovare alcune informazioni qui: https://community.jboss.org/wiki/ClassLoadingConfiguration

    Ho avuto lo stesso problema e alla fine ho trovato una soluzione alternativa su java.net:

    Copia tutti i file org.eclipse.persistence jar da glassfish4/glassfish/modules a WEB-INF/lib . Quindi vai nel tuo glassfish-web.xml e imposta il class-delegate di class-delegate false .

    Ha funzionato per me!

    Ho avuto un problema simile con JAXB e JBoss AS 7.1. Il problema e la soluzione sono descritti qui: javax.xml.bind.JAXBException: Classe *** o qualsiasi sua super class è nota in questo contesto . L’eccezione che è stata data è che org.foo.bar.ValueSet non può essere lanciato su org.foo.bar.ValueSet

    Ho avuto lo stesso problema su un bean wildfly, L’EJB restituiva un elenco di oggetti e ha un’interfaccia remota e locale. Ho usato l’interfaccia locale per sbaglio su ciò che funzionava bene fino al punto in cui provi a lanciare gli oggetti nell’elenco.

    Interfaccia locale / remota:

     public interface DocumentStoreService { @javax.ejb.Remote interface Remote extends DocumentStoreService { } @javax.ejb.Local interface Local extends DocumentStoreService { } 

    Il bean EJB:

     @Stateless public class DocumentStoreServiceImpl implements DocumentStoreService.Local, DocumentStoreService.Remote { 

    L’involucro a molla corretto attorno all’EJB:

          

    Nota $ Remote, puoi cambiarlo in $ Local e troverà l’interfaccia Local perfettamente funzionante, ed eseguirai anche i metodi senza alcun problema (da un’applicazione separata sullo stesso contenitore), ma gli oggetti del modello non sono sottoposti a marshalling e sono da un caricatore di classi diverse se si utilizza l’interfaccia locale per errore.

    Un’altra opzione:

    Mi è successo in weblogic, ma suppongo che possa succedere anche in altri server – se lo fai (solo) “Pubblica” e quindi alcune delle tue classi vengono ricaricate. Invece fai “Clean” in modo che tutte le classi vengano ricaricate insieme.

    Ho avuto lo stesso my.package.MyClass cannot be cast to my.package.MyClass su WildFly 10.1 e, come ho capito, ho fatto l’opposto di ciò che @Emil Lundberg ha descritto nella sua risposta.

    Ho aggiunto il modulo (che contiene my.package.MyClass ) a my.war/WEB-INF/jboss-deployment-structure.xml come dipendenza

      ...   

    e rimosso il jar corrispondente da my.war/WEB-INF/lib , ri-distribuito il WAR e quindi il codice ha funzionato come previsto.

    Pertanto, ci siamo assicurati che risolva il problema. Ora, dobbiamo assicurarci che il problema non ritorni, ad esempio quando la versione aggiornata di WAR verrà assemblata e distribuita.

    Per questo, nelle fonti di WAR , è necessario aggiungere provided per quei jar in pom.xml , in modo che quando my.war viene riassemblato la prossima volta con il codice fix / enhancement iniettato , non raggrupperà questo jar in my.war/WEB-INF/lib .