Persistence Bean Style Guide

From Mugshot Developer Wiki

Jump to: navigation, search

You should be familiar with EJB3 Persistence Beans or this page won't make a lot of sense.

Naming Join Tables

We haven't used this rule consistently in the past, but the idea is that the table names in the database should make sense. So for example if you have:

    @Entity
    class Account {
	@ManyToMany
	public Set<Post> getFavoritePosts() {
		return favoritePosts;
	}
    }

Hibernate will name the database table "Account_Post", which is really annoying when you're at the database console. So, it's good to add something like:

   @JoinTable(table=@Table(name="Favorite"))

But it might be even better to just avoid the "implicit" join table and have an entity bean like:

   @Entity
   class Favorite {
       public Account getAccount();
       public Post getPost();
   }

But we aren't sure yet about that and have examples of doing it both ways.

Getters/Setters for Collections

If you have a property "Set<Foo> foos" then a best-practices POJO is probably something like this:

class Bar {
    private Set<Foo> foos;
    // shared among all constructors
    private void initMissing() {
      // could also use setFoos(Collections.emptySet()) 
      // (but due to a javac but you have to put emptySet in a temp var first)
      if (foos == null)
         foos = new HashSet<Foo>();
    }
    public Bar() {
      initMissing();
    }
    public Bar(Set<Foo> foos) {
      setFoos(foos); // use setter, so the copy gets made
      initMissing(); // does nothing while we only have one field
    }
    public Set<Foo> getFoos() {
      return Collections.unmodifiableSet(foos); // keep caller from changing it underneath us
    }
    public void setFoos(Set<Foo> foos) {
      if (foos == null)
        throw new IllegalArgumentException("null");
      foos = new HashSet<Foo>(foos); // make a copy so caller can't change it underneath us
    }
}

With EJB3 Persistence, hibernate replaces your Set<> with its own wrapper object.

From my reading, Hibernate is happy if you replace the wrapper object with your own set, BUT next time you send your object to Hibernate, the Hibernate wrapper will be put back.

Hibernate has a special rule that breaks the defensive programming in the above example: according to their FAQ they use "==" on the return value from getFoos(), and if you return a different object from the one Hibernate expected it will be inefficient since Hibernate will recreate the wrapper.

From my own travails, one other thing seems to be true: if you return an unmodifiable set from getFoos(), then Hibernate's wrapper object will be unmodifiable also. Which means your internal private Set<> is unmodifiable.

So the following changes are required vs. "normal" objects:

- setFoos() is protected and does not make a copy
- getFoos() has to just "return foos", no unmodifiableSet() cleverness

Sucky.

Personal tools