Migrating EJB2 Entity Beans to EJB3 and JPA
Impossible is nothing. Read on to learn how to migrate all of the EJB2 Entity Beans from a legacy project to EJB3 Entity Beans with JPA.
Join the DZone community and get the full member experience.
Join For FreeScenario: you have to migrate all of the EJB2 Entity Beans from a legacy project to EJB3 Entity Beans with JPA. Hibernate will be your JPA implementation and Spring Framework cannot be used. No other layer that the EJB2 Entity Beans layer will be migrated.
The application also contains an EJB2 Session Beans layer. This one will not be replaced, but updated to work with the new EJB3 Entity Beans. (Note: this article will not explain the J2EE architecture. If you want to find more about that, please check here. Please take the patterns presented in the link with a grain of salt. Some of them are obsolete, but some still make sense.)
Assumption: The 10K feet view of your legacy back end layers looks like below:
EmployeeDelegate: a Business Delegate pattern implementation and it is the only class that exposes the available functionality to a client. More about the Business Delegate pattern here.
initializeEmployeeSessionFacadeHome: a function that will locate and create the EmployeeSessionFacadeHome and return an EmployeeSessionFacade interface.
EmployeeSessionFacadeBean: the session facade that will actually contain the functionality exposed by EmployeeSessionFacade.
findEmployeeHome: is the function responsible for finding the EJB2 Entity Bean for working with employee data. This function will return EmployeeHome which is an interface.
EmployeeBean: is actually the class that contains the code to save and remove and work with employee data.
Now, the standard classes and interfaces of an Employee EJB2 CMP entity bean are shown below:
EmployeeHome: used to locate the bean and define the create and remove operations.
EmployeeBean: the entity bean that is actually managed by the container and implements the operations.
Employee: is the local interface of the bean.
EmployeeDTO: a data transfer object used to transfer data between various layers.
(Note: I will not detail here what an EJB 2 Entity Bean is or how it is configured.)
If you want to find out more about this subject, please check the official documentation.
Migrating Employee Bean From EJB 2.1 to EJB 3
This is assuming that you want to do this while keeping EmployeeSessionFacade as an EJB 2 session facade bean.
When migrating the new EJB 3 entity beans, I will try to expose the same functions as the old EJB 2 Entity Beans were exposing in order to minimize the changes in the other layers that are using that beans.
The specifications for EJB 3 Entity Beans also mention the Home Local and Remote interfaces.
The EJB3Entity class, which will be the base class of all EJB3 Entity Beans:
public interface EJB3Entity<ID> {
ID getId();
void setId(ID id);
}
and the Employee EJB3:
@Entity
@Cacheable
@Table(name = "employee")
public class Employee implements EJB3Entity<Integer>, Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id;
@Column(name = "name", length = 100)
private String name;
@OneToOne(mappedBy="department_id")
private Department department;
...............
}
The EmployeeHome interface looks like below:
where BaseHome is exposing the same functions as EmployeHomeEJB2 was exposing (here, the name of the functions do not contain the prefix ejb).
The reason for the BaseHome to expose the same function is that if we keep the same function names (as per the EJB2 version), then the EmployeeSessionFacadeBean will suffer minor changes during this migration.
The Remote EmployeeHome interface looks like this:
@Remote
public interface EmployeeHome extends BaseHome<Employee, Integer, EmployeeDTO> {
List<Employee> findAll() throws Exception;
//more functions here
}
Please see below the class diagram for the Employee EJB3 Entity Bean:
and below how JPA is used for the findAll function:
public List<Employee> findAll() throws Exception {
String sqlQuery = "select emp from Employee emp order by emp.name ";
Query query = entityManager.createQuery(sqlQuery);
List<Employee> list = query.getResultList();
return list;
}
And now, let’s change EmployeeSessionFacadeBean(which is still an EJB 2 session facade) to use the new EJB3 Entity Bean:
public class DmsAnnotationCommtTypeSessionFacadeBean implements SessionBean {
/**
* this is an example that works with Wildfly 10
*/
private void findEmployeeHome(...) throws EJBException {
if (employeeHome == null) {
String entityBeanJndi = "java:jboss/exported/EMPLOYEE-EAR/EmployeeEJBs/EmployeeSessionFacade!com.myawesomeapp.employee.session.EmployeeSessionFacadeHome";
Context ctx = getContext();
Object ejb3EntityHome = ctx.lookup(entityBeanJndi);
employeeHome = (EmployeeHome)ejb3EntityHome;
}
return employeeHome;
}
public List<EmployeeDTO> findAll() throws EJBException, FinderException {
List<EmployeeDTO> dtoList = new ArrayList<EmployeeDTO>();
try {
List<Employee> employeeList= employeeHome.findAll();
List<EmployeeDTO> dtoList = convertToDTO(employeeList);
} catch (Exception e) {
throw new EJBException(e);
}
return dtoList;
}
.....
}
...where:
findEmployeeHome: it is used to locate the home interface of the new EJB3 entity bean. In this case, the entityBeanJndi string is specific to Wildfly 10.
If you want to find out more about Wildfly 10 and EJBs, please check here.
The findAll method is a good example of how simple it is now to work with the new EJB3 entity bean.
Conclusion: This article explained how with properly designed interfaces, it is possible to limit the amount of work needed to migrate from the old EJB 2 Entity Beans to the new EJB 3 Entity Beans and JPA.
(Note: In a real project the speed of migration has been 10 to 15 entity beans migrated per day using this design. Of course in real life the user cases are more complicated, for instance there are also complex search queries that require this architecture to be extended in order for that use cases to be also addressed.)
Opinions expressed by DZone contributors are their own.
Comments