[appengine-java] Re: ArrayIndexOutOfBoundsException when trying to persist an ArrayList of Objects which utilise inheritence
The only supported inheritance mapping strategy for polymorphic relationships is currently for JDO) new-table for the base class and superclass-table for all subclasses JPA) SingleTable. This means, everything in the inheritance hierarchy ends up in one entity kind, as you have noticed. Since we have an owned relationship, the entities (Car) get an ancestor key of the entity owning the relationship (Person). And the owning entity gets a property (cars) with all the keys of the entities in the list. And to get the java classes for the stored entities, when reading the data back, we have the discriminator. Example: One Person Entity [Person(1)]: (kind is “Person”) cars = [Person(1)/Car(2), Person(1)/Car(3)] name = Former F1 Champion with two Cars Entity [Person(1)/Car(2)]: (ancestor key Person(1), kind is “Car”) modelName = Ferrari DISCRIMINATOR = org.datanucleus.test.Model cars_INTEGER_IDX = 0 Entity [Person(1)/Car(3)]: (ancestor key Person(1), kind is “Car”) anotherModelName = Mercedes DISCRIMINATOR = org.datanucleus.test.AnotherModel cars_INTEGER_IDX = 1 Let's assume we would allow splitting the data of the elements of a relationship over more than one entity kind. To query the data store, with the low level Datastore API, to get the data for the cars owned by a person, you have basically the following options to formulate the queries (http://code.google.com/intl/de-DE/appengine/docs/java/ datastore/queries.html): 1) with a kind (e.g. Car, Model, AnotherModel, ...) and an ancestor key (key of the person owning the cars) = reading all Cars for a person means you have to execute a query for every entity kind involved in the inheritance hierarchy (would be five in your case) and then merge the results 2) no kind and no ancestor, but a filter on the entity keys in the list property (person.cars) = this would require a query with an IN filter, but the IN-queries are translated into multiple Equal-queries (http://gae-java- persistence.blogspot.com/2009/12/queries-with-and-in-filters.html), this in turn leads to a query for every entity in the list. 3) no kind but an ancestor key = this could also return entities not belonging to the relationship cars but to an another relationship of person(e.g. addresses). You would read too many entities and you would have to filter out all entities not belonging to this relationship. 2) no kind and no ancestor = this would require only one query, but the query would return all entities from your data store and you have to filter them in memory, I guess this is totally out of the question. The probably most performant solution here is to forbid splitting up the data of a collection element over multiple entity kinds and execute one query with a kind and an ancestor. But there is catch. You cannot have two relationships with the same element class (at least not at the moment). This problem could be solved easily, if the entities for the collection elements would get another property which says to which relationship it belongs. But in my opinion, it would be even better, if the low level Datastore API would support (without the need to split the query) kindless queries with an ancestor key and an IN filter on “subkeys” of the ancestor key. This should be performant since, as I understand it, all the data of one entity group resides in one bigtable row. I hope this explanation makes it easier for you to see all your different cars stored in one entity kind. And if you want to save a little space, you can take advantage of a discriminator map, and annotate your classes the following way: @PersistenceCapable() @Discriminator(column = D, strategy = DiscriminatorStrategy.VALUE_MAP) public abstract class Car { … } @PersistenceCapable @Discriminator(value = M) public class Model extends Car { …} Rolf On 8 Aug., 20:43, mscwd01 mscw...@gmail.com wrote: This worked nicely! One question I do have is, I noticed App Engine does not store Model kinds it instead stores Car kinds with a String DISCRIMINATOR property that stores what type of Class it is. Is it not possible to store Model entities? I actually have 5 Classes which extend Car and would have preferred to store an entity for each rather than have a Car kind comprising of each different class. Thanks for the help so far though! On Aug 8, 10:44 am, Rolf Aden mail.rolf.a...@googlemail.com wrote: It seems you are not using the latest sdk version (be something pre 1.5.1?). As of release 1.5.1 polymorphic relationships are supported for the default inheritance strategy in JDO (new-table for the base class, and superclass-table for all subclasses) and JPA SingleTable. You may want to change Car to @PersistenceCapable @Discriminator(column = DISCRIMINATOR) public abstract class Car { } and keep Model @PersistenceCapable public class Model extends Car { ... } Rolf
[appengine-java] Re: ArrayIndexOutOfBoundsException when trying to persist an ArrayList of Objects which utilise inheritence
It seems you are not using the latest sdk version (be something pre 1.5.1?). As of release 1.5.1 polymorphic relationships are supported for the default inheritance strategy in JDO (new-table for the base class, and superclass-table for all subclasses) and JPA SingleTable. You may want to change Car to @PersistenceCapable @Discriminator(column = DISCRIMINATOR) public abstract class Car { } and keep Model @PersistenceCapable public class Model extends Car { ... } Rolf On 8 Aug., 01:35, mscwd01 mscw...@gmail.com wrote: Hey, I have 3 classes: Person, Car and Model. Person has an ArrayList property defined: ListCar cars; Car is an abstract class which class Model extends, I.e. @PersistenceCapable @Inheritance(strategy = InheritanceStrategy.SUBCLASS_TABLE) public abstract class Car { @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) protected Key key; public Car() { } } Model extends Car: @PersistenceCapable public class Model extends Car { public Model() { } } I load a Person object and create a new Car object, I.e. Person personObj = pm.getObjectById(Person.class, key); Car newCar = new Model(); I then try to persist the new Car by adding it to the cars property in the Person Class, I.e. personObj.getCars().add(newCar); However, when I try this App Engine throws the following exception: java.lang.ArrayIndexOutOfBoundsException: 0 at org.datanucleus.store.mapped.scostore.FKListStore.init(FKListStore.java: 133) at org.datanucleus.store.appengine.DatastoreFKListStore.init(DatastoreFKList Store.java: 41) at org.datanucleus.store.appengine.DatastoreManager.newFKListStore(DatastoreMa nager.java: 528) at org.datanucleus.store.mapped.MappedStoreManager.getBackingStoreForCollectio n(MappedStoreManager.java: 729) at org.datanucleus.store.mapped.MappedStoreManager.getBackingStoreForField(Map pedStoreManager.java: 646) at org.datanucleus.sco.backed.List.init(List.java:104) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAcce ssorImpl.java: 39) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstru ctorAccessorImpl.java: 27) at java.lang.reflect.Constructor.newInstance(Constructor.java:513) at com.google.appengine.tools.development.agent.runtime.Runtime.newInstance_(R untime.java: 112) at com.google.appengine.tools.development.agent.runtime.Runtime.newInstance(Ru ntime.java: 120) at org.datanucleus.util.ClassUtils.newInstance(ClassUtils.java:94) at org.datanucleus.sco.SCOUtils.newSCOInstance(SCOUtils.java:164) at org.datanucleus.store.mapped.mapping.AbstractContainerMapping.replaceFieldW ithWrapper(AbstractContainerMapping.java: 426) at org.datanucleus.store.mapped.mapping.CollectionMapping.postInsert(Collectio nMapping.java: 165) at org.datanucleus.store.appengine.DatastoreRelationFieldManager.runPostInsert MappingCallbacks(DatastoreRelationFieldManager.java: 217) at org.datanucleus.store.appengine.DatastoreRelationFieldManager.access $200(DatastoreRelationFieldManager.java:48) at org.datanucleus.store.appengine.DatastoreRelationFieldManager $1.apply(DatastoreRelationFieldManager.java:116) at org.datanucleus.store.appengine.DatastoreRelationFieldManager.storeRelation s(DatastoreRelationFieldManager.java: 81) at org.datanucleus.store.appengine.DatastoreFieldManager.storeRelations(Datast oreFieldManager.java: 955) at org.datanucleus.store.appengine.DatastorePersistenceHandler.storeRelations( DatastorePersistenceHandler.java: 546) at org.datanucleus.store.appengine.DatastorePersistenceHandler.insertPostProce ss(DatastorePersistenceHandler.java: 304) at org.datanucleus.store.appengine.DatastorePersistenceHandler.insertObjects(D atastorePersistenceHandler.java: 256) at org.datanucleus.store.appengine.DatastorePersistenceHandler.insertObject(Da tastorePersistenceHandler.java: 240) at org.datanucleus.state.JDOStateManagerImpl.internalMakePersistent(JDOStateMa nagerImpl.java: 3185) at org.datanucleus.state.JDOStateManagerImpl.makePersistent(JDOStateManagerImp l.java: 3161) at org.datanucleus.ObjectManagerImpl.persistObjectInternal(ObjectManagerImpl.j ava: 1298) at org.datanucleus.ObjectManagerImpl.persistObject(ObjectManagerImpl.java: 1170) at org.datanucleus.jdo.JDOPersistenceManager.jdoMakePersistent(JDOPersistenceM anager.java: 669) at org.datanucleus.jdo.JDOPersistenceManager.makePersistent(JDOPersistenceMana ger.java: 694) This sounds much like a similar question that was raised
[appengine-java] Re: ArrayIndexOutOfBoundsException when trying to persist an ArrayList of Objects which utilise inheritence
This sounds like it could be the issue, I'll go ahead and upgrade to the latest SDK tonight and see how I get on. Thanks Rolf On Aug 8, 10:44 am, Rolf Aden mail.rolf.a...@googlemail.com wrote: It seems you are not using the latest sdk version (be something pre 1.5.1?). As of release 1.5.1 polymorphic relationships are supported for the default inheritance strategy in JDO (new-table for the base class, and superclass-table for all subclasses) and JPA SingleTable. You may want to change Car to @PersistenceCapable @Discriminator(column = DISCRIMINATOR) public abstract class Car { } and keep Model @PersistenceCapable public class Model extends Car { ... } Rolf On 8 Aug., 01:35, mscwd01 mscw...@gmail.com wrote: Hey, I have 3 classes: Person, Car and Model. Person has an ArrayList property defined: ListCar cars; Car is an abstract class which class Model extends, I.e. @PersistenceCapable @Inheritance(strategy = InheritanceStrategy.SUBCLASS_TABLE) public abstract class Car { @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) protected Key key; public Car() { } } Model extends Car: @PersistenceCapable public class Model extends Car { public Model() { } } I load a Person object and create a new Car object, I.e. Person personObj = pm.getObjectById(Person.class, key); Car newCar = new Model(); I then try to persist the new Car by adding it to the cars property in the Person Class, I.e. personObj.getCars().add(newCar); However, when I try this App Engine throws the following exception: java.lang.ArrayIndexOutOfBoundsException: 0 at org.datanucleus.store.mapped.scostore.FKListStore.init(FKListStore.java: 133) at org.datanucleus.store.appengine.DatastoreFKListStore.init(DatastoreFKList Store.java: 41) at org.datanucleus.store.appengine.DatastoreManager.newFKListStore(DatastoreMa nager.java: 528) at org.datanucleus.store.mapped.MappedStoreManager.getBackingStoreForCollectio n(MappedStoreManager.java: 729) at org.datanucleus.store.mapped.MappedStoreManager.getBackingStoreForField(Map pedStoreManager.java: 646) at org.datanucleus.sco.backed.List.init(List.java:104) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAcce ssorImpl.java: 39) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstru ctorAccessorImpl.java: 27) at java.lang.reflect.Constructor.newInstance(Constructor.java:513) at com.google.appengine.tools.development.agent.runtime.Runtime.newInstance_(R untime.java: 112) at com.google.appengine.tools.development.agent.runtime.Runtime.newInstance(Ru ntime.java: 120) at org.datanucleus.util.ClassUtils.newInstance(ClassUtils.java:94) at org.datanucleus.sco.SCOUtils.newSCOInstance(SCOUtils.java:164) at org.datanucleus.store.mapped.mapping.AbstractContainerMapping.replaceFieldW ithWrapper(AbstractContainerMapping.java: 426) at org.datanucleus.store.mapped.mapping.CollectionMapping.postInsert(Collectio nMapping.java: 165) at org.datanucleus.store.appengine.DatastoreRelationFieldManager.runPostInsert MappingCallbacks(DatastoreRelationFieldManager.java: 217) at org.datanucleus.store.appengine.DatastoreRelationFieldManager.access $200(DatastoreRelationFieldManager.java:48) at org.datanucleus.store.appengine.DatastoreRelationFieldManager $1.apply(DatastoreRelationFieldManager.java:116) at org.datanucleus.store.appengine.DatastoreRelationFieldManager.storeRelation s(DatastoreRelationFieldManager.java: 81) at org.datanucleus.store.appengine.DatastoreFieldManager.storeRelations(Datast oreFieldManager.java: 955) at org.datanucleus.store.appengine.DatastorePersistenceHandler.storeRelations( DatastorePersistenceHandler.java: 546) at org.datanucleus.store.appengine.DatastorePersistenceHandler.insertPostProce ss(DatastorePersistenceHandler.java: 304) at org.datanucleus.store.appengine.DatastorePersistenceHandler.insertObjects(D atastorePersistenceHandler.java: 256) at org.datanucleus.store.appengine.DatastorePersistenceHandler.insertObject(Da tastorePersistenceHandler.java: 240) at org.datanucleus.state.JDOStateManagerImpl.internalMakePersistent(JDOStateMa nagerImpl.java: 3185) at org.datanucleus.state.JDOStateManagerImpl.makePersistent(JDOStateManagerImp l.java: 3161) at org.datanucleus.ObjectManagerImpl.persistObjectInternal(ObjectManagerImpl.j ava: 1298) at org.datanucleus.ObjectManagerImpl.persistObject(ObjectManagerImpl.java:
[appengine-java] Re: ArrayIndexOutOfBoundsException when trying to persist an ArrayList of Objects which utilise inheritence
This worked nicely! One question I do have is, I noticed App Engine does not store Model kinds it instead stores Car kinds with a String DISCRIMINATOR property that stores what type of Class it is. Is it not possible to store Model entities? I actually have 5 Classes which extend Car and would have preferred to store an entity for each rather than have a Car kind comprising of each different class. Thanks for the help so far though! On Aug 8, 10:44 am, Rolf Aden mail.rolf.a...@googlemail.com wrote: It seems you are not using the latest sdk version (be something pre 1.5.1?). As of release 1.5.1 polymorphic relationships are supported for the default inheritance strategy in JDO (new-table for the base class, and superclass-table for all subclasses) and JPA SingleTable. You may want to change Car to @PersistenceCapable @Discriminator(column = DISCRIMINATOR) public abstract class Car { } and keep Model @PersistenceCapable public class Model extends Car { ... } Rolf On 8 Aug., 01:35, mscwd01 mscw...@gmail.com wrote: Hey, I have 3 classes: Person, Car and Model. Person has an ArrayList property defined: ListCar cars; Car is an abstract class which class Model extends, I.e. @PersistenceCapable @Inheritance(strategy = InheritanceStrategy.SUBCLASS_TABLE) public abstract class Car { @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) protected Key key; public Car() { } } Model extends Car: @PersistenceCapable public class Model extends Car { public Model() { } } I load a Person object and create a new Car object, I.e. Person personObj = pm.getObjectById(Person.class, key); Car newCar = new Model(); I then try to persist the new Car by adding it to the cars property in the Person Class, I.e. personObj.getCars().add(newCar); However, when I try this App Engine throws the following exception: java.lang.ArrayIndexOutOfBoundsException: 0 at org.datanucleus.store.mapped.scostore.FKListStore.init(FKListStore.java: 133) at org.datanucleus.store.appengine.DatastoreFKListStore.init(DatastoreFKList Store.java: 41) at org.datanucleus.store.appengine.DatastoreManager.newFKListStore(DatastoreMa nager.java: 528) at org.datanucleus.store.mapped.MappedStoreManager.getBackingStoreForCollectio n(MappedStoreManager.java: 729) at org.datanucleus.store.mapped.MappedStoreManager.getBackingStoreForField(Map pedStoreManager.java: 646) at org.datanucleus.sco.backed.List.init(List.java:104) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAcce ssorImpl.java: 39) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstru ctorAccessorImpl.java: 27) at java.lang.reflect.Constructor.newInstance(Constructor.java:513) at com.google.appengine.tools.development.agent.runtime.Runtime.newInstance_(R untime.java: 112) at com.google.appengine.tools.development.agent.runtime.Runtime.newInstance(Ru ntime.java: 120) at org.datanucleus.util.ClassUtils.newInstance(ClassUtils.java:94) at org.datanucleus.sco.SCOUtils.newSCOInstance(SCOUtils.java:164) at org.datanucleus.store.mapped.mapping.AbstractContainerMapping.replaceFieldW ithWrapper(AbstractContainerMapping.java: 426) at org.datanucleus.store.mapped.mapping.CollectionMapping.postInsert(Collectio nMapping.java: 165) at org.datanucleus.store.appengine.DatastoreRelationFieldManager.runPostInsert MappingCallbacks(DatastoreRelationFieldManager.java: 217) at org.datanucleus.store.appengine.DatastoreRelationFieldManager.access $200(DatastoreRelationFieldManager.java:48) at org.datanucleus.store.appengine.DatastoreRelationFieldManager $1.apply(DatastoreRelationFieldManager.java:116) at org.datanucleus.store.appengine.DatastoreRelationFieldManager.storeRelation s(DatastoreRelationFieldManager.java: 81) at org.datanucleus.store.appengine.DatastoreFieldManager.storeRelations(Datast oreFieldManager.java: 955) at org.datanucleus.store.appengine.DatastorePersistenceHandler.storeRelations( DatastorePersistenceHandler.java: 546) at org.datanucleus.store.appengine.DatastorePersistenceHandler.insertPostProce ss(DatastorePersistenceHandler.java: 304) at org.datanucleus.store.appengine.DatastorePersistenceHandler.insertObjects(D atastorePersistenceHandler.java: 256) at org.datanucleus.store.appengine.DatastorePersistenceHandler.insertObject(Da tastorePersistenceHandler.java: 240) at org.datanucleus.state.JDOStateManagerImpl.internalMakePersistent(JDOStateMa nagerImpl.java: