2010-04-10 21 views
5

Je vois un message d'erreur bizarre et je cherche des idées sur ce que pourrait être le problème. Je suis un peu novice dans l'utilisation de l'APP.Brainstorming: Problème JPA étrange, peut-être classpath ou problème de version de pot?

J'ai une application où j'utilise Entity Manager Factory de Spring (LocalContainerEntityManagerFactoryBean), EclipseLink comme mon fournisseur ORM, connecté à une base de données MySQL et construit avec Maven. Je ne suis pas sûr si tout cela importe .....

Lorsque je déploie cette application à Glassfish, l'application fonctionne comme prévu.

Le problème est que j'ai créé un ensemble de tests unitaires autonomes à exécuter en dehors de Glassfish qui ne fonctionnent pas correctement. Je reçois l'erreur suivante (j'ai édité les noms de classe un peu)

com.xyz.abc.services.persistence.entity.MyEntity cannot be cast to com.xyz.abc.services.persistence.entity.MyEntity 

L'objet ne peut être lancé à une classe du même type? Comment cela peut-il être?

Voici un extrait du code qui est dans l'erreur

Query q = entityManager.createNamedQuery("MyEntity.findAll"); 
List entityObjects = q.getResultList(); 
for (Object entityObject: entityObjects) { 
    com.xyz.abc.services.persistence.entity.MyEntity entity = (com.xyz.abc.services.persistence.entity.MyEntity) entityObject; 

Auparavant, j'avais ce code qui a produit la même erreur:

CriteriaQuery cq = entityManager.getCriteriaBuilder().createQuery(); 
cq.select(cq.from(com.xyz.abc.services.persistence.entity.MyEntity.class)); 
List entityObjects = entityManager.createQuery(cq).getResultList(); 
for (Object entityObject: entityObjects) { 
    com.xyz.abc.services.persistence.entity.MyEntity entity = (com.xyz.abc.services.persistence.entity.MyEntity) entityObject; 

Ce code est question est le même que j'ai déployé sur le serveur.

est ici l'exception la plus interne si elle aide

Caused by: java.lang.ClassCastException: com.xyz.abc.services.persistence.entity.MyEntity cannot be cast to com.xyz.abc.services.persistence.entity.MyEntity 
    at com.xyz.abc.services.persistence.entity.factory.MyEntityFactory.createBeans(MyEntityFactory.java:47) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:115) 
    ... 37 more 

Je devine qu'il ya une jarre j'utilise dans Glassfish qui est différent de ceux que je utilise dans le test. J'ai regardé tous les pots que j'ai énumérés comme "fournis" et suis à peu près sûr qu'ils sont tous les mêmes de Glassfish. Faites-moi savoir si vous avez déjà vu ce problème étrange ou si vous avez des idées pour le corriger.

Répondre

5

Cela pourrait également être un problème de chargement de classe. La même définition de classe, chargée par deux chargeurs de classe différents, est vue comme des classes différentes par la JVM.

Vous pouvez essayer d'obtenir des informations sur les chargeurs de classes dans le jeu:

Query q = entityManager.createNamedQuery("MyEntity.findAll"); 
List entityObjects = q.getResultList(); 

ClassLoader loader1 = 
    com.xyz.abc.services.persistence.entity.MyEntity.getClass().getClassLoader(); 
System.out.println("MyEntity's class loader is " + loader1); 
for (Object entityObject: entityObjects) { 
    ClassLoader loader2 = entityObject.getClass().getClassLoader(); 
    System.out.println("Class loader of entity " + entityObject + " is " + loader2); 
} 

Au lieu de System.out.println vous pourriez bien sûr utiliser les appels à votre cadre de l'exploitation forestière préféré.

Voici a series of articles avec plus de détails sur le chargement des classes.

+0

Oui OK, cela semble être un problème. Voici la sortie: chargeur de classe MyEntity est le chargeur de classes de [email protected] MyEntity objet est org.springfr[email protected]16089a5 Maintenant, comment y remédier ??? Je vais creuser dans les articles que vous avez liés. – Vinnie

+1

@Vinnie Malheureusement, je ne connais pas les outils que vous utilisez, donc je ne peux pas vous aider plus concrètement. Bonne chance - vous en aurez besoin ... –

+1

OK, c'est probablement une erreur de débutant, mais votre suggestion (et la révélation sur l'utilisation de différents Classloaders localement) a conduit à une solution viable. Voyant qu'il y avait différents Classloaders en jeu, je pensais que le LocalContainerEntityManagerFactoryBean de Spring n'était pas le bon choix à utiliser lors de mes tests unitaires. Je suis passé à LocalEntityManagerFactoryBean (ce qui signifiait aussi que j'avais besoin d'une nouvelle unité de persistance puisque je ne pouvais pas injecter le DataSource) et les choses semblent fonctionner localement maintenant. Merci pour l'aide! – Vinnie

1

Cela sent clairement un problème ClassLoader (peut-être en raison du tissage requis par EclipseLink). Utilisez-vous le LoadTimeWeaver? Avez-vous des trucs javaagent configurés? Le problème se produit-il sur la ligne de commande sous Maven? dans votre IDE? Précisez s'il vous plaît.

+0

Bon point sur le tissage, je voulais le mentionner dans la question. J'utilise org.springframework.context.weaving.DefaultContextLoadTimeWeaver dans Glassfish et org.springframework.instrument.classloading.SimpleLoadTimeWeaver dans mes tests. Je ne savais pas lequel utiliser, alors je viens de choisir celui qui semblait fonctionner. – Vinnie

+0

BTW - Je n'ai aucun agent Java configuré. Et le problème se produit à la fois de la ligne de commande maven et de l'IDE. Le serveur Glassfish est le seul domaine où je ne vois pas le problème. – Vinnie