-
Notifications
You must be signed in to change notification settings - Fork 3
Domain Model Classes
The domain model classes represent entities from our problem domain. Domain model classes in Todor are Todo items and documents. Todo items have an id, text, status, priority, creation and last update dates. Documents are just collections of Todo items of particular users, and they also track the last time the collection was saved to the backend.
The model classes in Todor are shared between the client and the server. Being able to use the same domain model on the client and the server is a major advantage of GWT over other frameworks for creating rich internet applications, as it eliminates the redundant code and additional complexity from expressing and maintaining the same domain model more than once, potentially even using different programming languages.
This capability is not completely granted, however, as GWT model classes are subject to various requirements coming from:
- being able to compile the model to JavaScript for use on the client
- being able to serialize model objects for use in RPC client / server communication
- being able to persist model objects via JDO
Due to the above, one should follow certain guidelines in order to gain this capability. This is explained in more details in the following sections.
See:
The target language of any GWT application client side is ultimately JavaScript. Therefore, any classes to be used on the client have to follow the guidelines and restrictions outlined in Coding Basics - Compatibility with the Java Language and Libraries. However, since domain model classes are usually just simple POJOs, these guidelines are usually very easy to follow. The model classes in Todor are just normal POJOs with fields, constructors, and getter / setter methods.
The model classes in Todor are used also to transfer data to and from the server via RPC calls. The DocumentService
interface and its asynchronous counterpart DocumentServiceAsync
have methods for loading and saving entire Document
objects.
@RemoteServiceRelativePath("document")
public interface DocumentService extends RemoteService {
Document loadDocument();
Document saveDocument(Document document) throws IllegalArgumentException;
}
In order for this to be possible, model classes have to be serializable in the GWT sense of this term, as explained in Serializable Types, which means that:
- They implement the
Serializable
interface. - All their instance fields are themselves serializable.
- They have a default (zero argument) constructor.
See:
Finally, the model classes are used also on the server side to persist data via Java Data Objects (JDO). In order for this to be possible, model classes have to fulfill certain requirements and are annotated with JDO annotations which tell JDO how to store and recreate instances of these classes, as explained in Defining Data Classes with JDO:
- The model classes themselves are annotated with
@PersistenceCapable
. - All persistent fields are annotated with
@Persistent
. - Primary key fields are annotated with
@PrimaryKey
. - All fields are of supported types, i.e. either of one of the core types supported by the datastore, a collection or an array of values of such a type, or an instance or collection of instances of another
@PersistenceCapable
class. - Primary key fields follow one of the four strategies explained in Creating, Getting and Deleting Data in JDO- Keys.
- Entity relationships, such as one-to-one, one-to-many are expressed appropriately as explained in Entity Relationships in JDO.
The last two points deserve special attention as they are perhaps the most difficult to handle. In Todor, there is a one-to-many owned relationsip from the Document to the Item entity, i.e. one document contains multiple items. In the Document
class, this relationship is represented just by a List of Item
instances:
@Persistent(defaultFetchGroup = "true")
private List<Item> items;
The Item
class is much more interesting. In JDO terms, this class is an entity group child as instances of this class should be retrievable together with their parent Document
instance. Therefore, it has to use either the Key or the Key as Encoded String strategy for its key field. However, the first strategy is not appropriate as JDO Key
instances can't be used on the client. Therefore, only the Key as Encoded String strategy can be used in this particular case, which results in the following code in the Item
class:
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
@Extension(vendorName = "datanucleus", key = "gae.encoded-pk", value = "true")
private String key;
@Persistent
@Extension(vendorName = "datanucleus", key = "gae.pk-name", value = "true")
private String id;
Here, the key
field serves as a server-side composite key which is based both on the id of the document and the id of the item within the document. This key is not used on the client, but nevertheless transported to the client and back to ensure that Item instances have the same representation on both sides.