I am going to build myself another example application. I find these very handy for exploring ideas. If you already have a project with hibernate, spring, gigaspaces and such setup, your much more likely to try a few ideas out, and then blog them. So for a while this blog might be more quiet than usual. I think I may use Roo to do it. Roo looks like a great platform for quickly building something up for an experiment. i.e You can throw together a new set of entities, and then build an example on top of them. Before I begin, one last thing from my current experiments.
Sometimes JPA entity classes get hijacked.
Say for instance you have a need to pass entity classes to another system, via JAXB. Its possible to use DTO objects for the transfer or you could just annotate the the entity classes. In the example below, I wanted to fetch something from a database via JPA and write it into gigaspaces. It soon gets messy your Entity classes start to become a hub in the middle of your application with things dipping into some of the classes and annotating them and throwing them here and there.
Lets look at a simple one from my example system. This one is only used by gigaspaces and hibernate, it could get much messier than this if I chose to add one or two more technologies. I am deliberately leaving the imports in the examples so you can see where it all came from.
import com.gigaspaces.annotation.pojo.SpaceClass;
import com.gigaspaces.annotation.pojo.SpaceId;
import com.gigaspaces.annotation.pojo.SpaceRouting;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Transient;
@Entity
@Table(name = "HOUSE")
@SpaceClass
public class MessyHouse {
private String id;
private String name;
private String address;
private String pageId;
public MessyHouse() {
}
@SpaceRouting
@Transient
public String getPageId() {
return pageId;
}
public void setPageId(String pageId) {
this.pageId = pageId;
}
@Id
@GeneratedValue
@Column(name = "HOUSE_ID")
@SpaceId(autoGenerate = false)
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Some things I dislike about what I have done here
- See the block I have marked below SpaceRouting. In this class I wanted to change the Gigaspace routing strategy, so I have a method that has nothing to do with the persistence. Does adding annotations break the “A class should have only one responsibility” design goal? No perhaps not, but adding a whole method that is a Gigaspace concern does.
- As you add more and more annotations from different technologies things get messy very quickly.
- I have a JPA based DAO that uses this class. I also have a set of gigaspace processing units that use this class. Both systems are impinging their own design requirements on the class. At the moment they are deceptively similar. Gigaspace insists upon a default constructor, and getters and setters for all fields you wish to persist. Hibernate is not quite as strict. What if Gigaspaces relaxes that rule later and allows you to annotate the fields instead? Or perhaps added some other design restriction. Its unclear by looking at the class what things are there for hibernates soft contract and what gigaspace is insisting upon.
- If my gigaspace experiment gets big (not that likely!). I might want to split off the gigaspace into its own project and use it as a component. Ah! so what about the MessyHouse class then? Where should that live? Indeed its going to be in the wrong project wherever I decide to keep it.
This is one solution that I put to you. Create a class for the gigaspace fields, and compose a House class into it. With composition we can neatly separate the concerns. Well almost. Gigaspace may store these objects and need to restore them at some point. I believe to do that it creates House, and populates it. Then it creates GsHouseWrapper and injects House into it. To do that you need a setter for the house but at least we have a class with Gigaspace design constraints and another with Hibernate peculiarities. Check out the classes below and let me know what you make of the design. Are there alternatives?
Also, currently there is a problem with the design below. The delegation methods fail with an exception. i.e house.setId(id); fails when writing the object to the space. I need to submit a ticket with the Gigaspace crew to figure out why.
The refactored classes.
package javapuzzlers.compose;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "HOUSE")
public class House {
private String id;
private String name;
private String address;
public House() {
}
@Id
@GeneratedValue
@Column(name = "HOUSE_ID")
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package javapuzzlers.compose;
import com.gigaspaces.annotation.pojo.SpaceClass;
import com.gigaspaces.annotation.pojo.SpaceId;
import com.gigaspaces.annotation.pojo.SpaceRouting;
@SpaceClass
public class GsHouseWrapper {
private House house;
private String pageId;
public GsHouseWrapper() {
}
public GsHouseWrapper(House house) {
this.house = house;
}
@SpaceId(autoGenerate = false)
public String getId() {
return house.getId();
}
public void setId(String id) {
house.setId(id);
}
@SpaceRouting
public String getPageId() {
return pageId;
}
public void setPageId(String pageId) {
this.pageId = pageId;
}
public GsHouseWrapper(House house) {
this.house = house;
}
public String getName() {
return house.getName();
}
public String getAddress() {
return house.getAddress();
}
}













You don’t have to have getter and setter for all POJO fields.
The ones which you don’t want to be considered when the object is inspected should have @SpaceExclude decoration on their getter fields.
You might also want to take a look on this:
http://www.gigaspaces.com/wiki/display/SBP/Space+Object+Modeling
This page explains the pros/cons between a space object that is also a pure Hibernate object (where Hibernate deals with the associations) and the alternative way that is an hybrid approach that use both Hibernate and GigaSpaces API to deal with associations.
Shay