it-swarm.com.de

ClassCastException beim Umwandeln in dieselbe Klasse

Ich habe 2 verschiedene Java Projekte, eines hat 2 Klassen: dynamicbeans.DynamicBean2 Und dynamic.Validator.

Im anderen Projekt lade ich beide Klassen dynamisch und speichere sie auf einem Object

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

Dann erstelle ich ein Validator -Objekt mit validatorClass.newInstance() und speichere es auf validator. Dann erstelle ich auch ein Bean-Objekt mit beanClass.newInstance() und füge hinzu es zur Sitzung.

portletRequest.setAttribute("DynamicBean2", bean);

Während des Lebenszyklus des Projekts Form rufe ich validator.validate() auf, wodurch das zuvor erstellte Bean-Objekt aus der Sitzung geladen wird (ich führe Websphere Portal Server aus). Wenn ich versuche, dieses Objekt wieder in DynamicBean2 Umzuwandeln, schlägt dies mit einer ClassCastException fehl.

Wenn ich das Objekt mit aus der Sitzung zurückziehe

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

und überprüfe die Klasse mit .getClass() Ich erhalte dynamicbeans.DynamicBean2. Dies ist die Klasse, in die ich sie umwandeln möchte, aber wenn ich versuche, die ClassCastException abzurufen.

Gibt es einen Grund, warum ich das bekomme?

51
Jaime Garcia

Ich folge nicht ganz Ihrer Beschreibung des Programmflusses, aber normalerweise, wenn Sie ClassCastExceptions erhalten, können Sie nicht erklären, dass Sie die Klasse mit einem Klassenladeprogramm geladen haben, und versuchen, sie in dieselbe Klasse zu konvertieren, die von einem anderen Klassenladeprogramm geladen wurde. Dies funktioniert nicht - sie werden von zwei verschiedenen Klassenobjekten in der JVM dargestellt, und die Umwandlung schlägt fehl.

Es gibt einen Artikel zum Laden von Klassen in WebSphere . Ich kann nicht sagen, wie es auf Ihre Bewerbung zutrifft, aber es gibt eine Reihe möglicher Lösungen. Ich kann mir wenigstens vorstellen:

  1. Ändern Sie das Kontextklassenladeprogramm manuell. Erfordert, dass Sie tatsächlich einen Verweis auf ein geeignetes Klassenladeprogramm erhalten, was in Ihrem Fall möglicherweise nicht möglich ist.

    Thread.currentThread().setContextClassLoader(...);
    
  2. Stellen Sie sicher, dass die Klasse von einem Klassenladeprogramm höher in der Hierarchie geladen wird.

  3. Serialisieren und deserialisieren Sie das Objekt. (Yuck!)

Es gibt jedoch wahrscheinlich einen angemesseneren Weg für Ihre spezielle Situation.

57
waxwing

Die Klassenobjekte wurden in verschiedene Klassenladeprogramme geladen, daher werden die Instanzen, die in den einzelnen Klassen erstellt wurden, als "inkompatibel" angesehen. Dies ist ein häufiges Problem in einer Umgebung, in der viele verschiedene Klassenladeprogramme verwendet und Objekte weitergegeben werden. Diese Probleme können leicht in Java EE- und Portalumgebungen auftreten.

Das Umsetzen einer Instanz einer Klasse setzt voraus, dass die mit dem umzusetzenden Objekt verknüpfte Klasse mit der vom aktuellen Thread-Kontext-Klassenladeprogramm geladenen Klasse identisch ist.

12
Robin

Beim Versuch, mit Apache Commons Digester eine Liste von Objekten aus XML zu erstellen, ist das Problem A2AClassCastException aufgetreten.

List<MyTemplate> templates = new ArrayList<MyTemplate>();
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
}

Wie bereits erwähnt, verwendet der Digester nicht denselben ClassLoader wie der Rest des Programms. Ich habe dies in JBoss ausgeführt, und es stellte sich heraus, dass sich commons-digester.jar nicht im lib-Verzeichnis von JBoss, sondern im lib-Verzeichnis einer Webanwendung befand. Das Problem wurde auch durch Kopieren der JAR-Datei in mywebapp/WEB-INF/lib behoben. Eine andere Lösung bestand darin, digester.setClassLoader (MyTemplate.class.getClassLoader ()) zu installieren, aber dies scheint in diesem Zusammenhang eine ziemlich hässliche Lösung zu sein.

2
Emil Lundberg

Hatte das gleiche my.package.MyClass cannot be cast to my.package.MyClass Auf WildFly 10.1 und, wie ich verstehe, habe ich das Gegenteil von dem getan, was @Emil Lundberg in seiner Antwort beschrieben hat.

Ich habe das Modul (welches my.package.MyClass Enthält) zu my.war/WEB-INF/jboss-deployment-structure.xml Als Abhängigkeit hinzugefügt

<dependencies>
    ...
    <module name="my.package"/>
</dependencies>

und entfernte das entsprechende jar aus my.war/WEB-INF/lib, implementierte die WAR erneut und der Code funktionierte dann wie erwartet.

Auf diese Weise haben wir sichergestellt, dass das Problem behoben wird. Jetzt müssen wir sicherstellen, dass das Problem nicht erneut auftritt, wenn beispielsweise die aktualisierte Version von WAR zusammengestellt und bereitgestellt wird.

Dazu muss in den Quellen dieser WAR <scope>provided</scope> Für diese jar in pom.xml, So dass wenn my.war Das nächste Mal mit dem eingespeisten Fix/Enhancement-Code neu zusammengestellt wird, dieses jar nicht in my.war/WEB-INF/lib Gebündelt wird.

0
RAM237

Ich hatte das gleiche Problem und fand schließlich eine Problemumgehung auf Java.net:

Kopiere alles org.Eclipse.persistence jar Dateien aus glassfish4/glassfish/modules bis WEB-INF/lib. Dann geh in dein glassfish-web.xml und set class-delegate bis false.

Arbeitete für mich!

0
Adrien Dos Reis

Ich hatte das gleiche Problem mit einem EJB-Lookup von einem anderen EJB. Ich habe das Hinzufügen von @Remote (MyInterface.class) zur EJB-Klassenkonfiguration gelöst

0
user3402702

Ich hatte das gleiche Problem bei der Verwendung mehrerer JBoss-Instanzen auf verschiedenen Computern. Schade, dass ich nicht über diesen Beitrag gestolpert bin.
Es wurden Artefakte auf verschiedenen Computern bereitgestellt, von denen zwei als Klassenladeprogramme mit identischem Namen deklariert wurden. Ich habe einen der Klassenladeprogrammnamen geändert und alles hat einwandfrei funktioniert => Vorsicht beim Kopieren und Einfügen!

Warum werden in der ausgelösten ClassCastException die beteiligten Klassenladeprogramme nicht erwähnt? - Ich denke, das wäre eine sehr nützliche Information.
Weiß jemand, ob es in Zukunft so etwas geben wird? Es ist nicht so angenehm, die Klassenlader von 20-30 Artefakten überprüfen zu müssen. Oder habe ich etwas im Ausnahmetext verpasst?

[~ # ~] edit [~ # ~] : Ich habe die Datei META-INF/jboss-app.xml bearbeitet und den Namen des Loaders geändert Die Idee ist, einen eindeutigen Namen zu haben. Bei der Arbeit verwenden wir die Artefakt-ID (einzigartig) in Kombination mit der Version, die von maven ({$ version}) während des Builds eingefügt wurde.
Die Verwendung dynamischer Felder ist nur optional, aber hilfreich, wenn Sie verschiedene Versionen derselben Anwendung bereitstellen möchten.

<jboss-app>
   <loader-repository> 
   com.example:archive=unique-archive-name-{$version}
   </loader-repository> 
</jboss-app>

Einige Informationen finden Sie hier: https://community.jboss.org/wiki/ClassLoadingConfiguration

0
Andrei

Andere Option:

Ist mir in Weblogic passiert, aber ich denke, es kann auch auf anderen Servern passieren - wenn Sie (nur) "Veröffentlichen" und daher einige Ihrer Klassen neu geladen werden. Führen Sie stattdessen "Clean" aus, damit alle Klassen zusammen neu geladen werden.

0
Yogev Levy

Ich hatte ein ähnliches Problem mit JAXB und JBoss AS 7.1. Das Problem und die Lösung werden hier beschrieben: javax.xml.bind.JAXBException: Klasse ***, und in diesem Kontext ist keine ihrer übergeordneten Klassen bekannt . Die Ausnahme, die angegeben wurde, war org.foo.bar.ValueSet kann nicht in org.foo.bar.ValueSet umgewandelt werden

0
John

Dieses Problem trat auf, nachdem ich in meinem Springboot-Projekt eine Abhängigkeit zu spring-boot-devtools Hinzugefügt hatte. Ich entfernte die Abhängigkeit und das Problem verschwand. Ich vermute an dieser Stelle, dass spring-boot-devtools Einen neuen Klassenladeprogramm einführt und dass das Problem der Klassenumwandlung zwischen verschiedenen Klassenladeprogrammen in bestimmten Fällen auftritt, in denen das neue Klassenladeprogramm von einigen Threads nicht verwendet wird.

Referenz: Eine Dozer-Map-Ausnahme im Zusammenhang mit Spring Boot-Devtools

0
K.Nicholas

Ich hatte das gleiche Problem bei einem Wildfly-EJB. Der EJB gab eine Liste von Objekten zurück und verfügt über eine entfernte und eine lokale Schnittstelle. Ich habe versehentlich die lokale Benutzeroberfläche verwendet, was bis zu dem Zeitpunkt, an dem Sie versuchen, die Objekte in der Liste umzuwandeln, einwandfrei funktioniert hat.

Lokale/Remote-Schnittstelle:

public interface DocumentStoreService {

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

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

Die EJB Bohne:

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

Die richtige Federwicklung um den EJB:

<bean id="documentStoreService" class="org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean">
    <property name="jndiName" value="Java:global/dpc/dpc-ejb/DocumentStoreServiceImpl!santam.apps.dpc.service.DocumentStoreService$Remote"/>
    <property name="businessInterface" value="santam.apps.dpc.service.DocumentStoreService$Remote"/>
    <property name="resourceRef" value="true" />
</bean>

Beachten Sie $ Remote. Sie können dies in $ Local ändern, und die lokale Schnittstelle wird problemlos gefunden. Außerdem können Sie die Methoden ohne Probleme ausführen (aus einer separaten Anwendung im selben Container), aber die Modellobjekte werden nicht gemarshallt und werden gemarshallt von einem anderen Klassenladeprogramm, wenn Sie versehentlich die lokale Schnittstelle verwenden.

0
Meindert