Technical Article
Introducing the Java EE 6 Platform: Part 3
By Ed Ort, December 2009
Enterprise JavaBeans technology is the server-side component architecture for developing and deploying business applications in Java EE. Applications that you write using EJB technology are scalable, transactional, and secure. EJB 3.0, which is part of the Java EE 5 platform, made the technology a lot easier to use. The latest release of the technology, JSR 318: Enterprise JavaBeans 3.1, which is available in the Java EE 6 platform, further simplifies the technology and makes many improvements that reflect common usage patterns.
Some improvements made in EJB 3.1 are as follows:
- No-interface view. Allows you to specify an enterprise bean using only a bean class without having to write a separate business interface.
- Singletons. Lets you easily share state between multiple instances of an enterprise bean component or between multiple enterprise bean components in an application.
- Asynchronous session bean invocation. Enables you to invoke session bean methods asynchronously by specifying an annotation.
- Simplified Packaging. Removes the restriction that enterprise bean classes must be packaged in an
ejb-jar
file. You can now place EJB classes directly in a WAR file. - EJB Lite. Is a subset of EJB 3.1 for inclusion in a variety of Java EE profiles.
No-Interface View
The EJB 3.0 local client view is based on a plain old Java interface (POJI) called a local business interface. A local interface defines the business methods that are exposed to the client and that are implemented on the bean class. This separation of interface and implementation is sometimes unnecessarily cumbersome and adds little value — this is especially true for fine-grained components that are accessed locally from clients within the same module.
EJB 3.1 simplifies this approach by making local business interfaces optional. A bean that does not have a local business interface exposes a no-interface view. Now you can get the same enterprise bean functionality without having to write a separate business interface.
Local business interfaces are optional in EJB 3.1. Now you can get the same enterprise bean functionality without having to write a separate business interface.
The no-interface view has the same behavior as the EJB 3.0 local view, for example, it supports features such as pass-by-reference calling semantics and transaction and security propagation. However, a no-interface view does not require a separate interface, that is, all public methods of the bean class are automatically exposed to the caller. By default, any session bean that has an empty implements
clause and does not define any other local or remote client views, exposes a no-interface client view.
For example, the following session bean exposes a no-interface view:
@Stateless
public class HelloBean {
public String sayHello() {
String message = propertiesBean.getProperty("hello.message");
return message;
}
}
As is the case for a local view, the client of a no-interface view always acquires an EJB reference -- either through injection or JNDI lookup. The only difference is that the Java type of the EJB reference is the bean class type rather than the type of a local interface. This is shown in the following bean client:
@EJB
private HelloBean helloBean;
...
String msg = helloBean.sayHello();
Note that even though there is no interface, the client cannot use the new()
operator to explicitly instantiate the bean class. That's because all bean invocations are made through a special EJB reference, or proxy, provided by the container. This allows the container to provide all the additional bean services such as pooling, container-managed transactions, and concurrency management.
Singletons
A singleton bean, also known as a singleton, is a new kind of session bean that is guaranteed to be instantiated once for an application in a particular Java Virtual Machine (JVM) *. With singletons, you can easily share state between multiple instances of an enterprise bean component or between multiple enterprise bean components in the application. Consider, for example, a class that caches data for an application. You might define the class as a singleton and in doing so, ensure that only one instance of the cache and its state is shared in the application.
Singletons help you easily share state between the EJB components in an application.
You define a singleton with the @Singleton
annotation, as shown in the following code example:
@Singleton
public class PropertiesBean {
private Properties props;
public String getProperty(String name) { ... }
@PostConstruct
public void initialize { // props = ...}
}
Because it's just another kind of session bean, a singleton can define the same local and remote client views as can stateless and stateful beans. Clients access singletons in the same way as they access stateless and stateful beans, that is, through an EJB reference. For example, a client can access the PropertiesBean
singleton shown in the previous example as follows:
@EJB
private PropertiesBean propsBean;
...
String msg = propsBean.getProperty("hello.message");
Here, the container ensures that all invocations through PropertiesBean
references in the same JVM are serviced by the same instance of the PropertiesBean
. By default, the container enforces the same threading guarantee as for other component types. In other words, the singleton is fully thread safe. Specifically, no more than one invocation is allowed to access a particular bean instance at any one time. For singletons, that means blocking any concurrent invocations. However, this is just the default concurrency behavior. Additional concurrency options allow more efficient concurrent access to the singleton instance.
Asynchronous Session Bean Invocation
One of the powerful features introduced in EJB 3.1 is the ability to invoke session bean methods asynchronously. For an asynchronous invocation, control returns to the client before the container dispatches the invocation to an instance of the bean. This allows the client to continue processing in parallel while the session bean method performs its operations.
With EJB 3.1, you can invoke session bean methods synchronously or asynchronously.
You can make a method asynchronous by marking it with the @Asynchronous
annotation. You apply the annotation to a business method of a bean class. You can also use a deployment descriptor to designate a method as asynchronous.
Asynchronous methods can return a java.util.concurrent.Future<V>
object or void
. A Future<V>
object holds the result of an asynchronous operation. You can access the Future<V>
object to retrieve a result value, check for exceptions, or cancel an in-progress invocation. The Future<V>
interface provides a get()
method to retrieve the value. You can also retrieve the value by using the convenience class, AsyncResult<V>
, which implements the Future<V>
interface.
In the following example, the performCalculation()
method in made asynchronous. The method uses the AsyncResult<V>
class to retrieve the value returned in the Future<V>
object.
@Stateless
Public class CalculatorBean implements CalculatorService {
...
@Asynchronous
public Future<Integer> performCalculation(...) {
// ... do calculation
Integer result = ...;
return new AsyncResult<Integer>(result);
}
}
Simplified Packaging
The EJB specification has always required that enterprise beans be packaged in an enterprise module called an ejb-jar
file. Since it is common for Java EE web applications to use enterprise beans, this packaging requirement can be burdensome. These applications are forced to use a web application archive ( .war
) file for the web application, an ejb-jar
file for the enterprise beans, and an enterprise archive ( .ear
file) that encompasses the other packages. This is illustrated in Figure 4. This packaging approach is further complicated by the special handling required for any classes or resources that must be shared among the modules.
Figure 4. Traditional Enterprise Application Packaging
Figure 5. Simplified Enterprise Application Packaging
EJB 3.1 addresses this packaging complexity by removing the restriction that enterprise bean classes must be packaged in an ejb-jar
file. As Figure 5 illustrates, you can now place EJB classes directly in the .war
file, using the same packaging guidelines that apply to web application classes. This means that you can place EJB classes under the WEB-INF/classes
directory or in a .jar
file within the WEB-INF/lib
directory. The EJB deployment descriptor is also optional. If you need it, you can package the EJB deployment descriptor as a WEB-INF/ejb-jar.xml
file.
In EJB 3.1, you can place enterprise bean classes in the .war
file along with web tier components. You don't have to put EJB classes in the ejb-jar
file.
EJB Lite
For many applications, EJB technology offers a lot more functionality than those applications really need. The typical application that uses EJB only needs a subset of the features provided by the technology. EJB Lite meets the needs of these applications with a small subset of the features in EJB 3.1 centered around the session bean component model.
EJB Lite should simplify the use of EJB technology for many developers. Developers who use EJB Lite in their applications only need to learn to use a small set of features. In addition, applications developed with EJB Lite can run in application servers that implement either EJB Lite or the full EJB 3.1 API. Also, vendor implementations of EJB Lite should be simpler and more lightweight than full EJB implementations.
EJB Lite meets the needs of applications that require only a subset of the features provided by EJB technology.
Note that EJB Lite is not a product or an implementation, but rather a small convenient subset of the EJB 3.1 API. The objective of EJB Lite is to offer a subset of EJB 3.1 features that cover the common requirements for the business logic tier of most applications, one that also gives vendors the flexibility to provide EJB technology across a variety of Java EE profiles. To meet those objectives, EJB Lite offers the following features:
- Stateless, stateful, and singleton session beans
- Local EJB interfaces or no interfaces
- Interceptors
- Container-managed and bean-managed transactions
- Declarative and programmatic security
- Embeddable API
More New Features in EJB 3.1
EJB 3.1 delivers more features and enhancements than those covered in the previous sections. For example, it includes an embeddable API and container for use in the Java SE environment. These makes it easy to test EJB components outside a Java EE container, and more generally, in Java SE. For another example, the introduction of singletons in EJB 3.1 offers a convenient way for EJB applications to receive callbacks during application initialization or shutdown. By default, the container decides when to instantiate the singleton instance. However, you can force the container to instantiate a singleton instance during application initialization by using the @Startup
annotation. This allows the bean to define a @PostConstruct
method that is guaranteed to be called at startup time. In addition, any @PreDestroy
method for a singleton is guaranteed to be called when the application is shutting down, regardless of whether the singleton was instantiated using lazy instantiation or eager instantiation.
To learn about all the features and enhancements in EJB 3.1, see JSR 318: Enterprise JavaBeans 3.1.
A More Complete Java Persistence API
The Java EE 5 platform introduced the Java Persistence API, which provides a POJO-based persistence model for Java EE and Java SE applications. JPA handles the details of how relational data is mapped to Java objects, and it standardizes Object/Relational (O/R) mapping. JPA has been widely adopted and is recognized as the enterprise standard for O/R persistence.
Java EE 6 includes the latest release of this technology, JSR 317: Java Persistence 2.0. JPA 2.0 adds a number of significant new features and enhancements. These include:
- Object/Relational mapping enhancements, such as the ability to model collections of objects
- Additions to the Java Persistence query language
- A new criteria-based query API
- Support for pessimistic locking
Object/Relational Mapping Enhancements
JPA 1.0 supported the mapping of collections. However, those collections could only contain entities. JPA 2.0 adds the mapping of collections of basic data types, such as String
s or Integer
s, as well as collections of embeddable objects. Recall that an embeddable object in JPA is an object that cannot exist on its own, but exists as part of a parent object — that is, its data does not exist in its own table, but is embedded in the parent object's table.
In JPA 2.0, you can map collections of basic data types, such as String
s or Integer
s, as well as collections of embeddable objects.
JPA 2.0 adds two annotations in support of the new collection mappings: @ElementCollection
and @CollectionTable
. You use the @ElementCollection
annotation to specify that the basic or embeddable objects in the collection are stored in a separate table called a collection table. You use the @CollectionTable
annotation to specify details about the collection table, such as its columns.
Here, for example, is an embeddable class that represents a service visit for a vehicle. The embeddable class stores the date of the visit, a description of the work that was done, and the cost. In addition, the vehicle can be equipped with one or more optional features. Each of the available features is an enumerated value of type FeatureType
.
public enum FeatureType { AC, CRUISE, PWR, BLUETOOTH, TV, ... }
@Embeddable
public class ServiceVisit {
@Temporal(DATE)
@Column(name="SVC_DATE")
Date serviceDate;
String workDesc;
int cost;
}
The enumerated values and embeddable objects can then be used in an entity that represents a vehicle's service history and its features.
@Entity
public class Vehicle {
@Id int vin;
@ElementCollection
@CollectionTable(name="VEH_OPTNS")
. @Column(name="FEAT")
Set<FeatureType> optionalFeatures;
@ElementCollection
@CollectionTable(name="VEH_SVC")
@OrderBy("serviceDate")
List<ServiceVisit> serviceHistory;
...
}
The first pairing of @ElementCollection
and @CollectionTable
annotations in the Vehicle
entity specifies that the FeatureType
values are stored in the VEH_OPTNS
collection table. The second pairing of @ElementCollection
and @CollectionTable
annotations in the entity specifies that the ServiceVisit
embeddable objects are stored in the VEH_SVC
collection table.
Though not shown in the example, the @ElementCollection
annotation has two attributes: targetClass
and fetch
. The targetClass
attribute specifies the class name of the basic or embeddable class, and is optional if the field or property is defined using generics, as it is in this example. The fetch
attribute is optional and specifies whether the collection should be retrieved lazily or eagerly, using the javax.persistence.FetchType
constants of either LAZY
or EAGER
, respectively. By default, the collection is fetched lazily, which is the case in this example.
There are many more Object/Relational mapping enhancements in JPA 2.0 than the mapping of collections described here. For example, JPA 2.0 supports nested embeddables, embeddables with relationships, and ordered lists. There are also new annotations for generalized map functionality, more flexible support for specific access types through an @Access
annotation, more mapping options for entity relationships such as foreign key mapping support for unidirectional one-to-many relationships, support for derived identities through the @MapsId
annotation, and support for orphan removal.
Additions to the Java Persistence Query Language
JPA 1.0 defined an extensive Java Persistence query language (informally referred to as JPQL) with which you can query entities and their persistent state. JPA 2.0 makes a number of enhancements to JPQL. For example, you can now use case expressions in queries. In the following query, a case expression increases an employee's salary by a multiplier of 1.1 if the employee has a rating of 1, by a multiplier of 1.05 if the rating is 2, and by a multiplier of 1.01 for any other rating:
JPA 2.0 includes enhancements to Java Persistence query language. For example, you can now use case expressions in queries.
UPDATE Employee e
SET e.salary =
CASE WHEN e.rating = 1 THEN e.salary * 1.1
WHEN e.rating = 2 THEN e.salary * 1.05
ELSE e.salary * 1.01
END
JPA 2.0 also adds a number of new operators to JPQL. Two of these are NULLIF
, and COALESCE
. The NULLIF
operator is particularly useful when a database uses something other than nulls to encode missing or non-applicable information. Using NULLIF
, you can easily convert these values to nulls in queries. If the arguments to NULLIF
are equal, NULLIF
returns null, otherwise it returns the value of the first argument.
JPA 2.0 also adds two new operators to Java Persistence query language: NULLIF
, and COALESCE
.
For example, suppose that salaries in an employee table are represented as integer values and that missing salaries are encoded by -99999. Here's a query that returns the average value of the salaries. To correctly ignore the missing salaries, the query uses NULLIF
to convert the -99999 values to null.
SELECT AVG(NULLIF(e.salary, -99999))
FROM Employee e
The COALESCE
operator accepts a list of parameters and then returns the first non-null value from the list. It is equivalent to the following case expression:
CASE WHEN value1 IS NOT NULL THEN value1
WHEN value2 IS NOT NULL THEN value2
WHEN value3 IS NOT NULL THEN value3
...
ELSE NULL
END
For example, suppose that an employee table includes columns for a work phone number and a home phone number. A missing phone number is represented by a null value. The following query returns the name and phone number of each employee. The COALESCE
operator specifies that the query return the work phone number, but if it's null, return the home phone number. If both are null, return a null value for the phone number.
SELECT Name, COALESCE(e.work_phone, e.home_phone) phone
FROM Employee e
The other new operators that JPA 2.0 adds to JPQL are INDEX
, TYPE
, KEY
, VALUE
, and ENTRY
. The INDEX
operator queries over the ordering in an ordered list. The TYPE
operator selects an entity's type and restricts a query to one or more entity types. The KEY
, VALUE
, and ENTRY
operators are part of the generalized map functionality in JPA 2.0. You use the KEY
operator to extract map keys, the VALUE
operator to extract map values, and the ENTRY
operator to select a map entry.
In addition, JPA 2.0 adds support for operators in the select list, as well as in collection-valued parameters and non-polymorphic queries.
Criteria API
One of the significant new features introduced in JPA 2.0 is the Criteria API, an API for dynamically constructing object-based queries. In essence, the Criteria API is the object-oriented equivalent of JPQL. With it, you can take an object-based approach to creating queries, rather than using the string manipulation required by JPQL.
You can use the new Criteria API to dynamically construct object-based queries.
The Criteria API is based on a metamodel, an abstract model that provides schema-level metadata about the managed classes of the persistence unit. The metamodel enables you to build queries that are strongly typed. It also enables you to browse the logical structure of a persistence unit.
Typically an annotation processor is expected to use the metamodel to generate static metamodel classes. These classes provide the persistent state and relationships of the managed classes of a persistence unit. However, you can also code the static metamodel classes.
Here, for example, is an entity:
@Entity public class Employee {
@Id Long Id;
String firstName;
String lastName;
Department dept;
}
And here is its corresponding static metamodel class:
import javax.persistence.meta,model.SingularAttribute;
import javax.persistence.meta,model.StaticMetamodel;
@Generated("EclipseLink JPA 2.0 Canonical Model Generation"
@StaticMetamodel(Employee.class)
public class Employee_ {
public static volatile SingularAttribute<Employee, Long> id;
public static volatile SingularAttribute<Employee, String> firstName;
public static volatile SingularAttribute<Employee, String> lastName;
public static volatile SingularAttribute<Employee, Department> dept;
}
In addition, a JPA 2.0 metamodel API enables you to dynamically access the metamodel. So when you use the Criteria API you can either statically access the metamodel classes or dynamically access the metamodel. However, the Criteria API gives you even more flexibility in that you can navigate the metamodel either in an object-based way or in a string-based way. This means that you have four ways to use the Criteria API:
The Criteria API is based on a metamodel for building queries that are strongly typed.
- Statically with metamodel classes
- Statically with strings
- Dynamically with the metamodel
- Dynamically with strings
No matter which of these approaches you use, you define a Criteria API-based query by constructing a CriteriaQuery
object. You construct the CriteriaQuery
using a factory object called CriteriaBuilder
. You can get the CriteriaBuilder
from either the EntityManager
or EntityManagerFactory
class.The following code, for example, constructs a CriteriaQuery
object:
EntityManager em = ... ;
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Customer> cq = cb.createQuery(Customer.class);
Notice that the CriteriaQuery
object is generically typed. You use the createQuery
method of CriteriaBuilder
to create a CriteriaQuery
and to specify a type for the query result. In this example, the Employee.class
argument to the createQuery
method specifies that the query result type is Employee
. Significantly, CriteriaQuery
objects and the methods that create them are strongly typed, and this typing continues through the execution of the query.
Next, you specify one or more query roots for the CriteriaQuery
object. The query roots represent the entities on which the query is based. You create a query root and add it to a query with the from()
method of the AbstractQuery
interface. The AbstractQuery
interface is one of a number of interfaces, such as CriteriaQuery
, From
, and Root
, that are defined in the Criteria API. The CriteriaQuery
interface inherits from the AbstractQuery
interface.
The argument to the from()
method is the entity class or EntityType
instance for the entity. The result of the from()
method is a Root
object. The Root
interface extends the From
interface, which represents objects that may occur in the from
clause of a query.
The following code adds a single query root to the CriteriaQuery
object:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Employee> cq = cb.createQuery(Employee.class);
Root<Employee> emp = cq.from(Employee.class);
After you add one or more query roots to the CriteriaQuery
object, you access the metamodel and then construct a query expression. How you do that depends on whether you issue the query statically or dynamically and whether you use the metamodel or strings to navigate the metamodel. Here's an example of a static query that uses the metamodel classes:
cq.select(emp);
cq.where(cb.equal(emp.get(Employee_.lastName), "Smith"));
TypedQuery<Employee> query = em.createQuery(cq);
List<Employee> rows = query.getResultList();
The select()
and where()
methods of the CriteriaQuery
interface specify the selection items that are to be returned in the query result.
Notice that you create a query using the EntityManager
and you specify the CriteriaQuery
object as input. This results in a TypedQuery
, an extension introduced in JPA 2.0 to the javax.persistence.Query
interface . The TypedQuery
interface knows the type it returns so that strong typing continues into the query's execution.
In metamodel terminology, Employee_
is the canonical metamodel class corresponding to the Employee
entity class. A canonical metamodel class follows certain rules described in the JPA 2.0 specification. For example, the name of the metamodel class is derived from the name of the managed class by appending "_" to the name of the managed class. A canonical metamodel is a metamodel comprising the static metamodel classes that correspond to the entities, mapped superclasses, and embeddable classes in the persistence unit. This query, in fact, uses the canonical metamodel.
Here is the complete query:
EntityManager em = ... ;
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Employee> cq = cb.createQuery(Employee.class);
Root<Employee> emp = cq.from(Employee.class);
cq.select(emp);
cq.where(cb.equal(emp.get(Employee_.lastName), "Smith"));
TypedQuery<Employee> query = em.createQuery(cq);
List<Employee> rows = query.getResultList();
Here's a dynamic version of the query that uses the metamodel API:
EntityManager em = ... ;
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Employee> cq = cb.createQuery(Employee.class);
Root<Employee> emp = cq.from(Employee.class);
EntityType<Employee> emp_ = emp.getModel();
cq.select(emp);
cq.where(cb.equal(emp.get(emp_.getSingularAttribute("lastName", String.class)),"Smith"));
TypedQuery<Employee> query=em.createQuery(cq);
List<Employee> rows=query.getResultList();
A criteria query that uses the metamodel API provides the same type safety as one that uses the canonical metamodel, but it can be more verbose than queries based on the canonical metamodel.
The getModel()
method of Root
returns the metamodel entity corresponding to the root. It also enables run time access to the persistent attributes declared in the Employee
entity. Again, the select()
and where()
methods of the CriteriaQuery
interface specify the selection items that are to be returned in the query result.
The getSingularAttribute()
method is a metamodel API method that returns a persistent single-valued property or field. In this example, it returns the lastName
property whose value is Smith
.
Here is a static version of the query that uses string navigation of the metadata:
EntityManager em = ... ;
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Employee> cq = cb.createQuery(Employee.class);
Root<Employee> emp = cq.from(Employee.class);
cq.select(emp);
cq.where(cb.equal(emp.get("lastName"), "Smith"));
TypedQuery query = em.createQuery(cq);
List <Employee>rows = query.getResultList();
The string-based approach is relatively easy to use, but you lose the type safety that the metamodel enables.
Support for Pessimistic Locking
Locking is a technique for handling database transaction concurrency. When two or more database transactions concurrently access the same data, locking is used to ensure that only one transaction at a time can change the data.
There are generally two locking approaches: optimistic and pessimistic. Optimistic locking assumes infrequent conflicts between concurrent transactions, that is, they won't often try to read and change the same data at the same time. In optimistic locking, the objective is to give concurrent transactions freedom to process simultaneously, but to detect and prevent collisions. Two transactions can access the same data simultaneously. However, to prevent collisions, a check is made to detect any changes made to the data since the data was last read.
Pessimistic locking assumes that transactions will frequently collide. In pessimistic locking, a transaction that reads the data locks it. Another transaction cannot change the data until the first transaction commits.
JPA 1.0 only supported optimistic locking. You could indicate what type of locking was in effect by specifying a lock mode value of READ
or WRITE
in the lock()
method of the EntityManager
class. For example:
EntityManager em = ... ;
em.lock (p1, READ);
For the READ
lock mode, the JPA entity manager locked the entity and before a transaction committed, checked the entity's version attribute to determine if it had been updated since the entity was last read. If the version attribute had been updated, the entity manager threw an OptimisticLockException
and rolled back the transaction.
For the WRITE
lock mode, the entity manager performed the same optimistic locking operations as for the READ
lock mode. However, it also updated the entity's version column.
JPA 2.0 adds six new lock modes. Two of these are for optimistic locking. JPA 2.0 also permits pessimistic locking and adds three lock modes for that. A sixth lock mode specifies no locking.
JPA 2.0 adds two new lock modes for optimistic locking. JPA 2.0 also permits pessimistic locking and adds three lock modes for that.
These are the two new optimistic lock modes:
OPTIMISTIC
. This is the same as theREAD
lock mode. TheREAD
lock mode is still supported in JPA 2.0, but specifyingOPTIMISTIC
is recommended for new applications.OPTIMISTIC_FORCE_INCREMENT
. This is the same as theWRITE
lock mode. TheWRITE
lock mode is still supported in JPA 2.0, but specifyingOPTIMISTIC_FORCE_INCREMENT
is recommended for new applications.
These are the three new pessimistic lock modes:
PESSIMISTIC_READ
. The entity manager locks the entity as soon as a transaction reads it. The lock is held until the transaction completes. Use this lock mode when you want to query data using repeatable-read semantics — in other words, when you want to ensure that the data is not updated between successive reads. This lock mode does not block other transactions from reading the data.PESSIMISTIC_WRITE
. The entity manager locks the entity as soon as a transaction updates it. This lock mode forces serialization among transactions attempting to update the entity data. This lock mode is often used when there is a high likelihood of update failure among concurrent updating transactions.PESSIMISTIC_FORCE_INCREMENT
. The entity manager locks the entity when a transaction reads it. It also increments the entity's version attribute when the transaction ends, even if the entity is not modified.
You can also specify the new lock mode NONE
, in which case, no lock is acquired.
JPA 2.0 also provides multiple ways to specify the lock mode for an entity. You can specify the lock mode in the lock()
and find()
methods of the EntityManager
. In addition, the EntityManager.refresh()
method refreshes the state of the entity instance from the database and locks it in accordance with the entity's lock mode.
The following code example illustrates pessimistic locking with the PESSIMISTIC_WRITE
lock mode:
// read
Part p = em.find(Part.class, pId);
// lock and refresh before update
em.refresh(p, PESSIMISTIC_WRITE);
int pAmount = p.getAmount();
p.setAmount(pAmount - uCount);
The code in this example first reads some data. It then applies a PESSIMISTIC_WRITE
lock using a call to the EntityManager.refresh()
method before updating the data. The PESSIMISTIC_WRITE
lock locks the entity as soon as the transaction updates it. Other transactions cannot update the same entity until the initial transaction commits.
More New Features in JPA 2.0
In addition to the enhancements and new features described in the previous sections, JPA 2.0 can use Bean Validation to automatically validate an entity when it is persisted, updated, or removed. What this means is that you can specify a constraint on an entity, for example, that the maximum length of a field in the entity is 15, and have the field automatically validated when the entity is persisted, updated, or removed. You use the <validation-mode>
element in the persistence.xml
configuration file to specify whether automatic lifecycle event validation is in effect.
For more information about all the features in JPA 2.0, see JSR 317: Java Persistence 2.0.
Further Ease of Development
You've seen how new technologies such as CDI and Bean Validation, as well as support for features such as web fragments, Facelets, the no-interface view, and the Criteria API make it even easier to develop enterprise or web applications. However, additional usability improvements have been made in many areas of the Java EE 6 platform. In particular, annotations can now be used in more types of Java EE components. In addition, the set of annotations used for dependency injection has been standardized, making injectable classes much more portable across frameworks.
Annotations can now be used in more types of Java EE components. And the set of annotations used for dependency injection has been standardized.
Annotations in More Types of Java EE Components
The simpler annotation-based programming model that was introduced in Java EE 5 has been extended to other types of Java EE components, such as servlets and JSF components. For example, instead of using a deployment descriptor to define a servlet in a web application, all you need to do is mark a class with the @WebServlet
annotation, as shown below:
@WebServlet(name="CalculatorServlet", urlPatterns={"/calc", "/getVal"})
public class CalculatorServlet extends HttpServlet{
public void doGet(HttpServletRequest req, HttpServletResponse res) {
...
}
...
}
The @WebServlet
annotation is one of the annotations provided by Servlet 3.0 technology. Here are some other Servlet 3.0 annotations:
@WebFilter
. Defines a servlet filter in a web application@WebInitParam
. Specifies anyinit
parameters that must be passed to a servlet or servlet filter@WebListener
. Annotates a listener to get events for various operations on a particular web application context@MultipartConfig
. When specified on a servlet, indicates that the request the servlet expects is of the MIME typemultipart/*
A good example of the annotation support in JSF 2.0 is the simplified approach to configuring managed beans. Instead of registering a managed bean by configuring it in the JSF configuration file, faces-config.xml
, all you need to do is mark the bean with the @ManagedBean
annotation and set its scope with the RequestScope
annotation, as shown below:
Instead of creating deployment descriptors, you can annotate classes to specify servlet-related deployment information.
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
@ManagedBean(name="userBean")
@RequestScoped
public class UserBean {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public UserBean() {}
}
Some other JSF 2.0 annotations are:
@ManagedProperty
. Marks a bean property to be a managed property@ResourceDependency
. Declares the resources that a component will need@ListenFor
. Enables a component to subscribe to particular events with the component as the listener@FacesConverter
. Registers a class as aConverter
, that is, a class that can performObject
-to-String
andString
-to-Object
conversions@FacesValidator
. Registers a class as aValidator
, that is, a class that can perform validation
If you want the annotations to be processed — whether they are Servlet 3.0 annotations or JSF 2.0 annotations — you need to put the classes that are marked with these annotations in the WEB-INF/classes
directory of the web application. You can also put the classes in a JAR file in the WEB-INF/lib
directory of the application.
JSF 2.0 supports various annotations to specify configuration information.
As is the case for web fragments, you use the <metadata-complete>
element in the web.xml
file to instruct the web container whether to look for annotations. If you set <metadata-complete>
to false or do not specify the <metadata-complete>
element in your file, then during deployment, the container must scan annotations as well as web fragments to build the effective metadata for the web application. However, if you set <metadata-complete>
to true, the deployment descriptors provide all the configuration information for the web application. In this case, the web container does not search for annotations and web fragments.
With its support for annotations as well as its new ServletContext
methods, Servlet 3.0 makes the web.xml
file optional. In other words, you no longer need to include a web.xml
file in a WAR file for a web application.
Standardized Annotations for Dependency Injection
Dependency injection is a popular technique in developing enterprise Java applications. In dependency injection, also called inversion of control, a component specifies the resources that it depends on. An injector, typically a container, provides the resources to the component. Although dependency injection can be implemented in various ways, many developers implement it with annotations. Dependency injection is used heavily in Java development frameworks such as Spring and Guice. Unfortunately, there is no standard approach for annotation-based dependency-injection. In particular, a framework such as Spring takes a different approach to annotation-based dependency injection than that of a framework such as Guice.
However, JSR 330: Dependency Injection for Java, which is part of Java EE 6, changes that. The objective of this specification is to provide a standardized and extensible API for dependency injection.
SR 330, Dependency Injection for Java, provides a standardized and extensible API for dependency injection. You no longer have to work with vendor-specific annotations.
The API comprises a set of annotations for use on injectable classes. The annotations are as follows:
@Inject
. Identifies injectable constructors, methods, and fields.@Qualifier
. Identifies qualifier annotations. Qualifiers are strongly-typed keys that help distinguish different uses of objects of the same type. For example, a@Red Car
and a@Blue Car
are understood to be different instances of the same type. In this example,@Red
and@Blue
are qualifiers.@Scope
. Identifies scope annotations.@Singleton
. Identifies a type that the injector only instantiates once@Named
. AString
-based qualifier.
For example, the following class named Stopwatch
uses the @Inject
annotation to inject a dependency on a class named TimeSource
:
class Stopwatch {
final TimeSource timeSource;
@Inject Stopwatch(TimeSource TimeSource) {
this.TimeSource = TimeSource;
}
void start() { ... }
long stop() { ... }
}
The dependency injection can be extended to other dependencies. For example, suppose, you want to create a StopwatchWidget
class that has a dependency on the Stopwatch
class. You could define the class as follows:
class StopwatchWidget {
@Inject StopwatchWidget(Stopwatch sw) { ... }
...
}
In response, the injector finds a TimeSource
object, uses the TimeSource
object to construct a Stopwatch
object, and then constructs a StopwatchWidget
object with the Stopwatch
object. .
The standardized set of annotations specified by JSR 330 should make injectable classes portable across frameworks. You no longer have to work with vendor-specific annotations.
Note that CDI builds on JSR-330 and adds much functionality to dependency injection. This functionality includes automatic discovery and configuration of injectable classes, and an API to define new injectable classes at runtime — for example, to help integrate with third-party frameworks.
Profiles and Pruning
Java EE 6 introduces the concept of profiles as a way to reduce the size of the Java EE platform and better target it for specific audiences. Profiles are configurations of the Java EE platform that are designed for specific classes of applications. A profile may include a subset of Java EE platform technologies, additional technologies that have gone through the Java Community Process, but that are not part of the Java EE platform, or both. For example, consider a hypothetical profile for telephony applications. Such a profile might include Java EE web tier technologies, such as JSP and Servlet, EJB for the enterprise component model, and JPA for persistence. It would likely also include telephony-oriented technologies such as JSR 289: SIP Servlet v1.1, that have gone through the JCP process, but that are not part of the Java EE platform.
Profiles are Java EE platform configurations that are designed for specific classes of applications.
A profile is defined by following the JCP Community Process. In addition, the Java EE 6 Specification defines the rules for referencing Java EE platform technologies in Java EE Profiles. However, the Java EE 6 specification also underscores the principle that a new profile should be created only when there is a good reason for doing so. The specification states "The decision to create a profile should take into account its potential drawbacks, especially in terms of fragmentation and developer confusion. In general, a profile should be created only when there is a natural developer constituency and a well-understood class of applications that can benefit from it."
Profiles are intended to evolve independently of each other and independently of the Java EE 6 platform. In particular, profiles are initiated by submitting a Java Specification Request and are released on their own schedule, independently of any concurrent revision of the Java EE platform or of other profiles. This means that a profile such as the hypothetical telephony profile can evolve at a pace that is natural for its targeted industry, without being tied to the evolution of the Java EE platform or any other profile. Note however that it is highly recommended that profiles periodically synchronize with the platform, in particular when a major new platform is released. The objective is to preserve a common programming model and simplify the transfer of developer skills across the entire Java EE 6 family of products.
Web Profile
Java EE 6 defines the first profile, called the Web Profile. This initial profile provides a subset of the Java EE platform and is designed for web application development. The Web Profile includes only those technologies needed by most web application developers, and does not include the enterprise technologies that these developers typically don't need.
Java EE 6 defines the first profile, called the Web Profile. This initial profile is a Java EE platform subset for web application development.
Table 1 lists the technologies in the full Java EE 6 platform and indicates by checkmark (✓) which of those are in the Web Profile.
Table 1: Comparing the Technologies in the Java EE Platform and the Web Profile
Notice that the Web Profile includes a servlet container and all the traditional presentation technologies such as JSP, JSF, and the Standard Tag Library for JavaServer Pages (informally referred to as JSTL). EJB 3.1 Lite is available as a component model. There is also JPA for persistence and JTA for transaction management. And with the enhanced extensibility enabled by features such as web fragments, you can easily extend the Web Profile with additional frameworks or libraries such as JAX-RS.
Pruning
Another technique introduced in Java EE 6 for reducing the size of the platform is pruning. Pruning a technology means that the technology can become an optional component in the next release of the platform rather than a required component. Community reaction ultimately decides whether the candidate actually becomes an optional component. Pruning can reduce the size of Java EE platform products because implementors such as Java EE application server vendors may include or exclude a pruned technology in their implementation. However, if Java EE application server vendors do include a pruned technology, they must do so in a compatible way, such that existing applications will keep running.
Another technique introduced in Java EE 6 for reducing the size of the platform is pruning.
These are candidates for pruning:
- JSR 101: Java APIs for XML-Based RPC
- JSR 93: Java API for XML Registries 1.0 (JAXR)
- EJB Entity Beans (defined as part of JSR 153: Enterprise JavaBeans 2.0, and earlier)
- JSR 88: Java EE Application Deployment
Summary
With its support for profiles, significant new technologies such as JAX-RS, enhanced extensibility features such as web fragments, and ease of development improvements such as Facelets and platform-wide adoption of annotations, Java EE 6 delivers a Java EE platform that is more flexible, more powerful, and more developer friendly than ever before. You can try out an implementation of the Java EE 6 platform by downloading the Java EE 6 SDK. For a more in-depth understanding of the Java EE 6 platform, see the Java EE 6 Tutorial.
For More Information
- JSR 316: Java Platform, Enterprise Edition 6 (Java EE 6) Specification
- Java EE 6 Technologies
- Java EE 6 SDK
- Java EE 6 Tutorial
* As used on this web site, the terms "Java Virtual Machine" and "JVM" mean a virtual machine for the Java platform.