web-dev-qa-db-fra.com

ClassCastException lors du cast dans la même classe

J'ai 2 projets différents Java, on a 2 classes: dynamicbeans.DynamicBean2 Et dynamic.Validator.

Sur l'autre projet, je charge ces deux classes dynamiquement et les stocke sur un Object

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

Je continue ensuite et crée un objet Validator en utilisant validatorClass.newInstance() et le stocke sur validator puis je crée également un objet bean en utilisant beanClass.newInstance() et j'ajoute à la session.

portletRequest.setAttribute("DynamicBean2", bean);

Pendant le cycle de vie du projet Form, j'appelle validator.validate() qui charge l'objet bean créé précédemment à partir de la session (j'exécute Websphere Portal Server). Lorsque j'essaye de reconstituer cet objet dans un DynamicBean2, Il échoue avec une ClassCastException.

Lorsque je retire l'objet de la session à l'aide de

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

et vérifiez la classe en utilisant .getClass() J'obtiens dynamicbeans.DynamicBean2. Il s'agit de la classe dans laquelle je souhaite le diffuser, mais lorsque j'essaie, j'obtiens l'exception ClassCastException.

Une raison pour laquelle je reçois ça?

51
Jaime Garcia

Je ne suis pas tout à fait en train de suivre votre description du flux de programme, mais généralement lorsque vous obtenez des ClassCastExceptions, vous ne pouvez pas expliquer que vous avez chargé la classe avec un chargeur de classe, puis essayez de la convertir dans la même classe chargée par un autre chargeur de classe. Cela ne fonctionnera pas - ils sont représentés par deux objets Class différents à l'intérieur de la machine virtuelle Java et la conversion échouera.

Il y a un article sur le chargement de classe dans WebSphere . Je ne peux pas dire comment cela s'applique à votre demande, mais il existe un certain nombre de solutions possibles. Je pense au moins à:

  1. Modifiez le chargeur de classe de contexte manuellement. Nécessite que vous puissiez réellement obtenir une référence à un chargeur de classe approprié, ce qui peut ne pas être possible dans votre cas.

    Thread.currentThread().setContextClassLoader(...);
    
  2. Assurez-vous que la classe est chargée par un chargeur de classe plus haut dans la hiérarchie.

  3. Sérialiser et désérialiser l'objet. (Beurk!)

Il existe cependant un moyen plus approprié pour votre situation particulière.

57
waxwing

Les objets de classe ont été chargés dans différents chargeurs de classe, par conséquent, les instances créées à partir de chacune des classes sont considérées comme "incompatibles". Il s'agit d'un problème courant dans un environnement où de nombreux chargeurs de classe différents sont utilisés et où des objets sont transmis. Ces problèmes peuvent facilement survenir dans les environnements Java EE et portail).

La conversion d'une instance d'une classe nécessite que la classe liée à l'objet converti soit la même que celle chargée par le chargeur de classe de contexte de thread actuel.

12
Robin

J'ai eu le problème A2AClassCastException en essayant de créer une liste d'objets à partir de XML à l'aide d'Apache Commons Digester.

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
}

Comme indiqué ci-dessus, la cause est que le digesteur n'utilise pas le même ClassLoader que le reste du programme. J'ai exécuté ceci dans JBoss, et il s'est avéré que commons-digester.jar n'était pas dans le répertoire lib de JBoss, mais plutôt dans le répertoire lib d'une webapp. La copie du pot dans mywebapp/WEB-INF/lib a également résolu le problème. Une autre solution était de casll digester.setClassLoader (MyTemplate.class.getClassLoader ()), mais cela semble être une solution assez laide dans ce contexte.

2
Emil Lundberg

Eu le même my.package.MyClass cannot be cast to my.package.MyClass sur WildFly 10.1 et, si je comprends bien, j'ai fait le contraire de ce que @Emil Lundberg a décrit dans sa réponse.

J'ai ajouté le module (qui contient my.package.MyClass) à my.war/WEB-INF/jboss-deployment-structure.xml comme dépendance

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

et supprimé le jar correspondant de my.war/WEB-INF/lib, a redéployé le WAR, puis le code a fonctionné comme prévu.

Ainsi, nous nous sommes assurés que cela résout le problème. Maintenant, nous devons nous assurer que le problème ne se reproduira pas, par exemple, lorsque la version mise à jour de WAR sera assemblée et déployée.

Pour cela, dans les sources de ces GUERRE , il faut ajouter <scope>provided</scope> pour ceux jar in pom.xml, de sorte que lorsque my.war est réassemblé la prochaine fois avec le code de correction/amélioration injecté, il ne regroupera pas cela jar dans my.war/WEB-INF/lib.

0
RAM237

J'ai eu le même problème et j'ai finalement trouvé une solution de contournement sur Java.net:

Tout copier org.Eclipse.persistence jar fichiers de glassfish4/glassfish/modules à WEB-INF/lib. Ensuite, allez dans votre glassfish-web.xml, Et mettre class-delegate à false.

A travaillé pour moi!

0
Adrien Dos Reis

J'ai eu le même problème avec une recherche EJB à partir d'un autre EJB. J'ai résolu d'ajouter @Remote (MyInterface.class) à la configuration de la classe EJB

0
user3402702

J'ai eu le même problème lors de l'utilisation de plusieurs instances JBoss sur différentes machines. Dommage, je ne suis pas tombé sur ce post plus tôt.
.

Pourquoi le ClassCastException levé ne mentionne-t-il pas les chargeurs de classe impliqués? - Je pense que ce serait une information très utile.
Quelqu'un sait-il si quelque chose de ce genre sera disponible à l'avenir? La nécessité de vérifier les chargeurs de classe de 20-30 artefacts n'est pas si agréable. Ou y a-t-il quelque chose que j'ai manqué dans le texte d'exception?

[~ # ~] edit [~ # ~] : J'ai édité le fichier META-INF/jboss-app.xml et changé le nom du chargeur , l'idée est d'avoir un nom unique. Au travail, nous utilisons l'ID d'artefact (unique) combiné à la version insérée par maven ({$ version}) lors de la construction.
L'utilisation de champs dynamiques est uniquement facultative mais utile si vous souhaitez déployer différentes versions de la même application.

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

Vous pouvez trouver quelques informations ici: https://community.jboss.org/wiki/ClassLoadingConfiguration

0
Andrei

Une autre option:

Cela m'est arrivé dans weblogic, mais je suppose que cela peut aussi arriver sur d'autres serveurs - si vous faites (juste) "Publier" et donc certaines de vos classes sont rechargées. À la place, faites "Clean" pour que toutes les classes soient rechargées ensemble.

0
Yogev Levy

J'ai eu un problème similaire avec JAXB et JBoss AS 7.1. Le problème et la solution sont décrits ici: javax.xml.bind.JAXBException: la classe *** ni aucune de ses super classes n'est connue dans ce contexte . L'exception qui a été donnée était org.foo.bar.ValueSet ne peut pas être convertie en org.foo.bar.ValueSet

0
John

J'obtenais ce problème après avoir ajouté une dépendance à spring-boot-devtools dans mon projet Springboot. J'ai supprimé la dépendance et le problème a disparu. Ma meilleure supposition à ce stade est que spring-boot-devtools apporte un nouveau chargeur de classe et cela provoque des problèmes de transtypage de classe entre différents chargeurs de classe dans certains cas où le nouveau chargeur de classe n'est pas utilisé par certains threads.

Référence: ne exception de carte de bulldozer liée aux devtools de démarrage de Spring

0
K.Nicholas

J'ai eu le même problème sur un EJB wildfly, l'EJB renvoyait une liste d'objets et a une interface distante et locale. J'ai utilisé l'interface locale par erreur ce qui fonctionnait très bien jusqu'au moment où vous essayez de lancer les objets dans la liste.

Interface locale/distante:

public interface DocumentStoreService {

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

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

Le bean EJB:

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

L'emballage de ressort correct autour de l'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>

Notez $ Remote, vous pouvez le changer en $ Local et il trouvera l'interface locale très bien, et exécutera également les méthodes sans aucun problème (à partir d'une application distincte sur le même conteneur), mais les objets du modèle ne sont pas marshalés et sont à partir d'un chargeur de classe différent si vous utilisez par erreur l'interface locale.

0
Meindert