Meera has posted 70 posts at DZone. You can read more from them at their website. View Full User Profile

EJB 3.0 and Spring 2.5

08.27.2008
| 56111 views |
  • submit to reddit

Why is it that developers from these two communities don't like to see eye to eye? I have been using both Spring from its inception, and EJB's from 2001. Just like everyone else did, I just dreaded the huge amount of XML we had to write for both of these; configuration files in Spring, and deployment descriptors in EJB 2.x. However, Java 5 came to our rescue and now annotations have mostly replaced XML files in both these. But, after having used these two latest versions Spring 2.5 and EJB 3.0, I think that they complement each other, rather than compete with each other. There are certain features which are powerful in Spring, and equal number of features powerful on the EJB side as well.

Many developers fail to understand, that Spring is a popular non-standard framework created by Spring Source, while EJB 3.0 is a specification which is supported by major JEE vendors. There are a few developers with whom I have worked earlier, prefer to use standard specification, and they chose EJB2.x/ and are moving now to EJB 3.0. However, there isn't anything stopping you from using Spring along with EJB, is it? The complaint I have heard many times is: We can't use non-standard framework". The same developers who complain about Spring being non-standard use home grown frameworks, which was and will be forever so hard to even decipher. How can it be a specification when a couple of developers write several thousand lines of code?

Also, a recent article published here at Javalobby by Adam Bien showed the trend moving towards EJB 3.0, right? Anyway, in this article we will see how by adding a few lines in your Spring configuration file, you can seamlessly use EJB 3.0 components within your Spring application.

Back to our EJB 3.0 and Spring 2.5 article, we are going to see how easy and simple it is to access EJB 3.0 components in Spring by using its powerful dependency injection mechanism to inject an instance of our Customer session bean. This Customer session bean, in turn uses the Entity Manager for the CRUD operations on the Customer Entity.

Here are the detailed steps:

Step 1: Create a simple JPA Entity.

The Java Persistence API (JPA) is defined as part of the Java EE 5 specification. Creating entities using JPA is as simple as creating a POJO with a few annotations as shown below:

package com.ejb.domain;

import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

/**
*
* @author meerasubbarao
*/
@Entity
@Table(name = "CUSTOMER", catalog = "", schema = "ADMIN")
public class Customer implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Column(name = "CUSTOMER_ID")
private Long customerId;
@Column(name = "FIRST_NAME")
private String firstName;
@Column(name = "LAST_NAME")
private String lastName;
@Column(name = "MIDDLE_NAME")
private String middleName;
@Column(name = "EMAIL_ID")
private String emailId;

public Customer() {
}

public Customer(Long customerId) {
this.customerId = customerId;
}

public Long getCustomerId() {
return customerId;
}

public void setCustomerId(Long customerId) {
this.customerId = customerId;
}

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public String getMiddleName() {
return middleName;
}

public void setMiddleName(String middleName) {
this.middleName = middleName;
}

public String getEmailId() {
return emailId;
}

public void setEmailId(String emailId) {
this.emailId = emailId;
}


}

Step 2: Create a EJB 3.0 Session bean.

This session beans uses the Entity Manager for the Create Read Update Delete (CRUD) operations for the Customer Entity we created in Step 1. The CRUD opertions are also published as web methods by adding a few basic annotations.

The Interface:

 
package com.ejb.service;

import com.ejb.domain.Customer;
import java.util.Collection;
import javax.ejb.Remote;

/**
*
* @author meerasubbarao
*/
@Remote
public interface CustomerService {

Customer create(Customer info);

Customer update(Customer info);

void remove(Long customerId);

Collection<Customer> findAll();

Customer[] findAllAsArray();

Customer findByPrimaryKey(Long customerId);
}

The Implementation Class:

package com.ejb.service;

import com.ejb.domain.Customer;
import java.util.Collection;
import javax.ejb.Stateless;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.jws.WebMethod;

/**
*
* @author meerasubbarao
*/
@WebService(name = "CustomerService", serviceName = "CustomerService", targetNamespace = "urn:CustomerService")
@SOAPBinding(style = SOAPBinding.Style.RPC)
@Stateless(name = "CustomerService")
public class CustomerServiceImpl implements CustomerService {

@PersistenceContext
private EntityManager manager;

@WebMethod
public Customer create(Customer info) {
this.manager.persist(info);
return info;
}

@WebMethod
public Customer update(Customer info) {
return this.manager.merge(info);
}

@WebMethod
public void remove(Long customerId) {
this.manager.remove(this.manager.getReference(Customer.class, customerId));
}

public Collection<Customer> findAll() {
Query query = this.manager.createQuery("SELECT c FROM Customer c");
return query.getResultList();
}

@WebMethod
public Customer[] findAllAsArray() {
Collection<Customer> collection = findAll();
return (Customer[]) collection.toArray(new Customer[collection.size()]);
}

@WebMethod
public Customer findByPrimaryKey(Long customerId) {
return (Customer) this.manager.find(Customer.class, customerId);
}


}

Step 3. Compile, Package and Deploy to an application server.

There are no server specific annotations in either the Entity class or the Session bean. Package the entity class, the session bean interface, implemetation class along with the persistence.xml file in a JAR file. Since I am deploying this application to GlassFish, I am using the default persistence provider which is TopLink. Start your application server, and deploy this JAR to it. The contents of persistence.xml file is as shown below:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="SpringAndEJBPU" transaction-type="JTA">
<provider>oracle.toplink.essentials.PersistenceProvider</provider>
<jta-data-source>spring-ejb</jta-data-source>
<properties>
<property name="toplink.ddl-generation" value="drop-and-create-tables"/>
</properties>
</persistence-unit>
</persistence>

Once your application is deployed, make sure you check the JNDI name of your session bean. In GlassFish, click on the JNDI Browsing toolbar button to view the JNDI names.

 

Step 4: Test the Stateless Session beans.

Since my session beans are published as web services, I can just easily test them using either the test page provided by GlassFish application server, or by using SoapUI and make sure that my Customer entity can be persisted using the CustomerService session bean. I am using the default test page provided by Glass Fish for web services:

Step 5: Create a Spring Bean.

Here, I define a simple CustomerManager interface, and an implementation class; just to show how things are wired using Spring.

package com.spring.service;

import com.ejb.domain.Customer;

/**
*
* @author meerasubbarao
*/
public interface CustomerManager {

public void addCustomer(Customer customer);
public void removeCustomer(Long customerId);
public Customer[] listCustomers();


}
package com.spring.service;

import com.ejb.domain.Customer;
import com.ejb.service.CustomerService;

/**
*
* @author meerasubbarao
*/
public class CustomerManagerImpl implements CustomerManager {

CustomerService customerService;

public void setCustomerService(CustomerService customerService) {
this.customerService = customerService;
}

public void removeCustomer(Long customerId) {
customerService.remove(customerId);
}

public Customer[] listCustomers() {
return customerService.findAllAsArray();
}

public void addCustomer(Customer customer) {
customerService.create(customer);
}
}

Step 6: Injecting the EJB 3.0 Session bean into our Spring Beans.

As seen above, I am using setter injection to inject an instance of Customer Service and in turn invoke a method on the Stateless session bean. How do we inject an EJB into a Spring bean? It is quite simple as shown below in the Spring configuration file:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd">
<jee:jndi-lookup id="customerService" jndi-name="com.ejb.service.CustomerService">
</jee:jndi-lookup>
<bean id="manageCustomer"
class="com.spring.service.CustomerManagerImpl">
<property name="customerService" ref="customerService" />
</bean>
</beans>

The most important aspect here is the wiring of the EJB within the Spring configuration using the <jee:jndi-lookup> element in the jee schema.

<jee:jndi-lookup id="customerService" jndi-name="com.ejb.service.CustomerService">
</jee:jndi-lookup>

Next, we need to wire this with our Spring bean which is done as shown below:

    <bean id="manageCustomer"
class="com.spring.service.CustomerManagerImpl">
<property name="customerService" ref="customerService" />
</bean>

Step 7: Test

How do we know that it works. Lets create a simple class and test.

package com.spring.client;

import com.ejb.domain.Customer;
import com.spring.service.CustomerManager;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringAndEJBMain {

public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("SpringXMLConfig.xml");

CustomerManager service = (CustomerManager) context.getBean("manageCustomer");
Customer customer = new Customer();
customer.setFirstName("Meera");
customer.setLastName("Subbarao");
customer.setMiddleName("B");
customer.setEmailId("meera@springandejb.com");
customer.setCustomerId(new Long(1));

service.addCustomer(customer);
for (Customer cust : service.listCustomers()) {
System.out.println(cust.getFirstName());
System.out.println(cust.getLastName());
System.out.println(cust.getMiddleName());
System.out.println(cust.getEmailId());

}
service.removeCustomer(new Long(1));

}
}

And here is the sample output from my IDE:

 

We can go back to our GlassFish web services test page, and test the findAll method. It should have two entities.

In this article, we saw how quick and easy it was to create JPA entities, persist them using Entity Manager from within our session bean. We also saw how easy it was to publish web services by adding a few annotations to our session beans. Next, we saw how to create a simple Spring bean, inject our session bean, and finally call methods on this session bean from our Spring application.

Spring isn't in my opinion a replacement for EJB 3.0, you can mix and match EJB 3.0 and Spring 2.5 components to get the best of both.

Published at DZone with permission of its author, Meera Subbarao.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Gopal Krishna replied on Wed, 2011/04/20 - 11:52pm

Hi Meera , Many Thanks to your example. i succeded with that one eventhough i am new to spring and ejb. but i have question now i am working on banking project here i have to use JTA in spring with ejb3.0. can u provide an example spring + EJB+JTA

Hari Prasath replied on Fri, 2011/06/17 - 3:22am

i need to integrate ejb3 with struts2 but it showing error while integrating it (org.apache.jasper.JasperException: The Struts dispatcher cannot be found.)  can u give me a sample code to integrate these two things

thanksin advance.

hariprasathbe@gmail.com

Philip Puthenvila replied on Wed, 2013/02/27 - 6:14pm

 Hi Meera

I am just wondering have you got any article for the same thing expalined in this article using EJB3 and Spring3 . If yes please send me a link, or could you write one I am new to Spring, trying to understand the details.

Regards

Philip

Chege Kinuthia replied on Tue, 2013/08/06 - 2:38am

 Can the same work in a spring mvc application. How do i inject an Ejb into the controller?

Peter Stavrinides replied on Wed, 2014/01/15 - 8:36am

I think this a very interesting topic, and progress in competing technology is usually a good thing for consumers/adopters opening up their options.

Software development, but particularly Java, is moving ahead very rapidly. Reasons behind past hostility on this topic were directly related to complexity and bloat in EJB 2 and earlier, which was the catalyst for the Spring framework's rise to prominence and the 'back to basics' style of development using POJO'S sought after as a result. Many developers were burnt during this time, and frameworks like Spring, Seam, Tapestry etc brought some of the fun back into Java development, that quite frankly gained a reputation for being cumbersome and over complicated.

Developers who experienced this will still be skeptical of 'standards' as such, and won't adopt EJB again easily. That said EJB is remodeled and is very attractive in its own right now, as influences of modern lightweight best practices and patterns like the dependency inversion principle have been incorporated successfully back into EJB and yes its all Java code in the end, so it can all be made to work together, which brings me to my main point, complexity and bloat are the old enemy, it caused the failure that was EJB 2, and it can resurface in another form today simply by introducing higher barriers to entry for new developers, including framework bloat, shortened shelf-life of code meaning increased cost and lowered productivity. Changing to a new approach should involve a marked improvement, and not just matching like for like as there is a time cost as well as the most dreaded factor of change giving rise to unforeseen issues (rippling effect) deep within a code base bringing further costs.




Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.