Skip to content


Google App Engine + JAVA + JDO + Inheritance + One-To-Many Relationships

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 &amp; 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 &amp; 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……

  • Facebook
  • Twitter
  • Digg
  • del.icio.us
  • Reddit
  • Google Bookmarks
  • LinkedIn
  • Slashdot
  • MySpace
  • Propeller
  • StumbleUpon
  • Yahoo! Buzz
  • Add to favorites
  • email
  • Yahoo! Bookmarks
  • Live
  • FriendFeed
  • Technorati

Posted in Google App Engine, Spring Framework.

Tagged with , .


14 Responses

Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.

  1. Alexander ArendarNo Gravatar says

    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

  2. TomasNo Gravatar says

    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

  3. Alexander ArendarNo Gravatar says

    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.

  4. TomasNo Gravatar says

    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 ;)

  5. TomasNo Gravatar says

    here is the cause discussion on the topic

  6. Alexander ArendarNo Gravatar says

    Thanks,

    I already implemented this in that way.
    I see those guys also got this problem trying to implement comments )))) Fun.

    Alex

  7. VivekNo Gravatar says

    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…

  8. Tomas MazuknaNo Gravatar says

    Please provide test.shared.Address and Person implementations.

    thanks,
    Tomas

  9. BruceNo Gravatar says

    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.

  10. Tomas MazuknaNo Gravatar says

    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

  11. PrabuddhaNo Gravatar says

    Can you post the EntityBase class. Is it any different from the ModelBase class

  12. Tomas MazuknaNo Gravatar says

    Its the same as ModelBase, I just copy-pasted from different Project where it is called EntityBase.

  13. cghersiNo Gravatar says

    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

  14. dukeNo Gravatar says

    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



Some HTML is OK

or, reply to this post via trackback.