Dependent value classes are custom serializable objects that can be used as persistence fields (although this use is not recommended). They are useful for packaging data and moving it between an entity bean and its remote clients. They separate the client’s view of the entity bean from its abstract persistence model, which makes it easier for the entity bean class to change without affecting existing clients.
The remote interface methods of an entity bean should be defined independently of the abstract persistence schema. In other words, you should design the remote interfaces to model the business concepts, not the underlying persistence programming model. Dependent value classes can help separate a remote client’s view from the persistence model by providing objects that fill the gaps in these perspectives.
For example, the CustomerEJB
could be modified so
that its lastName
and firstName
fields are not exposed to remote clients through their accessor
methods. This is a reasonable design approach, since most clients
access the entire name of the customer at once. The remote interface
might be modified to look like:
import java.rmi.RemoteException; public interface CustomerRemote extends javax.ejb.EJBObject { public Name getName( ) throws RemoteException; public void setName(Name name) throws RemoteException; }
This remote interface is simpler than the one we saw earlier. It
allows the remote client to get all the name information in one
method call instead of two, reducing network traffic and improving
performance for remote clients. The use of the
Name
object is also more consistent with how the
client interacts with the Customer EJB.
To implement this interface, the CustomerBean
class adds a business method that matches the remote interface
methods. The setName( )
method updates the
lastName
and firstName
fields,
while the getName( )
method constructs a
Name
object from these fields:
import javax.ejb.EntityContext; public abstract class CustomerBean implements javax.ejb.EntityBean { public Integer ejbCreate(Integer id){ setId(id); return null; } public void ejbPostCreate(Integer id) { } // business methods public Name getName( ) { Name name = new Name(getLastName( ),getFirstName( )); return name; } public void setName(Name name) { setLastName(name.getLastName( )); setFirstName(name.getFirstName( )); } // abstract accessor methods public abstract String getLastName( ); public abstract void setLastName(String lname); public abstract String getFirstName( ); public abstract void setFirstName(String fname);
The getName( )
and setName( )
methods are business methods, not abstract persistence methods.
Entity beans can have as many business methods as needed. Business
methods introduce business logic to the Customer EJB; otherwise, the
bean would be only a data wrapper. For example, validation logic
could be added to the setName( )
method to ensure
that the data is correct before applying the update. In addition, the
entity bean class can use other methods that help with processing
data—these are just instance methods and may not be exposed as
business methods in the remote interface.
How dependent value classes are defined is important to understanding
how they should be used. The Name
dependent value
class is defined as:
public class Name implements java.io.Serializable { private String lastName; private String firstName; public Name(String lname, String fname){ lastName = lname; firstName = fname; } public String getLastName( ) { return lastName; } public String getFirstName( ) { return firstName; } }
You’ll notice that the Name
dependent value class has get
accessor methods but
not set
methods. It’s immutable.
This is a design strategy used in this book, not a requirement of the
EJB specification. By making dependent values immutable, we ensure
that remote clients cannot change the Name
object’s fields. The reason for this design is
simple: the Name
object is a copy, not a remote
reference. Changes to Name
objects are not
reflected in the database. Making the Name
immutable helps to ensure that clients do not mistake this dependent
value for a remote object reference, thinking that a change to the
Name
object is automatically reflected in the
database. To change the customer’s name, the client
is required to create a new Name
object and use
the setName( )
method to update the Customer EJB.
The following listing illustrates how a client would modify the name
of a customer using the Name
dependent value
class:
// find Customer customer = home.findByPrimaryKey(primaryKey); name = customer.getName( ); System.out.print(primaryKey+" = "); System.out.println(name.getFirstName( )+" "+name.getLastName( )); // change Customer's name name = new Name("Monson-Haefel", "Richard"); customer.setName(name); name = customer.getName( ); System.out.print(primaryKey+" = "); System.out.println(name.getFirstName( )+" "+name.getLastName( ));
The output will look like this:
1 = Richard Monson 1 = Richard Monson-Haefel
Defining the bean’s interfaces according to business concepts and not the underlying data is not always reasonable, but you should try to employ this strategy when the underlying data model doesn’t clearly map to the business purpose or concept being modeled by the entity bean. The bean’s interfaces may be used by developers who know the business but not the abstract programming model. It is important to them that the entity beans reflect the business concept. In addition, defining the interfaces independently of the persistence model enables the component interfaces and persistence model to evolve separately. This allows the abstract persistence programming model to change over time, and allows for new behavior to be added to the entity bean as needed.
Dependent value classes should not be used indiscriminately.
Generally speaking, it is foolish to use dependent value classes when
a CMP field will do just fine. For example, checking a
client’s creditworthiness before processing an order
can be accomplished easily using the getHasGoodCredit( )
method directly. In this case, a dependent value class
would serve no purpose. Exercise 6.2 in the Workbook shows how to
deploy these examples on the JBoss server.