October 1st, 2010 by Lincoln Baxter III

Spring to Java EE – A Migration Experience

So Java EE 6 is out, and you’ve decided to give it a go. You’re trying to port an existing application over to the new stack (or are trying to create a new one for the first time,) but exceptions are bursting through the seams and you just can’t seem to get things to work. If you’re familiar with Spring and Hibernate (with all the joy that is OpenSessionInView or OpenSessionInConversation,) more than likely the problems you’re having are related to the Java Persistence API (JPA), combined with Enterprise Java Beans (EJB). Contexts and Dependency Injection (CDI) should be a familiar face if coming from Spring, but things are subtly different in the world of Java EE.

Disclaimer: I work for JBoss and participate in creating some of the technologies I describe.

The trouble you’re having, however, is most likely due to the fact that you’re actually trying to solve problems that don’t need to be solved. When I first made the switch to Java EE 6 from Spring – for my own personal project – Spring’s dozens of extensions, and using Hibernate Object Relational Mapping (ORM) directly, managing transactions myself, I was trying to do things “the Spring way,” in other words – configuring everything up the wazoo, but let me try to explain some things for you that should help clear the fuzz of attempting to migrate to Java EE; they are things I ran in to, and would likely happen to others as well.

Before you start, go ahead and download your application server of choice, which at this point should probably be one of either: JBoss AS 7, or GlassFish 3.x. (I recommend AS7 not because I have to, but because I believe it is currently the top of the line app-server.)

The biggest difference you’ll find is, “Java EE already does that for you.”

Nearly every application requires the same set of basic features: persistence, transactionality, (dependency injection is typically assumed at this point,) and a web-tier view-layer or web-services. The first thing I have to say is: “Don’t freak out when I say Enterprise Java Beans (EJB)” – they’ve truly become a system worthy of attention, and if you’re going to take advantage of the Java EE stack, you’re going to want them around; EJB 3.1 today is miles apart from what it once was, can be used standalone in WARs, and requires just one annotation to configure – soon, with JBoss AS 7, Enterprise Java Beans may simply be an extension built on CDI, like everything else.

To start, I’ll review some of the problems I encountered and solved during my first transition between the Spring and Java EE 6 technologies; most – if not all – of these were due to my lack of technical understanding, the mindsets are truly very different; the results are striking.

Configuring the System – “It’s all just XML in the end.”

This one is simple. Where Spring has /WEB-INF/applicationContext.xml files of various types, Java EE has various distinct configuration files for each API in the framework WAR. Some of these files are required to activate the API, but some are not. The following chart overviews the most common of these configuration files – there is more to Java EE, but chances are these are all you’ll need to get started. Be careful! If these files are in the wrong place, you will not have a working system!

Java EE API Config File Location Required to Enable
Java Persistence API /META-INF/persistence.xml Yes
Enterprise Java Beans WAR /WEB-INF/ejb-jar.xml No
Java Server Faces /WEB-INF/faces-config.xml No
Contexts & Dependency Injection /WEB-INF/beans.xml Yes
Web Configuration /WEB-INF/web.xml No
JAX-RS (REST Web Services) /WEB-INF/web.xml No

You should also know that most of these files require some sort of schema, or “XML header” that tells the Application Server (JBoss Application Server, GlassFish, Etc…) which version of the technology to use, since most APIs attempt some level of backwards compatibility. This is similar to including new schemas in Spring’s applicationContext.xml.

EJBs can be defined via annotations alone, and require no configuration file in order to enable them. JAX-RS is similar, since no configuration file is required when using a Java EE 6 certified Application Server such as JBoss Application Server, everything can be specified through annotations once it is enabled.

Configuration of modules in JAR files:

One of the greatest features of Java EE APIs is the ability to break application code into separate reusable JAR files – where each individual JAR contributes configuration and code to the system they are included in; for instance, you might run multiple applications for your business, but each one must have the same data access providers. You’d create a shared domain-model JAR file and include it in each application. All the configuration would be contained in that JAR, and would be done using the same set of configuration files, placed in the JAR’s META-INF directory:

Java EE API Config File Location Required to Enable
Java Persistence API /META-INF/persistence.xml Main app must include own config file.
Enterprise Java Beans WAR /META-INF/ejb-jar.xml No
Java Server Faces /META-INF/faces-config.xml No
Contexts & Dependency Injection /META-INF/beans.xml Yes
Web Configuration /META-INF/web-fragment.xml No
JAX-RS (REST Web Services) /META-INF/web-fragment.xml No

Note that some of the file names are different from those that are used in the main application itself.

The Application Server Configuration

In addition to the application configuration, one of the most notable differences between Spring and Java EE is that you actually need to know how to use the application server itself. Spring replaces application server configuration with application configuration (sometimes more convenient, sometimes less convenient, but the same result in the end.) In order to use JPA and transactions (covered later,) you will want to know how to use the transactional data-source feature of the Java Enterprise Application Server, since it makes setting up transactions as simple as writing a plain Java class with an annotation.

Keep in mind that each of these configuration files may have a different syntax and format, since they are produced by different companies. These files should be used to configure settings that must exist in order for the application to run, and should be considered a natural extension to the Java EE module configuration files.

JBoss Application Server Documentation can be found here, online.
Container Configuration File
JBoss AS 6 – General Config /WEB-INF/jboss-web.xml
JBoss AS 6 – Data Source Config ${JBOSS_HOME}/server/default/deploy/*-ds.xml (must be placed in the actual JBoss server deploy directory, more info can be found here.)
Sun GlassFish v3 AS – General Config /WEB-INF/sun-web.xml
Sun GlassFish v3 AS – Data Source Config You must use the asadmin command to process a sun-resources.xml, use asadmin to explicitly define a data source, or create a data source in the web-admin console.

If your application depends on a transactional data source, this is the place to define it – preventing manual configuration of the application server, which can be a very repetitive, monotonous task. This configuration usually only needs to happen once per-server, and allows you to keep database passwords secret, data sources controlled and separate, and JMS queues centralized; though, if you want a standalone application/data-source configuration, then you should think about using these custom configuration files.

Contexts & Dependency Injection for Java – aka Beans

Where spring has @Autowired, Java EE (CDI to be more specific) has @Inject. The parallel is really quite straight-forward, since every class in a WAR or JAR file (that has a beans.xml file!) is automatically a bean in CDI, any class can be provided or scoped using dependency injection, just like a bean that would be defined in applicationContext.xml in a Spring application.

Before we get started, though – remember that you need to create an empty /WEB-INF/beans.xml file, or your system will not start the CDI container. Technically, you can only inject beans that are themselves in a bean archive (not just any class). However, you can use a producer method to pull in a class from a non-bean archive and make it a bean (or you can use Seam XML to add beans that aren’t in an archive that has a beans.xml file.)

A simple CDI bean
public class UserCredentialsBean

Wait, that’s it? Well, you have a few more options when it comes to managing these beans and deciding how long they will “live,” or how long each bean instance will remain active.

Every bean can be assigned to a “scope,” which is really defining the context in which the bean is relevant. For example, it doesn’t make sense for a logged-in user’s authentication credentials (username/password) to be retained longer than that user’s session, so you would place the bean containing that information in the Session Scope (which is just a nice, clean way of saying that we are storing that information in the HttpSession object, and when the HttpSession object dies, so does everything in Session Scope for that user.) This is done using the @SessionScoped annotation.

A session scoped bean
public class UserCredentialsBean

In reality we would probably leave the details of authenticating users up to a framework like Seam Security, but just consider this as an example.

There are also several more built-in scopes:

Annotation Lifespan Contextual Object
@RequestScoped From the beginning to the end of each individual HTTP request. HttpServletRequest
@ConversationScoped Begins when the request begins and ends when the request ends and the conversation is not in a long-running state. Calling conversation.begin() states intent for the scope to perpetuate to additional requests. Calling conversation.end() marks the conversation to end on the when the current request ends – but note that if the session is terminated, all active conversations will also be terminated. HttpSession
@SessionScoped From the first request starting when httpServletRequest.getSession() method is called, to the last request when httpSession.invalidate() is called. HttpSession
@ApplicationScoped For the entire duration of the running application; from post-server startup, to pre-shutdown. ServletContext
@Dependent (default) Controlled by the object in which it was @Injected. If @Injected into a @SessionScoped bean, for example, the @Dependent bean will also be @SessionScoped. This means that there can be multiple separate instances of the same @Dependent bean that are @RequestScoped, or any other scope for that matter. This is similar to, but not quite the same as Spring’s @Prototype scope. *** The bean into which this bean was injected.

Other custom scopes can be created as needed, and some frameworks such as the Seam Faces Module even provide additional scopes for you. But let’s look at how we inject an instance of our UserCredentialsBean into another bean.

Injecting one bean into another
public class AuthorizationBean
    private UserCredentialsBean credentials;

These are the basics; no configuration required. We can also scope the AuthorizationBean in order to control how long that lives as well, but we have a very subtle issue going on here.

Scoping a bean to control lifecycle
public class AuthorizationBean
    private UserCredentialsBean credentials;

We are injecting a @SessionScoped bean into an @ApplicationScoped bean, which in Spring, might cause two problems. We’ll see, though, that these problems have already been solved in Java EE:

  1. In Spring, when the the AuthorizationBean is created, there may not be any active user sessions, and the container may not be able to create the UserCredentialsBean dependency – resulting in a nasty exception. In CDI, however, the container knows that it will not be able to get a @SessionScoped object at that point in the life-cycle, so it waits until the credentials are accessed until it attempts to get an instance of UserCredentialsBean. If you access that object outside of the active scope, you’ll still get an exception, but that’s a different problem, one that can easily be solved with good application design. (In other words, “you shouldn’t be doing that.”)
  2. In Spring, when the @ApplicationScoped AuthorizationBean is created, assuming that it can get a hold of our @SessionScoped UserCredentialsBean, the instance that is injected will be the instance that remains for the life of the bean into which it assigned. This means that the same UserCredentialsBean will be used for all invocations and processing in our single instance of the AuthorizationBean, and that’s most likely not what we want, there would be some pretty nasty bugs (users sharing permissions, etc.) The problem can be solved by turning the bean into a “dynamic-proxy,” in the Spring configuration. In CDI, however, this is again taken care of us already, since the container knows that @SessionScoped beans may not live as long as an @ApplicationScoped bean, and that there may be more than one active Session. CDI will actually find the correct @SessionScoped UserCredentialsBean, and use that when performing operations on the parent bean, automatically making sure that the right objects are used. Sweet!

Interacting with Beans through Java APIs

If you are trying to get a handle to a bean while working in a part of the system that does not support dependency injection for some reason (@Inject in CDI, @Autowired in Spring), it’s sometimes required to ask the framework for a bean instance manually.

In Spring you can ask for an instance of a bean (an object that you can actually use to do some work,) using Java APIs – this assumes you’ve set up the appropriate listeners in your web.xml configuration.

Bean lookup - Spring
MyBean bean = ApplicationContext.getBean(“myBean”);

At first glance, you might think this is not possible using CDI, but really it would be more correct to say that it is not yet as convenient. There are technical reasons for this lack of convenience, but while I disagree with that aspect, I do understand the reason for doing things the way they were done.

In CDI, there is a concept of a @Dependent scoped bean, which adopts the scope of the bean into which it was injected. This means that when we use Java APIs to create a direct instance of a @Dependent scoped bean, that it will not be stored into a context object (the Request, Session, Application, or other common scope.) In other words, @PostConstruct methods will be called when the bean is created, but since there is no way for CDI to tell when the bean will be destroyed (because it is not stored in a context – which would normally take care of letting CDI know when to do its cleanup,) @PreDestroy annotated methods cannot be called automatically. You have to do this yourself, and for that reason the bean-creation process is slightly more complicated – though not that much more complicated – than in Spring; e.g: “With great power comes great responsibility.”

Before you read the following code, I quote from a CDI developer who agrees that things need to be simplified a little bit for convenience – so expect that in an upcoming release of CDI: “I can see that people are going to look at the instance creation code and say that CDI is too complicated. We’ve agreed that it’s lame that a utility method is not provided by CDI for those cases when the developer just has to use it.

CDI’s equivalent to the ApplicationContext is called the BeanManager, and can be accessed through JNDI or several other methods (the easiest method is to use the “JBoss Solder” or “DeltaSpike” projects which provide a BeanManagerAccessor.getBeanManager() static method very similar (but more generic) to Spring’s WebApplicationContext utility class:

Get BeanManager from Solder/DeltaSpike:

Get BeanManager from Solder/DeltaSpike
public BeanManager getBeanManager()
    return BeanManagerAccessor.getManager();
Note: the “getBeanManager()” function is provided by the base class BeanManagerAware. Don’t worry about how this works for now, unless you want to get into JNDI and server specific stuff.
NOTE: This is the recommended way of accessing the BeanManager if you cannot use @Inject BeanManager directly. The below options are purely for example, and should be avoided if possible.

Get BeanManager from ServletContext (in a JSF request):non-standard

Right now this is non-standard, but works in most CDI implementations and is proposed for version 1.1.

Get BeanManager in a JSF environment
public BeanManager getBeanManager()
    return (BeanManager) ((ServletContext) facesContext.getExternalContext().getContext())

Get BeanManager from ServletContext (in any Web Servlet Request): non-standard

Right now this is non-standard, but works in most CDI implementations and is proposed for version 1.1.

Get BeanManager in a Servlet environment
public BeanManager getBeanManager(HttpServletRequest request)
    return (BeanManager) request.getSession().getServletContext()

Get BeanManager from JNDI (does not require a Web Request): standard

Get BeanManager from JNDI
public BeanManager getBeanManager()
    try {
        InitialContext initialContext = new InitialContext();
        return (BeanManager) initialContext.lookup("java:comp/BeanManager");
    catch (NamingException e) {
        log.error("Couldn't get BeanManager through JNDI");
        return null;

Once we have a BeanManager, we can ask the container to give us an instance of a bean. This is the slightly more complicated part, but that complication is necessary; again, “with great power comes great responsibility.”

Instantiating a Bean using the BeanManager:

Don’t get scared, you only need to write this once and put it in a utility class (or use WeldX which provides this functionality already.)

Get a bean instance
public static <T> T getContextualInstance(final BeanManager manager, final Class<T> type)
    T result = null;
    Bean<T> bean = (Bean<T>) manager.resolve(manager.getBeans(type));
    if (bean != null)
        CreationalContext<T> context = manager.createCreationalContext(bean);
        if (context != null)
            result = (T) manager.getReference(bean, type, context);
    return result;

Take warning, though, that the CreationalContext object this method creates before we can get a reference to the bean is the object that must be used when “cleaning up” or “destroying” the bean, thus invoking any @PreDestroy methods. (Note, because the method above is actually losing the handle to the CreationalContext object, it will not be possible to call @PreDestroy methods on @Dependent scoped objects, and there-in lies the reason why creating beans in CDI is slightly more involved, and why this convenience was omitted – in order to force people to decide for themselves how to handle behavior that might be very important architecturally.) This is the same issue that I mentioned above, when discussing cleaning up bean scopes.

Interacting with Beans through Custom Scopes

The best way to manage instances of objects is to access them via injection, not through the Java API; in fact, any time you find yourself needing access to a bean through a Java API, you should ask yourself why you are not operating within the realm of dependency management via @Inject. Frequently, you can fix the problem at the root – just like Seam Faces Module does for Java Server Faces (JSF) – by adding injection support in other user-objects such as validators, converters, and more, so that you can use injection with ubiquity. Or the Seam Wicket, Seam Servlet, Seam JMS, and other Seam modules.

Sometimes adding injection support this means registering a custom scope, which can sound complex, but is frequently as simple as attaching a bean scope to an existing contextual object such as the HttpSession for @SessionScoped, or the JSF UIViewRoot, for @ViewScoped in Seam Faces.

The “Java Persistence API” vs. “the Spring way”

Spring: First you set up a data-source in applicationContext.xml, then you set up a connection pool, then you configure Hibernate to use that connection pool as a data source, then you tell Hibernate where to get its transaction manager, then you need to set up a byte-code assist library (AoP) in order to enable cross-bean transactionality and security via annotations.

Not only is that a good bit confusing to work through (unless you’ve already done it a few times,) but when I started using the actual Spring setup, I got LazyInitializationExceptions all over the place because I didn’t first understand what a Hibernate session was, which took another few days to understand and get working – I’ll get back to that in a bit when I talk about Extended Persistence Contexts in Java EE – something you should be using if you can. In my opinion Spring did a tremendous disservice by trying to hide the persistence context as though it were just an adapter. The persistence context is crucial to how the ORM model works; you need both the entities and the persistence context in your toolbox in order to be successful.

Put the Spring configuration aside for a moment; now let’s talk about Java EE – all you need is /META-INF/persistence.xml, of which I’ve provided a quick working example below.

For the purposes of these examples, I’m going to assume that you are using JBoss AS 6, or have already installed Hibernate on GlassFish (which is very easy to do, and I recommend since trying to get my application to run on the default EclipseLink has given me a lot of problems when attempting to migrate from Hibernate; Hibernate is still the industry leader in terms of stability and functionality, in my opinion.)

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
	<persistence-unit name="example">
	    <jta-data-source> java:/DefaultDS </jta-data-source> 
      <!-- Data source for GlassFish if you aren't using JBoss AS 6.0...
		<jta-data-source> jdbc/__default </jta-data-source> 
			<!-- Properties for Hibernate (default provider for JBoss AS, must be installed on GlassFish) -->
			<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
			<property name="hibernate.show_sql" value="true"/>
			<property name="hibernate.format_sql" value="false"/>

But where’s the configuration for transactions? Where do you set up database connections and connection pools? Well, transactions just work automatically if you are using a JTA data-source (more on that in a bit,) you can set up data-sources (and should set them up) in your application server configuration (meaning that since your data source configuration is not stored in the application itself, when your application is deployed it will use the data-source that is available on that server automatically,) and yes: “it’s that simple.” The mentality is a little different, but the end product is a much smaller, “weightless” application. You can set up data sources yourself, but for that you’ll need to read the documentation about your web application server. These files are typically kept separate in order to keep passwords out of your application source code or version control repository.

So great, we have persistence set up; but what about those Hibernate LazyInitializationExceptions that we all love to hate? We’ll talk about that in the next section, but this is where EJB’s come in, and again, don’t get scared. It’s really very simple to make an EJB, and once you learn what they actually do for you, I’d be surprised if you want to go back.

Here I’d like to mention that with the addition of a tool such as Seam 3‘s Persistence Module, you can use JPA and the PersistenceContext in standard CDI beans without EJB – Seam 3 also provides the same consolidated support for managed transactions, security, remoting, and messaging that is provided when you use EJB. Seam 3’s mission is to provide a unified programming model (standardized on CDI) to the Java Enterprise Framework.

As we continue, I’m going to assume a little familiarity with Object Relational Mapping in general, that you know you need to configure your data entities with annotations(or XML) so that the system knows how to map your data to the database. If you are familiar with Hibernate, then JPA should be no stretch by any means of imagination because Hibernate is a JPA implementation. In fact, you can use most of the same annotations!

A simple EJB
public class Service
This is an EJB with Persistence (that doesn't do anything)
public class Service
    @PersistenceContext(type = PersistenceContextType.EXTENDED)
    private EntityManager em;
This is an EJB that can save JPA entities to a database (a DAO)
public class Service
    @PersistenceContext(type = PersistenceContextType.EXTENDED)
    private EntityManager em;

    public <T> void create(final T entity)

    public <T> void delete(final T entity)

    public <T> T findById(final Class<T> type, final Long id)
        Class<?> clazz = getObjectClass(type);
        return result = (T) em.find(clazz, id);

    public <T> void save(final T entity)

That’s all it takes to create a service class that knows how to interact with the database, so assuming that you have a few @Entity classes defined, you’ll be good to go. If you want more information on getting started with Hibernate and JPA, you can start here. But wasn’t that simple? About 10 real lines of code and you’ve got a fully functional database access object. You do need to create actual @Entity objects to save to the database, but that’s for a separate tutorial.

Thanks to Dan Allen, I’ve attached a Maven project that includes an Arquillian-based test suite that you can study to get a greater handle on exactly what occurs when using a persistence context, both one that is transaction-scoped and one that is extended. This is exactly where Arquillian fills in nicely as a teaching tool. You can quickly make changes to the code and see how it affects the result…all in-container. You might want to take a look at this before continuing. You can download the lab here, unzip, open a terminal, and type: mvn test.

You can also import the project into your IDE and debug to get a visual sense of what’s going on, otherwise, the tests should be pretty revealing!

What about LazyInitializationException? (Persistence, Transactions, and the Conversation Scope)

The first thing you need to know about LazyInitializationException is that they occur when Hibernate (or another JPA-style ORM) attempts to load a collection or related data from an @Entity object that is no longer “managed.” What is a “managed” object?

To understand this term, we need to look back at how Hibernate and JPA work under the covers. Each time you ask for an object from the database, the system has some form of Session (Hibernate) or PersistenceContext (JPA) that is used to open connections, manage results, and decide whether or not the objects have been modified (which allows for clean/dirty state to determine when or when not to save objects back to the database.)

Introducing a failure situation:

Consider the scenario when an object is loaded from the database. This object has an ID, and holds a list of addresses that are associated with it.

Loading our person
Person person = service.getPerson(1);

Person is loaded from the database using a select statement like this:

The executed SQL
select from persons p where p.id = ?

But as you can see by the SQL query, we have not let loaded the addresses since associations and collections are typically be selected only when something attempts to access them, otherwise known as “Lazy” initialization:

Loading addresses
List<Address> addresses = person.getAddresses();

Here is when you have the chance for a LazyInitializationException, because this method call actually makes a secondary query to the database, requiring an open connection:

The executed SQL
select from addresses a where address.person_id = ?

That sounds fine, but let’s say for instance that a user does something on your website that triggers a Person object to be loaded from the database. Nothing special happens with this object, the application just loads it, reads some fields out of it, and goes on to the next page. When that next page is requested, we grab that same Person object that we loaded on the last page, try to pull more information out of it – for instance, the list of addresses that was not previously loaded, and oops! We got a LazyInitializationException - “Entity is not associated with a known PersistenceContext” What happened?

My object was just loaded, can’t the Session or PersistenceContext object just open a new connection to the database and get the information that I need? – The answer is “yes” it can, but not if that Session or PersistenceContext has already been destroyed, and the object is no longer associated with it! You are probably not using an “extended” persistence context. We need to dig deeper…

Understanding LazyInitializationException and the Extended PersistenceContext

First, we need to know a few things about “extended” Persistence Contexts:

  • They live as long as the bean they are scoped to.
  • Objects with dirty changes queued up in the context until a the transaction with which a persistence context is associated is committed. If a context is destroyed outside of the transaction, the changes are never propagated to the database. It’s the transaction that triggers the session flushing. Flushing can also happen in the middle of a transaction if Hibernate/JPA needs to run a query against the database based on the state of a managed entity (e.g., a where clause)
  • Changes made to objects associated with the context are deferred from flushing if an un-handled exception is encountered. The changes will be flushed the next time a flush is attempted.
  • While the extended PersistenceContext is alive, you will never get a LazyInitializationException from objects associated with that context, ever!
PersistenceContexts can be injected into @Stateless or @Stateful EJBs via the following annotation:
A stateful EJB with normal PersistenceContext
public class Service
    private EntityManager em;

By default, this EntityManager (persistence context) will be scoped to the length of the transaction (which can be controlled by getting a handle to the user transaction and manually calling tx.begin() and tx.end(); however, if we add (type = PersistenceContextType.EXTENDED) to our injection point, we are now using extended persistence contexts, and that is what we probably wanted all along.

A stateful EJB with extended PersistenceContext
public class Service
    @PersistenceContext(type = PersistenceContextType.EXTENDED)
    private EntityManager em;

Use case: the @ApplicationScoped PersistenceContext (Bad practice)

Lets imagine for a moment that one single PersistenceContext is created for our entire application; the context is started when the server starts up, the context is never destroyed until the server shuts down, and all objects are held within that context. In other words, you’ll never get a LazyInitializationException, ever, because the context will always survive, and @Entity objects never lose their reference to it.

But also consider that you are running this as a web-application, multi-threaded, that services multiple users at the same time. Changes made by each user are queued in our extended context until the next transaction boundary, which might be as long as until the application shuts down (destroying the extended context,) at which point all changes made by all users are saved to the database and the transaction is committed.

That sounds pretty dangerous… and that’s what happens if you use an Extended PersitenceContext in an @ApplicationScoped bean. Objects associated with that PersistenceContext will stay around for the life the context itself, so obviously we must (sarcasm) need a PersistenceContext for each user, since we don’t want all changes being queued up and saved when the application shuts down – too many things could go wrong with that scenario.

The @ApplicationScoped Persistence Context will start when the application starts up, and it will be destroyed when the application shuts down. There may be multiple transactions (bound to the EJB business methods) that occur within the lifespan of this context.

Use case: the @SessionScoped PersistenceContext

Let’s now create a PersistenceContext for each user session. Not a horrible concept, and does actually have applicable uses! Each user gets their own PersistenceContext that holds @Entity references to objects from the moment the session is created until the moment the session is destroyed. They can interact with these objects, save, update change and delete objects without fear of stomping on anyone else’s changes, and their queued changes are saved when the transaction is committed at the end of the session (or any other time a transaction is committed).

The @SessionScoped persistence context will be created when the user’s session begins, and it will be destroyed when the user’s session is destroyed. There may be multiple transactions (bound to the EJB business methods) that occur within the lifespan of this context.

But what if you want more fine-grained control over transactions? What if session scope is too long? We don’t want our users making changes on the site that won’t be saved until they log out or their session expires! Can’t we control transaction boundaries ourselves? I want a the context be created when they click “Add to Cart,” continue queuing up more changes, and finally I want a transaction to be committed when they click “Confirm.” We need to look at @ConversationScoped persistence contexts.

But first, in your head, separate the idea of a persistence context and a transaction, since they are orthogonal. They work together, but the transaction is when the persistence context performs operations (sometimes automatically, like flushing); the persistence context is just a monitor and cache.

Also, think of an extended persistence context like a @Dependent object (except it is uses a proxy). It is bound to the lifetime of the EJB into which it is injected. A transaction-scoped (default) persistence context, in contrast, lives and dies by the transaction. So you get a new one each time a business method is invoked (basically, every time you use the EJB – stateless in a sense).

Use case: the @ConversationScoped PersistenceContext

Conversation scope provides exactly what we’re looking for, and the way this works might be bit scary at first, “you’ll think, how can the system possibly do all of this for me?” To which I’ll answer, the magic of using a @ConversationScoped extended PersistenceContext, is that your users’ data, and your users’ saved state as they navigate between pages are living in the same place, and for the same length of time. A match made in heaven!

Using the conversation scoped PersistenceContext
public class Service
    @PersistenceContext(type = PersistenceContextType.EXTENDED)
    private EntityManager em;

The first thing to know about @ConversationScoped beans is that by default, conversation scope beings when the request begins, and ends when the request ends and the conversation is not in a long-running state. The call to converstation.begin() only states intent for the scope to perpetuate. This means that a PersistenceContext injected into a conversation scoped bean will live by default for one request, but of the conversation is started, it will live until the end of the request when the conversation ends. (The reason it is kept alive until the end of the request is because usually the end of the request is when rendering is completed, and destroying information prematurely could result in errors during that render.)

The @ConversationScoped persistence context will be created with conversation.begin(), and will be destroyed at the end of the request on which conversation.end() is called. There may be multiple transactions (bound to the EJB business methods) that occur within the lifespan of this context.

Use case: the @RequestScoped and custom scoped PersistenceContext

It stands to be mentioned that an extended persistence context can be injected into a bean of any scope, and the same rules will apply. If @RequestScoped, for example, the context is created when the request begins, and is destroyed when the request ends; if custom scoped, the same is true: There may be multiple transactions (bound to the EJB business methods) that occur within the lifespan of any context, and when using an extended persistence context.

Going beyond EJB/JTA with Seam Persistence Module:

Seam 3 provides a Persistence module which provides a programming API for short-lived persistence contexts (not extended contexts,) much like what you would find in Spring. You can use declarative @Transactional(BEGIN) and @Transactional(END) methods, and the like, in addition to tying in extra security features, and the power of CDI extensions, interceptors and more. Check back on this blog or on Seam Framework.ORG for more updates on this module.

EJB – Why are my thrown Exceptions wrapped in an EJBException?

Systems using an ORM like hibernate will frequently utilize a Data Access Object (DAO) layer in which standard exceptions are used to reflect the outcome of common operations. Exceptions such as, NoSuchObjectException, or DuplicateObjectException, are common place. If the system relies on catching these exceptions to recover appropriately and continue functioning, developers switching to EJB may be surprised when it comes time to run their application; it quickly becomes apparent that the exceptions being thrown are not the exceptions that are expected – everything is wrapped in EJBException.

At first, you might think, “This is invasive, and tight coupling!” but you have to think about this from the perspective of a transaction-aware system. EJB handles JTA for you, meaning that if you get an exception, EJB needs to know when to roll back the transaction, and when not to; in order to facilitate this decision, EJB has the concept of an @ApplicationException.

“Application” exceptions versus “System” exceptions:

  • An application exception is one that has meaning to the client/consumer of the services, and may affect error recovery, flow of logic, navigation, or any other use within the app.
  • A system exception is one that represents a failure in the underlying services that cannot be recovered from, and should never be handled by the client/consumer (aside from very basic error handling like printing “500 – Something horrible just happened.”)

By default, every unchecked/RuntimeException thrown from an EJB service will be treated as a “System” exception, meaning that the transaction should be rolled back, and a complete failure has occurred; you cannot recover, and you should never catch an EJBException in order to make a decision, other than very basic error recovery – sending a user to a generic error page, for example, or restarting a web-flow / wizard.

So what about the exceptions that we do want to recover from, exceptions that we know should not affect the state of the current transaction? Well, in order for EJB to respect your wishes, you must tell it which exceptions have meaning in your application; therefore, the exception classes must either be annotated with @ApplicationException, or if you cannot chance the Exception source itself, you must list your exceptions in /WEB-INF/ejb-jar.xml (example below.)

Don’t worry, this doesn’t take too long if you have a good exception hierarchy; only the top-level exception must be configured because exception subclasses automatically inherit the configuration from their parent exception types.

<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar xmlns="http://java.sun.com/xml/ns/javaee" version="3.1"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd">

Now your exceptions will be treated as transaction boundaries, or ignored depending on how you need your system configured. This prevents things like partial-commits, and combined with the conversation-scope (next section,) also prevents things like partial-commits from wizard interfaces.


Does it all make sense now? Do you know how to solve every problem? Probably not, but when it comes right down to it, using Java EE can be even simpler than using Spring, and take much less time. You just have to find the right guides and the right documentation (which is admittedly a severe sore-spot of Java EE; the documentation is still a work in progress, but is getting much better, save blogs like this one.) You have to turn to a vendor like JBoss, or IBM in order to get the use-case driven documentation you need, and they do have documentation, it’s just a matter of finding it.

Seam 3 in particular strives to give extensive user-documentation, hopefully making things much simpler to adopt, and easier to extend.

The main purpose of this article was not to bash Spring, although I may have taken that tone on occasion just for contrast and a little bit of fun. Both Spring and Java EE are strongly engineered and have strong foundations in practical use, but if you want a clean programming experience right out of the box – use Java EE 6 on JBoss Application Server 6 – JBoss Tools – and Eclipse. I will say, though, that the feeling I’ve gotten from the Spring forums vs the Java EE forums, is that there are far many more people willing to help you work through Java EE issues, and more available developers of the frameworks themselves to actually help you than there are on the Spring side. The community for Java EE is much larger, and much more supportive (from my personal experience.)

In the end, I did get my application migrated successfully, and despite these issues (from which I learned a great deal,) I am still happy with Java EE, and would not go back to Spring! But I do look forward to further enhancements from the JBoss Seam project, which continue to make developing for Java EE simpler and more fun.

Don’t believe me? Try it out. Find something wrong? Tell me. Want more? Let me know what you want to hear.

Shameless plugs for some other projects that I think you’ll find useful:

OCPsoft PrettyFaces and Rewrite – our own open-source tools for controlling the URL of your application, making pretty, bookmarkable URLs. The easiest (if I don’t mind saying, and I don’t) way of controlling URL parameters, query-parameters, and validating input that comes into your application through the URL. JBoss Arquillian – the single most inclusive and best Unit/Integration testing experience you will find in any application framework. Not only that, but it actually runs your code IN the container, so it’s being tested like it’ll actually be run in production.

Posted in Hibernate, Java, JSF2, OpenSource, Seam, Spring, Technology


  1. Alexis MP says:

    The line between Java EE 6 and extensions like Seam 3 is a bit blurry but that’s a nice article. Thanks for taking the time to write this.

    Also, web.xml and faces-config.xml are optional in Java EE 6. persistence.xml and beans.xml are the only required descriptors.

    1. Lincoln says:

      Thanks for reading 🙂 I corrected the descriptors.

  2. Roberto says:

    Nice article! A small correction: the table listing all the built-in scopes talks about @DependentScoped, but the correct annotation name is @Dependent, as used later in the article.

    1. Lincoln says:

      Fixed, thank you 🙂

  3. Great post. I think EJB, finally, have done things right.

  4. Narsi says:

    Great post

  5. Donatas Čiukšys says:

    Correction: JTA transactions are not bound by any Scoped anotations. A JTA transaction begins with the first EJB method annotated with Required attribute (default) or with RequiresNew. The transaction is commited automatically when returning from this method.
    So no matter the scope of the bean (@RequestScoped or @SessionScoped) transactions will always be commited (and persistent context flushed) at the end of request. This is as it was in EJB 2.0, and stays the same in EJB 3.1. CDI does not change JTA semantics. Otherwise please include some references to pages in specifications.

    1. Lincoln says:

      Thanks for the clarification! I was in the process of correcting myself as you posted this 🙂

      1. Donatas Čiukšys says:

        What concerns PersistenceContext’s (extended) scope, you are absolutely correct. And @ConversationScoped extended PersistenceContexts are very handy in applications – you get JPA entity cache designated for a single conversation. No LazyInitializationException’s, yet memory consumption on the server (for JPA entity cache) is small – at the end of conversation entity cache is deleted.

        The problem (or maybe “thanks god” 🙂 ) is that JTA container managed transactions are always request scoped. Actually you got me thinking whether I would like to have 30 minutes (session timeout) long transaction… Probably not 🙂 Not even conversation long transaction. Transactions should be as short as possible to consume as little DBMS resources as possible.

        Good luck!

      2. Lincoln says:

        Hmm… well actually the transactions only last for the duration of the @Stateful/@Stateless EJB business method, so unless you are controlling transactions manually, they shouldn’t be around that long 🙂

      3. Alberto Gori says:

        Transactions normally start and end during the same request.

        For an extended persistence context there is a nice trick, well known by Seam developers: you change the flush mode of the Hibernate session, disabling the auto-flushing feature at the beginning of the conversation, and manually forcing the flash at the end of the conversation.

        So, transactions don’t waste DBMS resources and the user-operations are still atomic with nice isolation properties, like they were in a long transaction.

  6. Doug says:

    Are you in trouble if you suggest using Java EE out of the box instead of Hibernate? You’re working for RedHat you know 😉

    Good article I already forward this as today’s mandatory reading for my team!

  7. Pooria says:

    Instead of using a conversation scoped persistence context to hold our conversation data (which seems hackish), I’m guessing it’s more natural to just use a conversation scoped object (without a persistence context) to keep our conversation data (e.g. a shopping cart class), and only in the end, when the conversation data needs to be persisted (e.g. user tries to buy the items in the shopping cart), we can use a the default and simple RequestScoped persistence context to take the required data (e.g. list of items in the cart) from the conversation scoped object (e.g. the shoppingCart) and try to validate/persist it.

    What do you think bout this approach? Do you see any disadvantages?

    And thanks for the great article.

    1. Alberto Gori says:

      @Pooria: your approach is likely to face the well known LazyInitializationException, and King Gavin (Hibernate and Seam creator) thought up to the conversation scope to avoid this exception.

      Think to your flow: conversation begin and you load the user object from database. In the next page you access the user address list…and BANG! LazyInitializationException.

      1. LaloZeke says:

        select a EntityA a join FETCH a.bList b

        another LazyException solution 😉

  8. Daniel Cullender says:

    Thanks for an interesting article!

    We are currently running ejb 3.0 and spring side by side via the jboss-spring deployer.

    One nice feature about spring is the @configurable annotation which basically spring configures any pojo without having to worry about configuring it inside the spring container (using aspects)

    Does ejb 3.1 offer anything similar? (I see the BeanManager exists, but this does provide a good substitution). Furthermore, can @Asynchronous be used with any old pojo (like spring’s @async method) or does it only work for EJB components?


    1. Daniel Cullender says:

      correction : Does ejb 3.1 offer anything similar? (I see the BeanManager exists, but this does NOT provide a good substitution). Furthermore, can @Asynchronous be used with any old pojo (like spring’s @async method) or does it only work for EJB components?

      1. henk says:

        @Asynchronous is specifically for EJBs, but don’t forget that every simple POJO can be made into an EJB by just adding the @Stateless annotation to it.

        So in a way, yes, in some way POJOs can use @Asynchronous 😉

  9. dont get it says:

    So what jars do i need to include in my Maven POM so i can deploy the JEE 6 persistence on Tomcat or some other non JEE 6 container? Or do i need to constantly upgrade my entire server farm to the latest greatest application server software (most likely for a massive fee) just for the pleasure of doing what i can do with a few simple jars with Spring?

    1. Lincoln says:

      Since when does open-source cost a massive fee? You’re going to pay the same price if you pay VMWare for support on the Spring stack, as if you pay a company for support on Java EE. No difference there, sorry 😉

      1. henk says:

        Indeed, a still don’t get why Spring fans keep using this argument of Java EE supposedly being so massively expensive.

        Last time I looked Glassfish, Geronimo, JBoss AS etc could all be downloaded without paying anyone a penny. In case of Glassfish the download size is even smaller than if you downloaded everything you needed to build a complete application server with Spring.

        Java EE has many totally free (gratis) and fully open source implementations, which are also used a lot.

      2. Lincoln says:

        And it’s worth mentioning that Spring actually takes individual pieces of Java EE and re-assembles them, so you’re still using Java EE. Java EE is still the core, and Spring is still the extension, it’s important not to forget that.

    2. Lincoln says:

      I quote from a friend who sent me an email in response instead of commenting:

      “One phrase: web profile (or JBoss’s slightly perfected web profile)

      I would simply point over to (or quote) Adam Bien. He’s whole “what does lightweight really mean” entries are great.


      Also Gavin’s “You should update to Java EE 6”


      And Cay


      I absolutely agree that bloated runtimes and runtimes which are slow to load suck. But I don’t want to have to bring the whole internet with me just to deploy (because that slows down the deployment process). It’s about striking a happy balance, and that’s the web profile :)”

  10. Jacek says:

    Well, here’s the problem…I still fail to see a single advantage EE6 has over Spring. It’s just different annotations/config files that look very similar to the Spring ones, so what’s the benefit for an existing app? None.

    And here is the big one: with Spring we run our app in Jetty and can use the excellent Maven/Jetty integration for unit testing.

    With EE6 I need one of those big, clumsy app containers like Glassfish, JBoss or Weblogic.

    No thanks: I’d rather stay agile and lightweight with Jetty. Only Spring allows us that.

    1. Lincoln says:

      Big, clumbsy… embedded? I never said Java EE had advantages over Spring; I simply said it did things differently, and did some things for you 🙂 When you get right down to it, the level of work is just about the same.

      With regards to easy testing:

      Heh, times are changing. Yeah it’s a little bit of up-front work, but as it says in the article, “the benefits are clear.”

    2. henk says:

      >I still fail to see a single advantage EE6 has over Spring. It’s just different annotations/config files that look very similar to the Spring ones, so what’s the benefit for an existing app?

      Well for me this is the other way around. I fail to see a single advantage Spring has over Java EE 6. The other way around the same thing really holds; Spring is very similar to Java EE, just with a different API. All our existing apps are Java EE based (5 and now 6) and we’re very happy with it.

      Why should I migrate those to Spring?

  11. henk says:

    Very nice and very useful article! I’ll bookmark this for sure for later reference.

    One small addition about the data source config. You say the following about this:

    >must be placed in the actual JBoss server deploy directory

    But this is not completely true. You can also include the config file in your application code by creating a jboss-app.xml in META-INF and referencing the file there. This is handy for people who like their application archives to be as self-contained as possible.

    Of course, for some organizations or team structures it’s better to have the data sources (and actually other config files like JMS queues) defined in the JBoss AS installation itself on each server where the app is deployed to, but just wanted to mention that there is a choice 😉

    1. Lincoln says:

      Thank you! That’s very good to know! I’ll update the article when I get a chance 🙂

  12. Vbv says:

    This article is pure yet subtle propaganda. You do not state it clearly but with all that ‘ee6 does it for you’ things the message is that spring is complicate and ee6 is better. You work for rh yet still act ad a spring dev lookin’ for the first time at ee6! come on be more honest! and please : cut that part about getting beans programmatically, it’s better to say that ee6 doesn’t like it without scaring people that much on such basic tasks.
    Didn’t like your way of propaganding ee6 but I like ee6 and appreciated some of your thoughts.

    1. Lincoln says:

      You’re right. I’m out to secretly undermine Spring by sharing my own personal experiences and lessons learned from doing a migration to Java EE 6 🙂 Just kidding. Also, I’m confused: wasn’t the part about getting beans programmatically admitting that Spring did something better? Why do you want me to change that? I updated the post to be more clear that I do in fact work for JBoss.

    2. Lincoln says:

      PS. Sorry for coming across sarcastically. I’m hungry, and you are right. I’ll try to do better in the future.

      1. Vb says:

        Hey! No problem at all. I was a little aggressive too. Didn’t meant to, but I was.
        Don’t want to start a flame at all. So sorry for me beeing too severe.

        In the end EE6 and Spring are two different approaches. Sometimes I like the magics of EE6. Everything works right out of the box. No need to write the same things all over again.

        Sometimes there’s too much magic and I want a lighter system.

        But EE6 is really good and your article definitively worth reading (and posting …).

  13. dont get it says:

    three links that do not really say anything about the real issue. I can simply build a full enterprise application using Spring and deploy to any container, whether that is Weblogic 8, 9, 10, 11, Tomcat 5, 6, etc… I don’t even have to think about some vendor driven spec to know my application will work. JEE would be great if it followed the Spring model and was simple a series of jars to include in your war. Simply include the jar via Maven and done. The xml config points are interesting considering all the xml configuration you highlight in your article. Until you can simply include a couple of jars in a war file to do what 80% of java developers need like Spring can, you all will be begging for people to switch to the bloated jee platform.

    1. Lincoln says:

      If you like the Spring stack better than the Java EE stack, that’s awesome. Not gonna try to stop you 🙂 Use what works for your business, that’s always the bottom line.

    2. henk says:

      Spring just has a different default model: include everything in the war and end up with fat jars vs deploying very slim wars and assuming your deployment platform already has the required functionality.

      It’s just a different thing. Hard to say which is really better.

      In desktop applications, do you statically link in all libraries and whatever, or do you assume the OS has some base level of functionality? In practice, both happens really.

      Also, including everything in the .war is arbitrary too. Since you still have to rely on a base level of Servlet and JSP that is already installed. If you want to include JPA, JTA, EJB, JSF, JMS, etc in your .war, why not include Servlet and JSP in it too?

      In that way, the only thing you assume to be installed on the server is a JVM. You don’t deploy a .war, you deploy e.g. Tomcat with your application already in the webapps directory. Technically there is very little difference as Tomcat itself is a Java application too.

      The same can be done with JBoss AS. I can assume a certain version of JBoss AS is already installed on the server and thus deploy very rich EAR apps that are extremely small (couple of 100k max), OR I can assume only a JVM is installed and deploy JBoss AS together with my app.

      Luckily we all have a choice as Lincoln says. If Spring works for you, by all means keep using it 😉

      (although don’t forget that there are Spring Application Servers too, where basically an AS is build on top of Spring and all required libs are added to the Tomcat common libs dirs, so the picture is not that black/white)

  14. Satish says:

    Great article, First article that I have seen that actually brings CDI and EJB3 together and in a coherent fashion.

    But I dont think I am going to migrate anything to JEE6 in a hurry. All the JEE has done so far is to catch up with Spring and not do anything better than them. Ok, you solved the lazy init exception, so what. EJB3’s Interceptors are still way behind what I can do with first class AOP support that I get with Spring. All JEE seems to be aiming for is simple web/EJB projects, but almost all enterprise work that I do need additional features that frameworks like Spring Integration, Spring -Batch provide out of the box.Sure, there are other open source projects out there, but Spring does all these seamlessly and adding them is very little add on work unlike EJB3 where everything is PIA.

    I would have really jumped on the EJB3 bandwagon if only there were things that were compelling enough, but if all the work has been done so far is to catch up with Spring, I’d rather use Spring which atleast has had the time to mature.

    1. Lincoln says:

      This article wasn’t meant to be an attempt to convince anyone to switch, just an explanation of what’s going to happen if you do.

  15. @Lincoln,

    I really like how detailed you article is: that’s awesome! Thank you!

    Thing that appeared to me rather unnecessary negative are:

    “seemingly unresponsive Spring forums”

    We both know this is not true, or if it is, can you back it up by showing me at least 5 questions that you asked on Spring forum that were not answered?

    “download your application server of choice, which at this point will probably be one of either: JBoss AS 6, or GlassFish v3”

    why would I need these guys if I have plain Tomcat ( and yes, I know how to use it )?

    I think the overall direction is to hide the complexity and focus on the real task ( some people call it “business”, I call it a “task” ). Having that in mind, if I would really switch from vanilla Spring / Hibernate stack today, that would definitely be Grails: can’t go simpler than that.

    I am sure you know that Spring also has a complete annotation driven configuration, I personally _like_ my XML, but it is there. Plus if I need flexibility I would go with Grails bean builder.

    Finally, I know that you are a big JSF supporter, we actually met at Philly ETE conference, and I attended all your and Dan Allen’s talks, just to make sure I “get” the message. And even thought Spring Webflow is practically sits on top of JSF, I really think they could have done better 🙂

    Again, thank you for a detailed article, I love those, and even though I belong to “The World” good luck in “Pure JEE vs. The World” mission.


    1. Lincoln says:


      Actually, you’re right. I went back and double checked my posts on Spring’s forums and I saw that I participated and was answered serveral times. I was distinctly thinking of a real experience I had on some forums though, and I’m embarrassed to say that it was probably the Hibernate forums before they moved to JBoss.org… All I remember is asking questions about Spring open-session-in-view filters, and getting crickets. I was asking in the wrong place 🙂

      You’re also right. The article did not need any inflammatory statements in the first place, and I’ve removed it.


      1. henk says:

        If there is any unresponsive forum in the world it’s indeed the Hibernate forum. Getting any question answered by anyone knowledgeable, let alone the actual developers, is near to impossible.

    2. henk says:

      >why would I need these guys if I have plain Tomcat ( and yes, I know how to use it )?

      Well, because the article is about Java EE and those are examples of popular Java EE implementations?

      Your reply is like replying to an article about iOS where the author mentions you probably would get either an iPhone or iPod in order to use iOS, that you already have a Nokia and yes, you know how to use it.

      Doesn’t make a lot of sense, does it mate? 😛

      1. But I have not edited this article, I added a comment.

        I will let you think about my comment as “Tomcat”, and this article as “JEE”. [ it’ll “click” after you read it over a couple of times ]

        Going back to “Nokia” point: “why do I need iPhone, if my Android already does it, and does it better” 🙂


    3. Cash says:

      A few years ago I’d have to pay someone for this ionfrmiaton.

  16. GT says:

    Thanks Lincoln … for a detailed and well written blog. A lot of things about JEE6 were answered by this post.

  17. I liked your article, thanks! Two questions:
    (1) Does Java 6EE CDI also support annotated components like in Spring through @Component, @Service, @Repository and @Controller?
    (2) How would you compare Java 6EE CDI and Guice?

    1. Lincoln says:


      1. I’m not sure what you’re asking here. CDI has tons of annotations (Including @Model, @Service, and I believe @Repository), CDI also lets you create your own Stereotype annotations to extend functionality, and has *tons* of extension points.

      2. CDI is a much richer (but also more heavyweight) DI container. It features the same type-safe approach, but has an extreme level of extendability. If you don’t need that, Guice is still a good option, but CDI is gaining major ground already, so it really depends on what you want to be using in 5 or 10 years, and what extensions you want to use with it.

  18. vinay says:

    Let me run annotated transaction in tomcat and then i will make a switch from Spring to EJB.

    1. Paul youngh says:

      vinay, that’s a bit like saying you switch to apple mail as soon as you can run iOS on Android.

      It doesn’t really work like that. Java EE is a full platform, you don’t run Java EE on Tomcat. (although many Java EE implementations use Tomcat for the Servlet part).

      You can run bits and pieces of Java EE on top of Tomcat, but you don’t get the full conveniance then and you are basically repeating the work that eg Apache Geronimo has already done for you.

      1. vinay says:

        I remember seeing in one of articles that you could run lightweight EJB’s on tomcat. They would not be fully functional. Do not remember much but will post a link as soon as I find one.

        But my point is that for a lightweight application, Spring + hiberante is providing with all the feature sets which EJB + JPA is providing
        JPA has been derived from Hiberante so basically you are only getting EJB’s and that you are using Stateless Session bean most of time. I had worked with EJB for a long time but now with Spring , I do not find enough motivation.
        In most of cases, Spring’s transaction capabilities are better than EJB’s. Here is a comparison of both

      2. henk says:

        I think the point is that you don’t HAVE to assemble your own stack. JBoss AS basically already is Tomcat + Hibernate + EJB + JTA.

        Why painfully build your own stack with possible incompatibilities?

        Hopefully JBoss AS will also specifically add a “web profile” configuration (they have “all”, “default”, “standard”, “minimal”, “osgi” and “jboss web standalone” now. Those are just pre-assembled configurations. You can delete the other ones or make your own.)

  19. jacques says:

    Thanks for the article. It made me want to investigate EE6 a little bit more.

    However I am still turned off by some of the decision that seemed to linger from the old EJB days: checked exception for example…

    Lastly I believe you made a mistake writing that in spring you will get an exception if you inject a session scoped bean in an application scoped bean. Spring wraps its scoped objects with proxies that are injected immediately. So on creation the application scoped bean will only get injected with its own proxy that points to the session bean. However if you try to access that session scoped bean outside of a session context you will get the exception you are talking about. From what you described this is exactly the same behavior as EE6.

  20. […] Spring to Java EE – A Migration Experience is very interesting article. I haven’t looked into EE recently but from what I read coding EJBs is very simple compared old days. Categories: Java Extreme MakeOver 6 October 2010 at 14:20 – Comments […]

  21. yh says:

    i believe that JEE 6 has caught up to Spring. it is light, fast, easy and standardized. but Spring ppl are very smart and are business oriented. while most ppl are debating Spring vs JEE (don’t forget python, php5, ruby on rails ..etc), Spring is fast moving ahead. Their applications are ready for the Cloud with all the tools u need. They make ideas like SaaS, PaaS accessible to ordinary developers and within their reach. see

    their support services are unmatched and the their sub-projects are stamped ‘Enterprise ready’.

    I use JEE in my applications. but I keep an eye on Springsource. to say the least, they are always one step ahead and their vision into enterprise apps is just impressive.

  22. […] 2) http://ocpsoft.com/java/spring-to-java-ee-a-migration-guide-cdi-jsf-jpa-jta-ejb/ […]

  23. Erik Lund Jensen says:

    Java EE 6 vs Spring boils down to one decision:
    Do you want to be dependent upon the application server version again? Using Java EE you will be bound to the versions bundled with that application server. How many of you havn’t struggled with WebLogic shipping/supporting e.g. old WS-* versions?! With Spring you may use all the new features without upgrading your application server, and thereby each project may upgrade at it’s own pace. When depending upon Java EE you are forced to upgrade the application server and thereby coordinate the change with all other applications/projects running on the same application server instance/cluster.
    With Java EE you are send back to the days where you had to wait for all the applications to be ready (and wait for new test and production environments).
    With Spring you may upgrade your project as you need new features provided by Spring/Hibernate without being dependent upon others.

    1. Paul youngh says:

      I don’t buy into your argument that upgrading Java EE is somehow more difficult.

      From an application architecture point of view, migrating your application code to a major new version of Spring is just as risky as migrating to a major new version of Java EE. There is no difference here.

      If you’re using the Spring deployment model of more or less completely shipping an AS in your .war to blindside operations (“no, i’m not upgrading any libs, I really wrote that 100mb of code myself”) than that’s a very debatable practice.

      Most importantly, the argument of upgrading individual apps at their own pace because they all run on the same AS is silly. In practice you don’t do that! Every app runs on it’s own AS and that one typically runs on it’s own virtual server.

      Spring fans of all people should know this is the preferred deployment strategy now that VMWare own SpringSource.

  24. andrewly says:

    Totally Seam and JBoss biassed, totally antispring oriented.

    Spring was the revolution, it will be, just Guize compares to it’s simplicity and intelligence.

    Period !

    1. Lincoln says:

      The purpose of this article was not to be balanced and fair. This was a discussion about the issues encountered when moving *away* from Spring, and moving *to* Java EE / CDI.

      Thank you for reading.

  25. Brian says:

    I’m curious about injecting a @SessionScoped bean into an @ApplicationScoped bean. I couldn’t quickly find where this is addressed in the JSR-299 spec.

    The only ways I could see this working are synchronizing access to the @ApplicationScoped bean, using ThreadLocal storage for the @SessionScoped bean, or having multiple instances of the @ApplicationScoped bean (which you wouldn’t expect if there weren’t any injected @SessionScoped beans). Is there another option that I’m missing?

    I’d be more comfortable understanding what the consequences are (in terms of performance, memory use, etc.) of having such a straightforward way of representing something that seems like it could have a lot of complexity (as evidenced by how you describe Spring’s handling of it).

    1. Lincoln says:

      Well that’s the clever thing, and like I said this is the same in Spring if you use , but Weld/CDI use a Java Proxy to wrap the @SessionScoped bean reference that is @Injected into the @ApplicationScoped bean. This means that whenever the @ApplicationScoped bean attempts to access the @SessionScoped bean, it actually accesses the proxy, which accesses the current user’s Session (the BeanManager takes care of all of this,) and gets a reference to that current user’s @SessionScoped bean.

      The @ApplicationScoped bean is not inherently threadsafe since there is only one instance of it in the entire app, but its accesses to the session scoped bean *are* local to each individual user. Unless you do bad things, you won’t have bleed-over. Obviously @SessionScoped beans are not inherently threadsafe either, but @RequestScoped beans are, because they only live within the scope of a single request, or one single thread.

      1. Brian says:

        Ahh, of course. I had thought of maybe putting a proxy around the @ApplicationScoped bean, but that wouldn’t work for direct field access to the @SessionScoped bean. I didn’t think of putting the proxy around the @SessionScoped bean. Thanks!

      2. henk says:

        Delegating via the proxy to the current user’s session is a very clever trick.

        It’s a little like what TLS does in the standard JDK. You seem to be accessing a static variable, but under the hood it delegates to an instance in the current executing thread.

      3. Zak says:

        Wouldn’t it make more sense that the injection point for the @SessionScoped bean be “@Inject private Instance credentials” instead? That way you can obtain the correct instance of credentials whenever you need to do something with the object and not have to worry about the session.

      4. Zak says:

        Oops. That should be:

         @Inject private Instance credentials
  26. Jorge Soria says:

    If it ain’t broken, don’t fix it.
    Spring works. Maybe JEE does too. Who cares?
    Do what you feel is good.

    Deploying a light war with a heavy server or a fat war with a light server is a matter of necessity for each situation. It depends.

    I concur with some earlier opinions: All JEE has done is catching up. It’s like Spring is the standard and JEE is the extension. It certainly feels that way.

    The only thing truly compelling I have heard (although I haven’t heard that much) is the Conversation scope. We implemented a custom conversation scope for our Spring, JSF, Hibernate application, and it wasn’t that hard (merely 4 classes with some handling of the Hibernate Session and Spring Transaction) but I would like to have that done for me.

    But Tomcat is easy, light, fast, and very well supported. Spring was a huge change back in the day. They are beautifully documented and developed. Transactions are good, AOP is good, and specially, their attitude is AWESOME.
    Spring doesn’t tie you to anything. You can integrate with what you need, run as complex or simple applications as you wish, use the server you see fit. And they do that with a smile… so much different that Gavin “I’m so much more smarter than you so don’t bother me” King attitude.

    In the end, and with two close specs, it’s that what keeps me in the Spring side. That, and more than 6 years doing what JEE is now coming to do: Keeping Java as an enterprise option.

    1. henk says:

      > If it ain’t broken, don’t fix it.
      Spring works. Maybe JEE does too.

      Java EE does. Believe me 😉

      >Who cares? Do what you feel is good.

      I think that’s the entire idea. If Spring works for you, by all means keep using it. And of course nobody is forcing anyone to migrate existing apps from Spring to Java EE, that would be really silly.

      For new projects and new teams however I think Java EE is a very compelling choice. People already familiar with Spring and starting with a complete new project should really consider Java EE. I think this article will be very helpful for those people.

      >And they do that with a smile… so much different that Gavin “I’m so much more smarter than you so don’t bother me” King attitude.

      I hear you, and maybe Gavin is a little like that, but he does know his stuff. There’s a difference with thinking you know better while in reality you do not really (an all too common phenomenon under developers).

      Personally what drove me away from Spring is Rod’s attitude of “EJB is evil! Containers are bad! J2EE is heavyweight”, long after Java EE 5/EJB3 was released. Your experience may differ, but in my opinion if you wanted to be part of the Spring culture, then having to hate EJB and J2EE was just part of it.

      There are two things very wrong with that. First of all, it’s a little strange that in order to use technology A you actually have to be indoctrinated to hate technology B, and secondly, most of the things said by Rod actually applied to EJB2 and J2EE 1.4. I’m not sure why rants against EJB2 are still relevant in 2010.

    2. Yannick Majoros says:

      >It’s like Spring is the standard and JEE is the extension.
      >In the end, and with two close specs, it’s that what keeps me in the Spring side.

      That’s just the point: Spring is not a standard, and there is only one implementation. It’s sometimes easier (but not necessarily better) to work alone than to have to decide with other people.

      Spring had once more features than Java EE. That’s gone.

  27. Nikola says:

    Great article. The only thing I’m worried about is developing application on java application server like Jboss AS that is painfully slow. When project is large you have to wait up to 3 min for Jboss AS to start (or publish application). Tomcat rules!

  28. myuan says:

    Nice article. I think both JEE 6 and Spring has their strength at different areas. I just don’t see Spring is over.
    JEE is getting stronger at the business-logic tier and the persistency tier, however, it still doesn’t have a real competitor to Spring at the presentation tier. The “page controller” pattern behind JSF still prevents any implementation of the specification from significantly reducing memory consumption and improving performance. Another great feature in Spring is its openness. The framework can be (in fact have been) integrated with other popular frameworks without huge efforts.
    JEE’s biggest advantage is its vendor support. In addition to JEE server licenses, no one would want to pay extra to support a framework running on the server.
    In my opinions, JEE or Spring? It depends…

    1. Lincoln says:

      For addressing the page-controller JSF issue, you can use my own tool/well-adopted open-source project: [[PrettyFaces]] – http://ocpsoft.com/prettyfaces/

      You set up URL-mappings that point to one or more pages; actions can be invoked when those pages are requested, thus effectively creating a front-controller instead of a page-controller pattern.

  29. Yannick Majoros says:

    > installed Hibernate on GlassFish (which is very easy to do, and I recommend since TopLink has given me a lot of problems;

    Nice article, but why recommanding an implementation over another one because you had problem using it? I don’t think it’s fair.

    What do you mean by Toplink? If you mean Toplink Essentials, this one has been obsoleted by Eclipselink. If you mean Toplink JPA, this is a commercial product based on Eclipselink. Eclipselink is an implementation of JPA 1 and JPA 2 (RI).

    If you have a jpa compliant application, Eclipselink just works. Please be precise if you think it doesn’t: it’s the RI for JPA 2, so I’d really doubt it and it’s really worth filing a bug.

    I’ve got a lot of production apps using Eclipselink.

    One more detail: you don’t have to install Eclipselink in Glassfish, you can bundle it in your application if you want. That means you can have different versions for different projects, and you don’t have to install anything on glassfish to deploy your application.

    1. Lincoln says:

      That’s a fair enough point. I suppose I should have said, “Coming from Hibernate, there are enough differences between it and EclipseLink that I had a lot of trouble getting my existing app to run on it.”

      1. Yannick Majoros says:

        Why? JPA is a standard and switching should be easy. If you say it’s not, it would be interesting to know why.

        Eclipselink is stable and has been there longer than Hibernate. In your article, it sounds as if Hibernate is better, more stable and Eclipselink is problematic. This simply isn’t the case, and I bet you can change your JPA provider easily.

      2. Like I said, I personally had problems using Eclipselink instead of Hibernate 🙂 It’s been a while since I went through it, so I can’t pinpoint them specifically right now 🙁

  30. […] week a JBoss core developer, Lincoln Baxter, published a detailed and insightful report on his migration experience from the Spring Framework to the new Java EE 6 platform. In the post […]

  31. […] I still need those proprietary frameworks? Last week a JBoss core developer, Lincoln Baxter, published a detailed and insightful report on his migration experience from the Spring Framework to the new Java EE 6 platform. In the post […]

  32. Gene De Lisa says:

    Nice article.

    Unfortunately we’ve been mandated to use Websphere – which means we’ll get support for this around 2019.

  33. […] boost his argument in his blog post, Badani pointed to a write-up from fellow Red Hat employee, and JBoss core developer, Lincoln Baxter, which discussed the […]

  34. […] [Technik] Spring to Java EE – A Migration Experience […]

  35. Robbert says:

    Regarding your example of a EJB as generic DAO.

        public  T findById(final Class type, final Long id)
            Class clazz = getObjectClass(type);
            return result = (T) em.find(clazz, id);

    has 2 compilation errors.

    Shouldn’t it just be (not tested it myself):

        public  T findById(final Class type, final Long id)
            return (T) em.find(type, id);
  36. […] which, for reasons best explained in a separate article, is not easy unless you use some “Solder.” However, this approach is recommended only […]

  37. K1ng.Solomon says:

    Guys, who designed EE6 should just do the same things that were done in Spring but better. Instead they chose their own way, and this way is seemingly more complicated than Spring way. In turn, benefits are very doubtful.

    The case might be closed here. New EJB technology is not going to fly. It does not worth time to spend. Spring works just great. Why somebody time and money to do the same things that are already done.

    Everybody who remember EJB 1.0-2.1, know how much pain it was to deal with server specific deployment descriptors and other meta data. Why do we need it again ?

  38. […] The days of Spring and popular Web Frameworks are over, is clear from this article on Java EE 6. Migrating from Spring to Java EE 6 is thoroughly described here. […]

  39. Jagadeesh says:

    CDI might replace Spring DI, but the power of Spring lies in the support for Aspect oriented programming (AOP).

    Though we can workaround this in JEE, with EJB interceptors, we are forced to move to EJB and the flexibility of applying aspects on Java bean level is not present.

    Even if projects wants to move from spring to JEE. Non support of AOP is going to be the blocking factor.

    1. That’s an interesting perspective, actually. I think that CDI interceptors provide a great deal of functionality as well, but the idea that you can extend the public interface of a class is something that is yet to come in to EE as a major practice.

      I think we’ll see some serious power with interface-driven implementations, however (where you define an interface that is automatically bound to an implementation to meet your needs.)

      That’s one place where CDI will shine well 🙂

  40. Cristhian says:

    I’m in the way to migrate mi old Spring + Vaadin application to JEE6, right now i’m having an issue with Spring-Security, how can i use Spring-Security with JEE6 ???
    There is no way to @Inject the AuthenticationManager. :S Some help will be appreciated.

    1. I suggest taking a look at Seam Security or PicketLink (unfortunately the documentation link seems to be broken at the moment – trying to get that fixed.)


  41. […] forte, molto forte, ma l’arrivo di Java EE 6 sembra aver incrinato le certezze di più d’uno, ma non di […]

  42. […] be discovered and included in the larger application. (For more details on these descriptors, see this post.)To run your application with the least amount of effort, you should use a full Java EE Application […]

  43. Frank says:

    That is why the Head First book series is so popular and effective. Those books make you think/experience the problem first and then help you finding a solution.

  44. Tiago Augusto says:

    Nice article, very nice indeed. But as you show it is possible to use an EJB as a, let say view component, so tha page can acess it as a Managed Bean. This aproch is not so heavy?

    1. EJB3.1 is pretty lightweight these days 🙂 Just a few annotations.

  45. Java Pins says:

    Spring to Java EE – A Migration Experience | OCPSoft…

    Thank you for submitting this cool story – Trackback from Java Pins…

  46. Tirthal says:

    My experience of several months with Seam 2 is that there are some inherent speed bumps introduced by JSF and bijection. For UI controls with many elements (tables, dropdown boxes), the bottleneck is not at all the database (even without 2nd level caching), but the time spent by Seam during the RenderResponse phase. The heavy use of bijection and events (see, for instance, org.jboss.seam.core.MethodContextInterceptor.aroundInvoke() which sets 5 context variables, each creating 2 events) has a visible impact on the page rendering time and we found it is hard to reduce it. There are only a few tools: bypassing interceptors, use and rethink the UI interaction to have lazy loading of data in UI controls or have autosuggestions instead of populating lists. It is somewhat frustrating to constantly have this conflict between using the framework for its features and avoiding the framework for its slowness. I don’t know if I can ever make the app really snappy (say, have responses back in less than 100ms).

    Any comment on Seam 3 performance (JavaEE 6 CDI + JSF) compare to Spring framework?

  47. Magnus says:

    Great article.
    I’ve been researching how to migrate our apps which are based on spring as jee container.
    We are using OSIV (filter) to avoid the LazyInitializationException.

    The author suggests using ConversationScoped stateful beans/services with extended PersistenceContext.
    (Our services are internally stateless though).
    Which looks promising for use with a servlet framework.

    But what if we want to use the same services in other cases – like EJB timers/schedule. (We use quartz scheduler now)

    How to deal with the (unwanted) extended scope here.
    Should we then programmatically begin and end conversations – or manually flush entitymanager. Could it be done declaratively?

  48. […] are a couple of very useful articles. This one is very detailed and is published by JBoss employee: http://ocpsoft.com/java/spring-to-java-ee-a-migration-guide-cdi-jsf-jpa-jta-ejb and this is the presentation from IBM: http://www.slideshare.net/kelapure/java-e-evsspringshootout. […]

  49. sreenath v says:

    Before commenting, we should try out whats there…rather than basing our opinions on years old…Jboss 7 boots in 45 seconds…

  50. Conversation Scoped Entity Manger disallowed by CDI? says:

    According to comments of http://stackoverflow.com/questions/10056600/weld-on-websphere-8 CDI does not allow a conversation scoped EntityManager because the EntityManager interface is not Serializable. Is Weld more tolerant in this respect?

    1. Actually I think that this does work in Weld. I’ve used ConversationScoped EntityManager instances many times on JBoss AS 7; I’ve never had a problem with this. That’s the whole idea of the Extended PersistenceContext, so if it’s broken on WebSphere, that’s really bad.

  51. Armen says:

    EJB3.1 the best at this time, from 2008 we used only EJB3 on several successfull projects, EJB3.1+JSF2.1 have not alternatives.

  52. Armen says:

    Some people ask me why EJB3.1/JSF2.1 have not alternatives, why? Because XML is not a java, because with EJB3/JSF2.1 you write only java code, only 1-2 simple xml. In Spring still you must use a lot if xml what in the big projects caused failure layer.
    Also structure and logics EJB3.1/JSF defined in the right way. Spring still does not know what is java 6 CDI, POJO and more:(((((((

  53. Paci says:

    I’m a “little bit” late and I’m not a Spring specialist, but I leave a comment anyhow. With Spring your application is bound to certain platform which is not the case with Java EE. For example, with async EJBs you can implement application server neutral threading, but with Spring’s @Async you cannot; you have to change TaskExecutor according to platform. For WebSphere and WLS it must org.springframework.scheduling.commonj.WorkManagerTaskExecutor but cannot be on any other platform. I would also say that WorkManagerTaskExecutor doesn’t work correctly and can make your server to hang, but lets not concentrate on that. So, depending on your platform you have to use some kind of deployment tool to change this or unpack the XML files and change them manually. And which application servers have console support or deployer tool to do it? I think the same still applies to TransactionManager; it must be changed for WebSphere.

    “Declarative transaction demarcation in Spring 2.5 or later are supported in WebSphere Application Server using the following declaration for the WebSphere transaction support:

    <bean id="transactionManager"

    or how about not changing it?

    “Managing transaction demarcation through WebSphere Application Server’s UOWManager class ensures that an appropriate global transaction or LTC context is always available when accessing a resource provider. However, earlier versions of Spring used internal WebSphere interfaces that compromised the ability of the Web and EJB containers to manage resources and are unsupported for application use. This could leave the container in an unknown state, possibly causing data corruption.”

    See for more information: http://www.ibm.com/developerworks/websphere/techjournal/0609_alcott/0609_alcott.html



  54. nojbossplease says:

    Great article! Can’t wait to see Spring disappear from every freaking project I had to put my hands on.

    PS: Recommending JBoss AS 7.x over GF 3.x ? Not sure about this statement… JBoss = Very buggy

    1. What bugs have you found specifically?

    2. Sorry to hear you had trouble. Was this with the final release or one of the earlier betas, or even AS 6? JBoss AS7 is incredibly stable and clean.

  55. Anil Chalil says:

    1 month ago i also migrated one of my applications to JEE and i could say it was easy. But the problem here is not "JEE is also easy" thing . I think what makes spring is a little bit better is its flora like spring-data,spring transactions,spring-security. In my project i did not use ejb for example instead i use seam-persistence and seam-security because i didnt want to use a jee server just because i have to persist some small data but still want to use declarative transactions and i dont want to use web.xml based security or JAAS(i think still hard to understand). Because of all those things i look forward to deltaspike project which i believe fills all those gaps.

  56. Shailendra kumar says:

    That’s a really well written and helpful piece of information. However in all the ensuing debate specifically of the difference in preference to use Tomcat vs EE severs, I did not get a mention of the newest kid on the block TomEE which according to apache is " an all-Apache stack aimed at Java EE 6 Web Profile certification where Tomcat is top dog". This seems to be pretty exciting. Will this be game changer for people who actually like Tomcat but want to move to EE technologies ? What do people think here ?

  57. Interesting article. I’ve been experimenting with JEE 6 myself and wrote a pet app for it, but the immaturity of some of its solutions (CDI being a good example) has managed to seriously put me off, and cause me drift back towards Spring.
    Also, JEE is supposed to be the (self-proclaimed?) standard, but in reality you end up depending on the application server and taking advantage of its features, as you pointed out in the article, and the portability effectively goes out of the window.
    My worst nightmare has been integration testing, which requires an unreasonable amount of effort vs. getting it right with Spring.

    1. rmpestano says:

      "but in reality you end up depending on the application server" Have you really tried to switch among EE servers? if you are in the spec thinks are really straightforward, if you use maven things get even easier. Also how often you migrate from app servers? i’ve seen people arguing that in favor of Spring but they are always using Tomcat…

      "My worst nightmare has been integration testing" have you heard about arquillian(arquillian.org)?

      Another thing thats is really powerful and is growing in EE6 are the CDI portable extensions

  58. […] Annotations, or Hibernate Search, I recommend reading a section in another OCPsoft blog about using extended PersistenceContexts. You can also try some books written by my colleagues and peers. (Note, you will need to disable […]

  59. […] Spring to Java EE – A Migration Experience by Lincoln Baxter […]

  60. Tony Herstell says:

    A Conversation is supposed to be related to a short, CLEAR, "business type process" that has a beginning a middle and and end. This may span multiple round trip to the User within the bounds of a single session.

    +Saves multiple reads from the DB by "caching" stuff in/for the Conversation span
    +Saves up commits to the DB and flushes them at the "natural" end of the conversation or have them ALL rolled back by not committing (very neat!). [@ExtendedPersistance]
    +Gives a CLEAR area to store things so that nothing is left around in the Session/Application etc. Scope when the "business type process" is completed or abandoned.

    Due to the "fad" to completely UsStatelesstise everything (mainly from Spring and JQuery people) this has not had much attention and has largely been forgotten and even JEE 6 (CDI) has only really given it lip service. It’s all about BIG DATA and mashups or 100 things into a facebook/twitter page…

    So; it seems that jPBM (and things like Oracle SOA [BPEL]) have stepped into this space and moved things into what Seam 2 called the @BusinessScope which ALSO supported the ability to come back later to an "in progress" "business type process" so you are not locked into the Session…

    The lack of a "good" implementation of Conversation has driven myself to jBPM (5) which is now looking very capable and is actually built around a Rules Engine (Drools). I hope it is as good as it looks.

  61. Yeah, I really think the JBPM5 stuff is *really* interesting. The Drools guys and Mark Proctor have been doing awesome work, especially with their UberFire web workspace based on the Errai UI framework.

    Really great stuff happening there.

    1. Tony Herstell says:

      Yes its does look awesome.
      Conversation did always have the problem with the "back" button being pressed in page having to be handled.
      here is hoping that, like Seam 2, they handle that out of the box too.
      Interesting to see how they support the users "Work in Progress" UI bits and how easy it is to lock into "security" as I needed more than roles and permissions.

  62. Sunil Kumar says:

    Very good site. Have very good explanation. In coming few months, i have to migrate our legacy Spring application to java CDI and i was in search of such a good article.

    Thanks a lot.

    One Question – What is the alternate for Spring batch jobs (i know java batch jobs are also there but it is not supported by most of the servers)


    1. I’m not very familiar with 3rd party batch libraries, but I know that Java EE 7 supports batch functionality that can be used to replace Spring Batch. Both WildFly and JBoss EAP7 support this spec.

Leave a Comment

Please note: In order to submit code or special characters, wrap it in

[code lang="xml"][/code]
(for your language) - or your tags will be eaten.

Please note: Comment moderation is enabled and may delay your comment from appearing. There is no need to resubmit your comment.