ClassCastException when trying to add child to parent in owned one to many. (using jdo on google appengine)

google-app-engine, google-cloud-datastore, java, jdo

Solution

i dont think you are doing anything wrong. this seems to be a bug with the vendor code. see this link. there isnt a whole lot of info, but they intimate that the PK on your type `Long` Employee.id is problematic.

Problem

I need some help figuring out what I'm doing wrong here. I am trying to master one to many relationships and running into a roadblock. I tried to modify the Employee and ContactInfo example to do one to many mappings: Everything works if I create both the parent (employee) and child (Contact) and then call makePersistent. But if I try to add a child object to an already persistent parent, I get a java.lang.ClassCast exception. The full stack trace is at the bottom of the post. Here is the code that breaks (If I move the makePersistent() call to after the add(), everything works fine: ``` public void testOneToMany(){ pm = newPM(); Employee e = new Employee("peter"); pm.makePersistent(e); Contact c = new Contact("123 main"); List<Contact> contacts = e.getContacts(); contacts.add(c); // here I get java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.String } ``` Here is the parent class ``` @PersistenceCapable(identityType = IdentityType.APPLICATION) public class Employee { @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) private Long id; @Persistent private String name; @Persistent(mappedBy="employee") private List<Contact> contacts; public Employee(String e){ contacts = new ArrayList<Contact>(); name = e; } List<Contact> getContacts(){ return contacts; } Long getId(){ return id; } public String getName(){ return name; } } ``` Here is the child class ``` @PersistenceCapable(identityType = IdentityType.APPLICATION) public class Contact { @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) private Key key; @Persistent private String streetAddress; @Persistent private Employee employee; public Contact(String s){ streetAddress = s; } public String getAddress(){ return streetAddress; } public Employee getEmployee(){ return employee; } } ``` Here's the full stacktrace: ``` java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.String at org.datanucleus.store.appengine.DatastoreRelationFieldManager $1.setObjectViaMapping(DatastoreRelationFieldManager.java:148) at org.datanucleus.store.appengine.DatastoreRelationFieldManager $1.apply(DatastoreRelationFieldManager.java:108) at org.datanucleus.store.appengine.DatastoreRelationFieldManager.storeRelations (DatastoreRelationFieldManager.java:80) at org.datanucleus.store.appengine.DatastoreFieldManager.storeRelations (DatastoreFieldManager.java:770) at org.datanucleus.store.appengine.DatastorePersistenceHandler.insertObject (DatastorePersistenceHandler.java:231) at org.datanucleus.state.JDOStateManagerImpl.internalMakePersistent (JDOStateManagerImpl.java:3067) at org.datanucleus.state.JDOStateManagerImpl.makePersistent (JDOStateManagerImpl.java:3043) at org.datanucleus.ObjectManagerImpl.persistObjectInternal (ObjectManagerImpl.java:1258) at org.datanucleus.sco.SCOUtils.validateObjectForWriting (SCOUtils.java:1365) at org.datanucleus.store.mapped.scostore.ElementContainerStore.validateElementForWriting (ElementContainerStore.java:401) at org.datanucleus.store.mapped.scostore.FKListStore.validateElementForWriting (FKListStore.java:764) at org.datanucleus.store.mapped.scostore.FKListStore.internalAdd (FKListStore.java:503) at org.datanucleus.store.mapped.scostore.AbstractListStore.add (AbstractListStore.java:123) at org.datanucleus.sco.backed.List.add(List.java:752) at com.btg.plyus.scratch.JDOTest.testOneToMany(JDOTest.java:33) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at junit.framework.TestCase.runTest(TestCase.java:168) at com.btg.plyus.test.BaseTest.runTest(BaseTest.java:79) at junit.framework.TestCase.runBare(TestCase.java:134) at junit.framework.TestResult$1.protect(TestResult.java:110) at junit.framework.TestResult.runProtected(TestResult.java:128) at junit.framework.TestResult.run(TestResult.java:113) at junit.framework.TestCase.run(TestCase.java:124) at junit.framework.TestSuite.runTest(TestSuite.java:232) at junit.framework.TestSuite.run(TestSuite.java:227) at org.junit.internal.runners.OldTestClassRunner.run (OldTestClassRunner.java:76) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run (JUnit4TestReference.java:45) at org.eclipse.jdt.internal.junit.runner.TestExecution.run (TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests (RemoteTestRunner.java:460) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests (RemoteTestRunner.java:673) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run (RemoteTestRunner.java:386) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main (RemoteTestRunner.java:196) ```

Original source