
Objective
This article will show you how to persist real world data in Google App Engine. You will learn how to handle inheritance and one-to-many owned relationships in your model objects and store them correctly in the big table implementation of JDO.
The Problem Domain
In my application I need to segregate data by the customer this data belongs to. We will use inheritance in model objects, so all of them will have customer id defined in the base class. We will make the JDO save base class properties in the sub class “table”. We will also learn how to instruct Google App Engine JDO to handle customers with multiple addresses and phone numbers for us. If we define the relationship between model objects correctly JDO will manage storing/retrieving/deleting of these lined objects without our involvement.
Inheritance in Model Classes
First let’s define a superclass for all our model classes:
package com.yourcorp.here; import java.io.Serializable; import javax.jdo.annotations.IdGeneratorStrategy; import javax.jdo.annotations.IdentityType; import javax.jdo.annotations.Inheritance; import javax.jdo.annotations.InheritanceStrategy; import javax.jdo.annotations.PersistenceCapable; import javax.jdo.annotations.Persistent; import javax.jdo.annotations.PrimaryKey; @PersistenceCapable(identityType = IdentityType.APPLICATION, detachable="true") @Inheritance(strategy=InheritanceStrategy.SUBCLASS_TABLE) public class ModelBase implements Serializable{ @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) private Long id; @Persistent protected Long customerId; private static final long serialVersionUID = 3039288063578312662L; // getters & setters go here }
What we done here is defined Model Base class that has two properties – ID and customerID and marked them as persistent. We also annotated that our class is persistence capable and defined Inheritance strategy. In this case we chose to use Subclass Table. What this means is that ID and customerID properties will be saved in the table of the class that inherits this one. You can read more about inheritance strategies here.
Now lets define our User class:
package com.yourcorp.here; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import javax.jdo.annotations.IdentityType; import javax.jdo.annotations.PersistenceCapable; import javax.jdo.annotations.Persistent; @PersistenceCapable(identityType = IdentityType.APPLICATION, detachable="true") public class User extends ModelBase implements Serializable { @Persistent private String email; @Persistent private String name; @Persistent private String password; private static final long serialVersionUID = 3039288063578312662L; // getters & setters go here }
When you persist an instance of this User class in the big table it will have id, customerId, email, name and password properties in the single user “table”.
One-to-many relationships in Google App Engine JDO
For this example lets define a customer class that has a list on phone and address objects:
package com.yourcorp.here; import java.util.ArrayList; import java.util.List; import javax.jdo.annotations.IdentityType; import javax.jdo.annotations.PersistenceCapable; import javax.jdo.annotations.Persistent; import javax.jdo.annotations.Element; @PersistenceCapable(identityType = IdentityType.APPLICATION, detachable="true") public class Customer extends ModelBase { @Persistent private String name; @Persistent private String contactName; @Persistent private String comments; @Persistent(mappedBy = "customer") @Element(dependent = "true") private List<Address> adresses = new ArrayList<Address>(); @Persistent(mappedBy = "customer") @Element(dependent = "true") private List phones = new ArrayList(); private static final long serialVersionUID = 3039288063578312662L; // getters & setters go here }
As you can tell we have defined two lists and annotated them to be persistent. (mappedBy = “customer”) defines this relationship as “owned” – meaning the customer property of the Address and Phone object will hold the reference tho this customer object.
And here is an example of the address object:
package com.yourcorp.here; import javax.jdo.annotations.IdentityType; import javax.jdo.annotations.PersistenceCapable; import javax.jdo.annotations.Persistent; @PersistenceCapable(identityType = IdentityType.APPLICATION, detachable="true") public class Address extends EntityBase { @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) private Key id; @Persistent private String type; @Persistent private String name; @Persistent private String line1; @Persistent private String line2; @Persistent private String city; @Persistent private String state; @Persistent private String zip; @Persistent private Customer customer; private static final long serialVersionUID = 3039288063578312662L; // getters & setters go here }
You may also notice @Element(dependent = “true”) which means that when the customer object is deleted JDO will delete these child objects for you automatically.
Conclusion
JDO simplifies your life when you need to store and retrieve data if you know how to define all these relationships correctly. Compare the effort required to store and retrieve the same object from your favorite relational database, without using the monster called hibernate……


















Hi Tomas,
very good post.
The only thing I didn’t get here is why did you need the Serializable implementation…
Could you explain?
Sincerely,
Alex
Alexander,
For the purpose of this example you do not need to implement Serializable. I copied code form a bigger project where I serialize objects over the wire to the client app and back.
Thanks,
Tomas
Tomas,
could you help me a bit if you have time?
yesterday I was trying to model a simple forum comments. Just a
comments which you can add more comments to.
So, the approximation of the entity is like this:
——————————————————————-
@PersistenceCapable (detachable = “true”, identityType =
IdentityType.APPLICATION)
public class CommentEntity {
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
@Persistent
private String category;
@Persistent
private String commentDate;
@Persistent
private String userName;
@Persistent
private String commentBody;
@Persistent
private List children = new
ArrayList();
getters/setters/etc.
}
DataNucleus enhancement goes ok, no errors in the console.
Call of the pm.makePersistent() goes without any exceptions for such
entity.
BUT IT IS NOT PERSISTED.
I found out that problem is in “children” property. And the problem is
it’s a list of objects of the same class as the parent entity. If I
comment that property declaration the entity is persisted. Also if I
change the type of the child entities to some new class (not extending
the CommentEntity) it also gets persisted.
So my suspicion is that JDO (or GAE JDO impl) does not allow child
entities to be of the same class. Is it correct? Maybe I’m missing
something essential? Please advice.
Yes, I think you are running into a limitation of big table JDO implementation. This creates kind of cyclic reference.
You will need to manage the relationship by hand on this one. Store a list of child keys to you can recreate the thread of comments. And have the parent for all comments be a thread, so you can pull them out in one query and contruct the thread by hand.
Some things are more work then you expect
here is the cause discussion on the topic
Thanks,
I already implemented this in that way.
I see those guys also got this problem trying to implement comments )))) Fun.
Alex
Hi
i have been trying to persist a object with arraylist of objects (1-many relationship) however i always ran into some problem or other. and finally decided to use the example here … but again ran into a problem .. the error is
Caused by: java.lang.IllegalArgumentException: addresses: test.shared.Address is not a supported property type.
I am using the following code to persist the object person with addresses
ArrayList aa = new ArrayList();
aa.add(new Address(“123 sasdf”, “”, “Some City”, “AZ”, “93923-2321″));
aa.add(new Address(“23432 asdf”, “Appt 34″, “Another City”, “AZ”, “43434-4432″));
ArrayList parray = new ArrayList();
Person p = new Person();
p.setName(“VVVVVVV”);
p.setAge(23);
p.setGender(‘m’);
p.setAddresses(aa);
PersistenceManager pm = PMF.get().getPersistenceManager();
pm.makePersistent(p);
pm.close();
by the looks of it … i am sure there is something very simple which i am missing but not able to put a finger to it.
Please help…
Please provide test.shared.Address and Person implementations.
thanks,
Tomas
Tomas,
could you help me a bit if you have time?
yesterday I was trying to model a simple forum comments. Just a
comments which you can add more comments to.
So, the approximation of the entity is like this:
——————————————————————-
@PersistenceCapable (detachable = “true”, identityType =
IdentityType.APPLICATION)
public class CommentEntity {
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
@Persistent
private String category;
@Persistent
private String commentDate;
@Persistent
private String userName;
@Persistent
private String commentBody;
@Persistent
private List children = new
ArrayList();
getters/setters/etc.
}
DataNucleus enhancement goes ok, no errors in the console.
Call of the pm.makePersistent() goes without any exceptions for such
entity.
BUT IT IS NOT PERSISTED.
I found out that problem is in “children” property. And the problem is
it’s a list of objects of the same class as the parent entity. If I
comment that property declaration the entity is persisted. Also if I
change the type of the child entities to some new class (not extending
the CommentEntity) it also gets persisted.
So my suspicion is that JDO (or GAE JDO impl) does not allow child
entities to be of the same class. Is it correct? Maybe I’m missing
something essential? Please advice.
Bruce,
Your observation is correct – you can not have children of the same class.
My hunch is that it is due to the implementation of the Key class.
Each child Key holds reference to parent key/id. In theory it should be possible to have child of the same type, but I think current implementation does not allow it. Maybe to safeguard for infinite loop where you make same object child and parent……
Tomas
Can you post the EntityBase class. Is it any different from the ModelBase class
Its the same as ModelBase, I just copy-pasted from different Project where it is called EntityBase.
Hi Tomas, thank you for the excellent example!!
I’m struggling with a strange problem with JDO.
I’ve got two PersistenCapable classes, one having a Collection of
objects of the second, something like this:
class First {
@Persistent
@PrimaryKey
Long id;
@Persistent(mappedby=”owner”)
ArrayList list = new ArrayList();
ArrayList getList() {
if (list == null)
list=new ArrayList();
return list;
}
…
}
class Second {
@Persistent
@PrimaryKey
Key id;
@Persistent
First owner;
First getOwner() {
if (owner==null)
owner = new First();
return owner;
…
}
Seems to be quite the same as you example, right?
In another class I need to print the owner of all my First objects, so
I do:
First obj = …;
ArrayList list = obj.getList();
for (Second s : list) {
System.out.println(s.getOwner());
}
In this loop, I find some Second object having null owner, and I
cannot understand why.
Now I have several questions about my data modelling:
1) Do I need to mark any field with (defaultFetchGroup = “true”)
annotation?
2) Does the check on null object (e.g. if (owner==null) owner = new
First();) in the getter methods results in any strange behavior?
3) Does the assignment on definition of objects (e.g.
ArrayList list = new ArrayList();) results in any
strange behavior?
4) Do I need to add any other annotation to owner field of Second
class?
Thank you very much for your help!!
Best regards
cghersi
Hello,
i am wandering something in a relationship 1/N normally you could do like cghersi’s example. But GWT’s client part needs source code of the classes it uses, so Key source code is needed. At execution time GWT will complains. How would you create a 1/N relationship without a Key class ?
(i saw a workaround creating a source code of the Key.java but it’s just a hack)
Thanks