Hibernate, Implementing the domain model


You’ll start with an issue that any implementation must deal with: the separation of concerns. The domain model implementation is usually a central, organizing component; it’s reused heavily whenever you implement new application functionality. For this reason, you should be prepared to go to some lengths to ensure that concerns other than business aspects don’t leak into the domain model implementation.

1 -  Addressing leakage of concerns

When concerns such as persistence, transaction management, or authorization start to appear in the domain model classes, this is an example of leakage of concerns. The domain model implementation is such an important piece of code that it shouldn’t depend on orthogonal Java APIs. For example, code in the domain model shouldn’t perform JNDI lookups or call the database via the JDBC API, not directly and not through an intermediate abstraction. This allows you to reuse the domain model classes virtually anywhere:
■    The presentation layer can access instances and attributes of domain model entities when rendering views.
■    The controller components in the business layer can also access the state of domain model entities and call methods of the entities to execute business logic.
■    The persistence layer can load and store instances of domain model entities from and to the database, preserving their state.
Most important, preventing leakage of concerns makes it easy to unit-test the domain model without the need for a particular runtime environment or container, or the need for mocking any service dependencies. You can write unit tests that verify the correct behavior of your domain model classes without any special test harness. (We aren’t talking about testing “load from the database” and “store in the database” aspects, but “calculate the shipping cost and tax” behavior.)
The Java EE standard solves the problem of leaky concerns with metadata, as annotations within your code or externalized as XML descriptors. This approach allows the runtime container to implement some predefined cross-cutting concerns—security, concurrency, persistence, transactions, and remoteness—in a generic way, by intercepting calls to application components.
Hibernate isn’t a Java EE runtime environment, and it’s not an application server. It’s an implementation of just one specification under the Java EE umbrella—JPA— and a solution for just one of these concerns: persistence.
JPA defines the entity class as the primary programming artifact. This programming model enables transparent persistence, and a JPA provider such as Hibernate also offers automated persistence.

2 - Transparent and automated persistence

We use transparent to mean a complete separation of concerns between the persistent classes of the domain model and the persistence layer. The persistent classes are unaware of—and have no dependency on—the persistence mechanism. We use automatic to refer to a persistence solution (your annotated domain, the layer, and mechanism) that relieves you of handling low-level mechanical details, such as writing most SQL statements and working with the JDBC API.
The Item class of the CaveatEmptor domain model, for example, shouldn’t have any runtime dependency on any Java Persistence or Hibernate API. Furthermore:
■    JPA doesn’t require that any special superclasses or interfaces be inherited or implemented by persistent classes. Nor are any special classes used to implement attributes and associations. (Of course, the option to use both techniques is always there.)
■    You can reuse persistent classes outside the context of persistence, in unit tests or in the presentation layer, for example. You can create instances in any runtime environment with the regular Java new operator, preserving testability and reusability.
■    In a system with transparent persistence, instances of entities aren’t aware of the underlying data store; they need not even be aware that they’re being persisted or retrieved. JPA externalizes persistence concerns to a generic persistence manager API.
■    Hence, most of your code, and certainly your complex business logic, doesn’t have to concern itself with the current state of a domain model entity instance in a single thread of execution.
We regard transparency as a requirement because it makes an application easier to build and maintain. Transparent persistence should be one of the primary goals of any ORM solution. Clearly, no automated persistence solution is completely transparent: Every automated persistence layer, including JPA and Hibernate, imposes some requirements on the persistent classes. For example, JPA requires that collectionvalued attributes be typed to an interface such as java.util.Set or java.util.List and not to an actual implementation such as java.util.HashSet (this is a good practice anyway). Or, a JPA entity class has to have a special attribute, called the database identifier (which is also less of a restriction but usually convenient).
You now know why the persistence mechanism should have minimal impact on how you implement a domain model, and that transparent and automated persistence are required. Our preferred programming model to archive this is POJO.
Around 10 years ago, many developers started talking about POJO, a back-to-basics approach that essentially revives JavaBeans, a component model for UI development, and reapplies it to the other layers of a system. Several revisions of the EJB and JPA specifications brought us new lightweight entities, and it would be appropriate to call

POJO
POJO is the acronym for Plain Old Java Objects. Martin Fowler, Rebecca Parsons, and Josh Mackenzie coined this term in 2000.
them persistence-capable JavaBeans. Java engineers often use all these terms as synonyms for the same basic design approach.
You shouldn’t be too concerned about what terms we use in this book; the ultimate goal is to apply the persistence aspect as transparently as possible to Java classes. Almost any Java class can be persistence-capable if you follow some simple practices. Let’s see how this looks in code.

3 - Writing persistence-capable classes

Working with fine-grained and rich domain models is a major Hibernate objective. This is a reason we work with POJOs. In general, using fine-grained objects means more classes than tables.
A persistence-capable plain-old Java class declares attributes, which represent state, and business methods, which define behavior. Some attributes represent associations to other persistence-capable classes.
A POJO implementation of the User entity of the domain model is shown in the following listing. Let’s walk through the code.
public class User implements Serializable {
protected String username;
public User()    {
}
public String getUsername() { return username;
}
public void setUsername(String username) { this.username = username;
}
public BigDecimal calcShippingCosts(Address fromLocation) { // Empty implementation of business method return null;
}
// ...
}

JPA doesn’t require that persistent classes implement java.io.Serializable. But when instances are stored in an HttpSession or passed by value using RMI, serialization is necessary. Although this might not occur in your application, the class will be serializable without any additional work, and there are no downsides to declaring that. (We aren’t going to declare it on every example, assuming that you know when it will be necessary.)
The class can be abstract and, if needed, extend a non-persistent class or implement an interface. It must be a top-level class, not nested within another class. The persistence-capable class and any of its methods can’t be final (a requirement of the JPA specification).
Unlike the JavaBeans specification, which requires no specific constructor, Hibernate (and JPA) require a constructor with no arguments for every persistent class. Alternatively, you might not write a constructor at all; Hibernate will then use the Java default constructor. Hibernate calls classes using the Java reflection API on such a noargument constructor to create instances. The constructor may not be public, but it has to be at least package-visible if Hibernate will use runtime-generated proxies for performance optimization. Also, consider the requirements of other specifications: the EJB standard requires public visibility on session bean constructors, just like the JavaServer Faces (JSF) specification requires for its managed beans. There are other situations when you’d want a public constructor to create an “empty” state: for example, query-by-example building.
The properties of the POJO implement the attributes of the business entities—for example, the username of User. You usually implement properties as private or protected member fields, together with public or protected property accessor methods: for each field a method for retrieving its value and a method for setting the value. These methods are known as the getter and setter, respectively. The example POJO in listing 3.1 declares getter and setter methods for the username property.
The JavaBean specification defines the guidelines for naming accessor methods; this allows generic tools like Hibernate to easily discover and manipulate property values. A getter method name begins with get, followed by the name of the property (the first letter in uppercase); a setter method name begins with set and similarly is followed by the name of the property. You may begin getter methods for Boolean properties with is instead of get.
Hibernate doesn’t require accessor methods. You can choose how the state of an instance of your persistent classes should be persisted. Hibernate will either directly access fields or call accessor methods. Your class design isn’t disturbed much by these considerations. You can make some accessor methods non-public or completely remove them—then configure Hibernate to rely on field access for these properties.

Should property fields and accessor methods be private, protected, or package visible?
Typically, you want to discourage direct access to the internal state of your class, so you don't make attribute fields public. If you make fields or methods private, you're effectively declaring that nobody should ever access them; only you're allowed to do that (or a service like Hibernate). This is a definitive statement. There are often good reasons for someone to access your “private” internals—usually to fix one of your bugs—and you only make people angry if they have to fall back to reflection access in an emergency. Instead, you might assume or know that the engineer who comes after you has access to your code and knows what they're doing.
The protected visibility then is a more reasonable default. You're forbidding direct public access, indicating that this particular member detail is internal, but allowing access by subclasses if need be. You trust the engineer who creates the subclass. Package visibility is rude: you're forcing someone to create code in the same package to access member fields and methods; this is extra work for no good reason. Most important, these recommendations for visibility are relevant for environments without security policies and a runtime SecurityManager. If you have to keep your internal code private, make it private.
Although trivial accessor methods are common, one of the reasons we like to use Java-Beans-style accessor methods is that they provide encapsulation: you can change the hidden internal implementation of an attribute without any changes to the public interface. If you configure Hibernate to access attributes through methods, you abstract the internal data structure of the class—the instance variables—from the design of the database.
For example, if your database stores the name of a user as a single NAME column, but your User class has firstname and lastname fields, you can add the following persistent name property to the class.
public class User {
protected String firstname; protected String lastname;
public String getName() {
return firstname + '    ' + lastname;
}
public void setName(String name) {
StringTokenizer t = new StringTokenizer(name); firstname = t.nextToken(); lastname = t.nextToken();
}
}

Later, you’ll see that a custom type converter in the persistence service is a better way to handle many of these kinds of situations. It helps to have several options.
Another issue to consider is dirty checking. Hibernate automatically detects state changes in order to synchronize the updated state with the database. It’s usually safe to return a different instance from the getter method than the instance passed by Hibernate to the setter. Hibernate compares them by value—not by object identity— to determine whether the attribute’s persistent state needs to be updated. For example, the following getter method doesn’t result in unnecessary SQL UPDATEs:
public String getFirstname() {    <1- This is OK.
return new String(firstname);
}
There is one important exception to this: collections are compared by identity! For a property mapped as a persistent collection, you should return exactly the same collection instance from the getter method that Hibernate passed to the setter method. If you don’t, Hibernate will update the database, even if no update is necessary, every time the state held in memory is synchronized with the database. You should usually avoid this kind of code in accessor methods:

protected String[] names = new String [0];
public void setNames(List<String> names) {
this.names = names.toArray(new String[names.size()]);
}
public List<String> getNames() {    Don’t do this if Hibernate accesses the methods
return Arrays.asList(names);   
}
Of course, this won’t be a problem if Hibernate is accessing the names field directly, ignoring your getter and setter methods.
How does Hibernate handle exceptions when your accessor methods throw them? If Hibernate uses accessor methods when loading and storing instances and a Run-timeException (unchecked) is thrown, the current transaction is rolled back, and the exception is yours to handle in the code that called the Java Persistence (or Hibernate native) API. If you throw a checked application exception, Hibernate wraps the exception into a RuntimeException.
The example in listing 3.2 also defines a business method that calculates the cost of shipping an item to a particular user (we left out the implementation of this method).
Next, we’ll focus on the relationships between entities and associations between persistent classes.

4 - Implementing POJO associations

You’ll now see how to associate and create different kinds of relationships between objects: one-to-many, many-to-one, and bidirectional relationships. We’ll look at the scaffolding code needed to create these associations, how to simplify relationship management, and how to enforce the integrity of these relationships.

Associations between the Item and Bid classes
Figure 3.4 Associations between the Item and Bid classes



You create properties to express associations between classes, and you (typically) call accessor methods to navigate from instance to instance at runtime. Let’s consider the associations defined by the Item and Bid persistent classes, as shown in figure 3.4.
As with all of our UML class diagrams, we left out the association-related attributes, Item#bids and Bid#item. These properties and the methods that manipulate their values are called scaffolding code. This is what the scaffolding code for the Bid class looks like:
public class Bid {
protected Item item;
public Item getItem() { return item;
}
public void setItem(Item item) { this.item = item;
}
}
The item property allows navigation from a Bid to the related Item. This is an association with many-to-one multiplicity; users can make many bids for each item. Here is the Item class’s scaffolding code:
public class Item {
protected Set<Bid> bids = new HashSet<Bid>();
public Set<Bid> getBids() { return bids;
}
public void setBids(Set<Bid> bids) { this.bids = bids;
}
}
This association between the two classes allows bidirectional navigation: the many-to-one is from this perspective a one-to-many multiplicity (again, one item can have many bids). The scaffolding code for the bids property uses a collection interface type, java.util.Set. JPA requires interfaces for collection-typed properties, where you must use java.util.Set, java.util.List, or java.util.Collection rather than HashSet, for example. It’s good practice to program to collection interfaces anyway, rather than concrete implementations, so this restriction shouldn’t bother you.
You choose a Set and initialize the field to a new HashSet because the application disallows duplicate bids. This is good practice because you avoid any NullPointer-Exceptions when someone is accessing the property of a new Item without any bids. The JPA provider is also required to set a non-empty value on any mapped collectionvalued property: for example, when an Item without bids is loaded from the database. (It doesn’t have to use a HashSet; the implementation is up to the provider. Hibernate has its own collection implementations with additional capabilities—for example, dirty checking.)
Shouldn’t bids on an item be stored in a list?
The first reaction is often to preserve the order of elements as they're entered by users, because this may also be the order in which you will show them later. Certainly, in an auction application there has to be some defined order in which the user sees bids for an item—for example, highest bid first or newest bid last. You might even work with a java.util.List in your user interface code to sort and display bids of an item. That doesn't mean this display order should be durable; data integrity isn't affected by the order in which bids are displayed. You need to store the amount of each bid, so you can find the highest bid, and you need to store a timestamp for each bid when it's created, so you can find the newest bid. When in doubt, keep your system flexible and sort the data when it's retrieved from the datastore (in a query) and/or shown to the user (in Java code), not when it's stored.
Just like for basic properties, accessor methods for associations need to be declared public only if they’re part of the external interface of the persistent class used by the application logic to create a link between two instances. We’ll now focus on this issue, because managing the link between an Item and a Bid is much more complicated in Java code than it is in an SQL database, with declarative foreign key constraints. In our experience, engineers are often unaware of this complication arising from a network object model with bidirectional references (pointers). Let’s walk through the issue step by step.
The basic procedure for linking a Bid with an Item looks like this:
anItem.getBidsO.add(aBid);
aBid.setItem(anItem);
Whenever you create this bidirectional link, two actions are required:
■    You must add the Bid to the bids collection of the Item.
■    The item property of the Bid must be set.
JPA doesn’t manage persistent associations. If you want to manipulate an association, you must write exactly the same code you would write without Hibernate. If an association is bidirectional, you must consider both sides of the relationship. If you ever have problems understanding the behavior of associations in JPA, just ask yourself, “What would I do without Hibernate?” Hibernate doesn’t change the regular Java semantics.
We recommend that you add convenience methods that group these operations, allowing reuse and helping ensure correctness, and in the end guaranteeing data integrity (a Bid is required to have a reference to an Item). The next listing shows such a convenience method in the Item class.
public void addBid(Bid bid) {
if (bid == null)    <- Be defensive
throw new NullPointerException("Can't add null Bid"); if (bid.getItem() != null)
throw new IllegalStateException("Bid is already assigned to an Item");
getBids().add(bid);
bid.setItem(this);
}
The addBid () method not only reduces the lines of code when dealing with Item and Bid instances, but also enforces the cardinality of the association. You avoid errors that arise from leaving out one of the two required actions. You should always provide this kind of grouping of operations for associations, if possible. If you compare this with the relational model of foreign keys in an SQL database, you can easily see how a network and pointer model complicates a simple operation: instead of a declarative constraint, you need procedural code to guarantee data integrity.
Because you want addBid() to be the only externally visible mutator method for the bids of an item (possibly in addition to a removeBid() method), you can make the Item#setBids( ) method private or drop it and configure Hibernate to directly access fields for persistence. Consider making the Bid#setItem() method package-visible, for the same reason.
The Item#getBids () getter method still returns a modifiable collection, so clients can use it to make changes that aren’t reflected on the inverse side. Bids added directly to the collection wouldn’t have a reference to an item—an inconsistent state, according to your database constraints. To prevent this, you can wrap the internal collection before returning it from the getter method, with Collections.unmodifiable-Collection(c) and Collections.unmodifiableSet(s). The client then gets an exception if it tries to modify the collection; you therefore force every modification to go through the relationship management method that guarantees integrity. Note that in this case you’ll have to configure Hibernate for field access, because the collection
returned by the getter method is then not the same as the one given to the setter method.
An alternative strategy is immutable instances. For example, you could enforce integrity by requiring an Item argument in the constructor of Bid, as shown in the following listing.
public class Bid {
protected Item item;
public Bid(Item item) { this.item = item;
item.getBids().add(this);    <- Bidirectional
}
public Item getItem() { return item;
}
}
In this constructor, the item field is set; no further modification of the field value should occur. The collection on the “other” side is also updated for a bidirectional relationship. There is no Bid#setItem( ) method, and you probably shouldn’t expose a public Item#setBids( ) method.
There are several problems with this approach. First, Hibernate can’t call this constructor. You need to add a no-argument constructor for Hibernate, and it needs to be at least package-visible. Furthermore, because there is no setItem() method, Hibernate would have to be configured to access the item field directly. This means the field can’t be final, so the class isn’t guaranteed to be immutable.
In the examples in this book, we’ll sometimes write scaffolding methods such as the Item#addBid() shown earlier, or we may have additional constructors for required values. It’s up to you how many convenience methods and layers you want to wrap around the persistent association properties and/or fields, but we recommend being consistent and applying the same strategy to all your domain model classes. For the sake of readability, we won’t always show convenience methods, special constructors, and other such scaffolding in future code samples and assume you’ll add them according to your own taste and requirements.
You now have seen domain model classes, how to represent their attributes, and the relationships between them. Next, we’ll increase the level of abstraction, adding metadata to the domain model implementation and declaring aspects such as validation and persistence rules.

Comments