|
[
Permlink
| « Hide
]
Marc Prud'hommeaux added a comment - 06/Sep/06 09:42 PM
Fix the ClassLoader issue by falling back to the parameter's ClassLoader in the event of a NoSuchMethodError. I am seeing a subsequent ClassCircularityError from the test case, but that might be a platform issue (I am using OS X). I'd be interested in seeing if the error occurs for the reporter: if so, please re-open this JIRA issue or else make a new one.
Marc,
Thanks for the quick fix - we are at least one step closer :) I'm also running under OS X and I do get the exception you mentioned - java.lang.ClassCircularityError: springdeveloper/domain/Manager Not sure if this is a Spring or OpenJPA issue yet though. I'll reopen this case if we need to. Thanks again. I don't think it's Spring here. Spring LoadTimeWeaver helps implement the JPA transformation contract - allow transformers to be registered and offer two classloaders for loading classes - one which loads them in pure form (the ThrowawayClassloader) and one to load them enhanced.
By looking at the stacktrace, I think that either the appropriate classloader is not used or the transformation is applied twice (maybe because it is registered twice). Re-opening.
For the record, the exception I am seeing is: 945 WARN [main] openjpa.Enhance - An exception was thrown while attempting to perform class file transformation on "springdeveloper/domain/Manager": java.lang.ClassCircularityError: springdeveloper/domain/Manager at java.lang.Class.getDeclaredFields0(Native Method) at java.lang.Class.privateGetDeclaredFields(Class.java:2232) at java.lang.Class.getDeclaredFields(Class.java:1715) at org.apache.openjpa.meta.AbstractMetaDataDefaults.populateFromReflection(AbstractMetaDataDefaults.java:178) at org.apache.openjpa.meta.AbstractMetaDataDefaults.populate(AbstractMetaDataDefaults.java:128) at org.apache.openjpa.persistence.PersistenceMetaDataDefaults.populate(PersistenceMetaDataDefaults.java:182) at org.apache.openjpa.meta.MetaDataRepository.addMetaData(MetaDataRepository.java:736) at org.apache.openjpa.persistence.XMLPersistenceMetaDataParser.startClass(XMLPersistenceMetaDataParser.java:720) at org.apache.openjpa.lib.meta.CFMetaDataParser.startElement(CFMetaDataParser.java:101) at org.apache.openjpa.lib.meta.XMLMetaDataParser.startElement(XMLMetaDataParser.java:427) at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.startElement(AbstractSAXParser.java:533) at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.startElement(XMLSchemaValidator.java:708) at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(XMLNSDocumentScannerImpl.java:330) at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(XMLDocumentFragmentScannerImpl.java:1693) at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:368) at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:834) at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:764) at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:148) at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1242) at javax.xml.parsers.SAXParser.parse(SAXParser.java:375) at org.apache.openjpa.lib.meta.XMLMetaDataParser.parseNewResource(XMLMetaDataParser.java:371) at org.apache.openjpa.lib.meta.XMLMetaDataParser.parse(XMLMetaDataParser.java:312) at org.apache.openjpa.lib.meta.XMLMetaDataParser.parse(XMLMetaDataParser.java:289) at org.apache.openjpa.lib.meta.XMLMetaDataParser.parse(XMLMetaDataParser.java:263) at org.apache.openjpa.persistence.PersistenceMetaDataFactory.parseXML(PersistenceMetaDataFactory.java:237) at org.apache.openjpa.persistence.PersistenceMetaDataFactory.load(PersistenceMetaDataFactory.java:188) at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:432) at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:287) at org.apache.openjpa.enhance.PCEnhancer.<init>(PCEnhancer.java:164) at org.apache.openjpa.enhance.PCClassFileTransformer.transform(PCClassFileTransformer.java:115) at org.apache.openjpa.persistence.PersistenceProviderImpl$ClassTransformerImpl.transform(PersistenceProviderImpl.java:132) at org.springframework.orm.jpa.ClassFileTransformerAdapter.transform(ClassFileTransformerAdapter.java:56) at org.springframework.instrument.classloading.WeavingTransformer.transformIfNecessary(WeavingTransformer.java:102) at org.springframework.instrument.classloading.WeavingTransformer.transformIfNecessary(WeavingTransformer.java:83) at org.springframework.instrument.classloading.SimpleInstrumentableClassLoader.transformIfNecessary(SimpleInstrumentableClassLoader.java:56) at org.springframework.instrument.classloading.AbstractOverridingClassLoader.loadClass(AbstractOverridingClassLoader.java:95) at java.lang.ClassLoader.loadClass(ClassLoader.java:251) at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:242) at org.apache.openjpa.meta.MetaDataRepository.classForName(MetaDataRepository.java:1156) at org.apache.openjpa.meta.MetaDataRepository.loadPersistentTypes(MetaDataRepository.java:1144) at org.apache.openjpa.kernel.AbstractBrokerFactory.loadPersistentTypes(AbstractBrokerFactory.java:218) at org.apache.openjpa.kernel.AbstractBrokerFactory.newBroker(AbstractBrokerFactory.java:175) at org.apache.openjpa.kernel.DelegatingBrokerFactory.newBroker(DelegatingBrokerFactory.java:139) at org.apache.openjpa.persistence.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:171) at org.apache.openjpa.persistence.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:124) 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:585) at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean$ManagedEntityManagerFactoryInvocationHandler.invoke(AbstractEntityManagerFactoryBean.java:354) at $Proxy0.createEntityManager(Unknown Source) at springdeveloper.TestApp.run(TestApp.java:60) at springdeveloper.TestApp.main(TestApp.java:31) This is a pretty hairy problem. The ClassCircularityError is coming from the fact that there are two different ClassLoaders in place: a org.springframework.instrument.classloading.SimpleThrowawayClassLoader, which is being used for temporary loading in the premain, and a org.springframework.instrument.classloading.SimpleInstrumentableClassLoader, which is being used to actually load the post-enhanced classes. The Manager and Client classes have a dependency on each other, and when Manager is loaded by SimpleThrowawayClassLoader, its metadata gets parsed, which causes Client to be transitively loaded. However, the XMLPersistenceMetaDataParser being used by our PersistenceMetaDataFactory is being configured with setClassLoader() using the SimpleInstrumentableClassLoader, rather than the SimpleThrowawayClassLoader. When Client's metadata is parsed, it then tries to load Manager in the SimpleInstrumentableClassLoader, which causes a re-entrant attempt to load Manager in SimpleThrowawayClassLoader, which is what I believe is causing the ClassCircularityError.
This can be fixed by changing "xmlParser.setClassLoader(loader)" to instead call "xmlParser.setClassLoader(envLoader)". However, if that happens, then the PersistenceCapable interface itself winds up getting loaded by the SimpleInstrumentableClassLoader, which later causes a mismatch with the interface with other classes (like ClassMetaData) that are loaded using the system AppClassLoader. Has Spring been tested with any other JPA implementations that use bytecode enhancement at runtime? On one hand, OpenJPA is working fine with Glassfish, on the other hand, the Glassfish samples we have tested against use annotation mappings, rather than XML mappings, so the problem might lie there. I just tested using entity-only annotations, and the same problem exists: the org.apache.openjpa.enhance.PersistenceCapable interface that the enhanced springdeveloper.domain.Client classes uses is being loaded by org.springframework.instrument.classloading.SimpleInstrumentableClassLoader, but the classloader that the PersistenceCapable interface referenced by core OpenJPA classes (like ClassMetaData) uses is a sun.misc.Launcher$AppClassLoader. It is almost like SimpleInstrumentableClassLoader is not delegating to the parent classloader or something.
I've committed the class loading fix. In addition to that, we need some way to exclude the openjpa classes from being instrumented. The only way I could think of doing that is to write a OpenJpaLoadTimeWeaver to do it, which I've attached to this issue. If you include it in the repository-config.xml as follows:
<property name="loadTimeWeaver"> <!-- <bean class="org.springframework.instrument.classloading.SimpleLoadTimeWeaver"/> --> <bean class="org.springframework.orm.jpa.vendor.OpenJpaLoadTimeWeaver"/> </property> then the class loading should work. Finally, there is an error in the orm.xml mapping file that OpenJPA has problems with: the "attribute-override" mapping for Manager says to override the "description" mapping, but "description" is defined in Manager, not in any mapped superclass of Manager. AFAIK, attribute-override is only supposed to be used to override superclass mappings, not mappings in the entity itself. So, in summary, I've gotten the sample to work by doing the following: 1. Put OpenJpaLoadTimeWeaver.java in the src/org/springframework/orm/jpa/vendor/ directory 2. Add OpenJpaLoadTimeWeaver as the "loadTimeWeaver" in repository-config.xml 3. Remove the "attribute-override" element from src/META-INF/orm.xml Once all these are done, the sample runs for me. I'll be interested in seing if it works for you, and what your opinion is on whether the OpenJpaLoadTimeWeaver is the best way to resolve the class loading issue. I made the changes you suggested and I can now run the test relying only on annotations. As soon as I involve an orm.xml in combination with the annotations I see errors - see
Thanks. To my knowledge, this has been resolved.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||