Issue with a relationship to an interface
The problem seemed to be intermittent when we had the implementing class in a different package. Once we moved it into the same package it didn't happen again - but on another dev machine it worked fine while in the different package - strange.
Anyway, the DataNucleus docs do mention some non deterministic behaviour if the metadata of implementations is not experienced prior to experiencing the class with the relationship to the interface. The docs say to avoid this non deterministic behaviour specify the implementation classes in the metadata (which we have now done) eg. field-type="com.sas.blah.blah.ImplementationClass" Everything seems to go just swimmingly now :) (because terms from the 1920s need a revival...) I still think the change in the pull request would be useful to anyone else who finds themselves in this situation as it helps to narrow down the exact class+attribute causing the issue. |
|
Page bloom
When I ran my app against a version of dn-rdbms with this change (pull request created) it revealed, for the first time, which PC class + attribute was causing the issue that resulted in the exception.
So at least this change enables me to drastically reduce the scope of my search for the root cause :) (which is still a bit of a mystery at the moment) |
|
It would be best to work out where the problem is in your mapping+classes and hence why you get some problem. Once you see that then you can put a trap at the root cause. Aka work backwards from where you are looking
|
|
Page bloom
I'm now actually getting this exception in the main app during start up.
I'm not sure if I've got the logging setup correctly (recently switched to Log4j 2 and unsure how to use the DataNucleus categories in that version) but the exception is thrown without giving any indication which class or attribute is causing the issue: Failed to generate new Mapping of type org.datanucleus.store.rdbms.mapping.java.InterfaceMapping, exception : org.datanucleus.store.rdbms.mapping.java.SerialisedMapping cannot be cast to org.datanucleus.store.rdbms.mapping.java.PersistableMapping
java.lang.ClassCastException: org.datanucleus.store.rdbms.mapping.java.SerialisedMapping cannot be cast to org.datanucleus.store.rdbms.mapping.java.PersistableMapping
at org.datanucleus.store.rdbms.table.ColumnCreator.createColumnsForField(ColumnCreator.java:308)
at org.datanucleus.store.rdbms.mapping.java.ReferenceMapping.createPerImplementationColumnsForReferenceField(ReferenceMapping.java:488)
at org.datanucleus.store.rdbms.mapping.java.ReferenceMapping.prepareDatastoreMapping(ReferenceMapping.java:230)
at org.datanucleus.store.rdbms.mapping.java.ReferenceMapping.initialize(ReferenceMapping.java:104)
at org.datanucleus.store.rdbms.mapping.java.InterfaceMapping.initialize(InterfaceMapping.java:52)
at org.datanucleus.store.rdbms.mapping.MappingManagerImpl.getMapping(MappingManagerImpl.java:667)
at org.datanucleus.store.rdbms.table.ClassTable.manageMembers(ClassTable.java:549)
at org.datanucleus.store.rdbms.table.ClassTable.manageClass(ClassTable.java:455)
at org.datanucleus.store.rdbms.RDBMSStoreManager$ClassAdder.initializeClassTables(RDBMSStoreManager.java:3347)
at org.datanucleus.store.rdbms.RDBMSStoreManager$ClassAdder.run(RDBMSStoreManager.java:2961)
at org.datanucleus.store.rdbms.AbstractSchemaTransaction.execute(AbstractSchemaTransaction.java:118)
at org.datanucleus.store.rdbms.RDBMSStoreManager.manageClasses(RDBMSStoreManager.java:1672)
The code where the above exception is raised is in: ColumnCreator#createColumnsForField (line 308) ((PersistableMapping)container).addJavaTypeMapping(refDatastoreMapping); <--- Cast fails
Once the exception is raised it is handled at a higher level where, presumably, specific field information is no longer available. Would it be viable to test if container was an instanceof 'PersistableMapping' and throw a DN exception if not, passing in the field data? eg if (container instanceof PersistableMapping) ((PersistableMapping)container).addJavaTypeMapping(refDatastoreMapping);
else
throw new NucleusUserException("Cannot create column for field " + mmd.getFullFieldName()); or is it best to wrap it in a try/catch?
try{ ((PersistableMapping)container).addJavaTypeMapping(refDatastoreMapping);
} catch(ClassCastException cce) { throw new NucleusUserException("Cannot create column for field " + mmd.getFullFieldName(), cce); } |
|
Page bloom
Ah doh!
That stack dump must have been when I reverted to 4.x to test it in that version and I've now gone back to 5.x. RDBMSMappingManager is obviously a Version 4.x class and renamed to something else in 5.x. Sorry, my bad! |
|
I meant the class that YOUR stack trace quotes. In current codebase there is no such class (but there is MappingManagerImpl). In whatever version you're using there is that class.
|
|
Page bloom
On Wed, Mar 21, 2018 at 12:00 am, Andy wrote:
RDBMSMappingManagerI can't find that specific class. Did you mean MappingManagerImpl in the *.rdbms package? |
|
Page bloom
I'm planning to create a minimalist class model that demonstrates the issue - but, as usual with our massive model, it will take some time to work out the minimalist chunk of it that exhibits the issue. datanucleus.generateSchema.database.mode=create is present or commented out. |
|
So demonstrate it or otherwise get the code for datanucleus-rdbms and debug from RDBMSMappingManager as to why it is choosing that type
|
|
Page bloom
I'm in the very early stages of debugging a unit test that is failing with an exception when establishing a PMF for a model that has classes with references to interfaces.
<field name="subscribable" persistence-modifier="persistent"> <extension vendor-name="datanucleus" key="mapping-strategy" value="per-implementation"/> </field> I can't work out why it is trying to create a SerialisedMapping for this and then complains that it can't be cast to PeristableMapping - it seems to be straddling both worlds, maybe due to some weirdness in our metadata.
setup really failed: javax.jdo.JDOFatalInternalException: Failed to generate new Mapping of type org.datanucleus.store.rdbms.mapping.java.InterfaceMapping, exception : org.datanucleus.store.rdbms.mapping.java.SerialisedMapping cannot be cast to org.datanucleus.store.rdbms.mapping.java.PersistableMapping
java.lang.ClassCastException: org.datanucleus.store.rdbms.mapping.java.SerialisedMapping cannot be cast to org.datanucleus.store.rdbms.mapping.java.PersistableMapping
at org.datanucleus.store.rdbms.table.ColumnCreator.createColumnsForField(ColumnCreator.java:261)
at org.datanucleus.store.rdbms.mapping.java.ReferenceMapping.createPerImplementationColumnsForReferenceField(ReferenceMapping.java:488)
at org.datanucleus.store.rdbms.mapping.java.ReferenceMapping.prepareDatastoreMapping(ReferenceMapping.java:230)
at org.datanucleus.store.rdbms.mapping.java.ReferenceMapping.initialize(ReferenceMapping.java:104)
at org.datanucleus.store.rdbms.mapping.java.InterfaceMapping.initialize(InterfaceMapping.java:52)
at org.datanucleus.store.rdbms.mapping.RDBMSMappingManager.getMapping(RDBMSMappingManager.java:482)
at org.datanucleus.store.rdbms.table.ClassTable.manageMembers(ClassTable.java:536)
at org.datanucleus.store.rdbms.table.ClassTable.manageClass(ClassTable.java:442)
at org.datanucleus.store.rdbms.table.ClassTable.initializeForClass(ClassTable.java:1270)
at org.datanucleus.store.rdbms.table.ClassTable.initialize(ClassTable.java:276)
at org.datanucleus.store.rdbms.RDBMSStoreManager$ClassAdder.initializeClassTables(RDBMSStoreManager.java:3279)
at org.datanucleus.store.rdbms.RDBMSStoreManager$ClassAdder.run(RDBMSStoreManager.java:2889)
at org.datanucleus.store.rdbms.AbstractSchemaTransaction.execute(AbstractSchemaTransaction.java:119)
at org.datanucleus.store.rdbms.RDBMSStoreManager.createSchemaForClasses(RDBMSStoreManager.java:3877)
at org.datanucleus.store.schema.SchemaTool.createSchemaForClasses(SchemaTool.java:499)
at org.datanucleus.PersistenceNucleusContextImpl.initialiseSchema(PersistenceNucleusContextImpl.java:953)
at org.datanucleus.PersistenceNucleusContextImpl.initialise(PersistenceNucleusContextImpl.java:481)
at org.datanucleus.api.jdo.JDOPersistenceManagerFactory.freezeConfiguration(JDOPersistenceManagerFactory.java:817)
at org.datanucleus.api.jdo.JDOPersistenceManagerFactory.createPersistenceManagerFactory(JDOPersistenceManagerFactory.java:334)
at org.datanucleus.api.jdo.JDOPersistenceManagerFactory.getPersistenceManagerFactory(JDOPersistenceManagerFactory.java:213)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at javax.jdo.JDOHelper$16.run(JDOHelper.java:1975)
at java.security.AccessController.doPrivileged(Native Method)
at javax.jdo.JDOHelper.invoke(JDOHelper.java:1970)
at javax.jdo.JDOHelper.invokeGetPersistenceManagerFactoryOnImplementation(JDOHelper.java:1177)
at javax.jdo.JDOHelper.getPersistenceManagerFactory(JDOHelper.java:814)
at javax.jdo.JDOHelper.getPersistenceManagerFactory(JDOHelper.java:702) |
|