2010-04-10 6 views
5

Visualizzo un messaggio di errore strano e sto cercando alcune idee su quale potrebbe essere il problema. Sono un po 'nuovo nell'usare l'JPA.Brainstorming: strano problema con JPA, probabilmente classpath o jar versioning problem?

Ho un'applicazione in cui sto utilizzando Spring Entity Manager Factory (LocalContainerEntityManagerFactoryBean), EclipseLink come provider ORM, connesso a un DB MySQL e costruito con Maven. Non sono sicuro che tutto ciò sia importante ...

Quando distribuisco questa applicazione su Glassfish, l'applicazione funziona come previsto.

Il problema è che ho creato una serie di test di unità indipendenti per l'esecuzione all'esterno di Glassfish che non funzionano correttamente. Ottengo il seguente errore (Ho modificato i nomi di classe un po ')

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

L'oggetto non può essere lanciato ad una classe dello stesso tipo? Come può essere?

Ecco un frammento del codice che è in errore

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; 

In precedenza, ho avuto questo codice che ha prodotto lo stesso errore:

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; 

Questo codice è questione è lo stesso che ho distribuito al server.

Ecco l'eccezione più interna se aiuta

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 

sto indovinando che ci sia qualche vaso che sto utilizzando in Glassfish, che è diverso da quelli che sto utilizzando in prova. Ho esaminato tutti i vasi che ho elencato come "forniti" e sono abbastanza sicuro che siano tutti gli stessi di Glassfish.

Fammi sapere se hai già riscontrato questo strano problema o hai qualche idea per correggerlo.

risposta

5

Questo potrebbe anche essere un problema di caricamento di classe. La stessa definizione di classe, caricata da due diversi programmi di caricamento classe, è vista come una classe diversa dalla JVM.

Si potrebbe provare questo per ottenere informazioni sui caricatori di classe nel gioco:

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

Invece di System.out.println si potrebbe naturalmente utilizzare le chiamate al vostro quadro di registrazione preferito.

Ecco a series of articles con ulteriori dettagli sul caricamento della classe.

+0

Sì OK, questo sembra essere un problema. Ecco l'output: class loader di MyEntity è class loader [email protected] MyEntity dell'oggetto è org.springfr[email protected]16089a5 Ora come risolvere il problema ??? Ho intenzione di approfondire gli articoli a cui ti sei collegato. – Vinnie

+1

@Vinnie Purtroppo non ho familiarità con gli strumenti che si utilizzano, quindi non posso offrire un aiuto più concreto. Buona fortuna - ne avrai bisogno ... –

+1

OK, questo è probabilmente un errore da principiante, ma il tuo suggerimento (e la rivelazione sull'utilizzo di diversi Classloader localmente) ha portato a una soluzione praticabile. Vedere che c'erano diversi Classloader in gioco mi ha fatto pensare che Spring's LocalContainerEntityManagerFactoryBean non fosse la scelta giusta da usare durante i miei test unitari. Sono passato a LocalEntityManagerFactoryBean (il che significava anche che avevo bisogno di una nuova unità di persistenza poiché non potevo iniettare DataSource) e le cose sembrano funzionare localmente ora. Grazie per l'aiuto! – Vinnie

1

Questo emette chiaramente un problema di ClassLoader (probabilmente dovuto alla tessitura richiesta da EclipseLink). Usi lo LoadTimeWeaver? Hai configurato qualcosa di javaagent? Il problema si verifica nella riga di comando di Maven? nel tuo IDE? Si prega di precisare.

+0

Un buon punto sulla tessitura, intendevo menzionarlo nella domanda. Sto usando org.springframework.context.weaving.DefaultContextLoadTimeWeaver in Glassfish e org.springframework.instrument.classloading.SimpleLoadTimeWeaver nei miei test. Non ero sicuro di quale usare, quindi ne ho scelto uno che sembrava funzionare. – Vinnie

+0

BTW - Non ho configurato javaagent. E il problema si verifica sia dalla riga di comando di Maven che dall'ID. Il server Glassfish è l'unica area in cui non vedo il problema. – Vinnie