Monday, March 31, 2014

Seam 2 Gotchas - Part 1

A few common mistakes I've seen made with Seam 2:

Referencing EJB Components Directly

I think it's pretty easy to know that referencing a Seam component that happens to be an EJB directly (with @EJB or with a JNDI lookup) is probably not going to end well, but a novice Seam developer might make this mistake.  This mistake is more likely when writing code in a non-JSF part of the system (e.g. a Servlet).

Here's what you can do about it:
  1. Make sure EJB Seam components are injected using @In, or look them up using Seam.   Make sure you have a clear distinction between 'regular' EJBs and Seam component EJBs.  Here are the two main things to avoid:    
    • INJECTING SEAM COMPONENTS WITH @EJB - Use @In instead!
    • LOOKING UP SEAM COMPONENTS WITH JNDI - Use Component.getInstance(name) or  Contexts.lookupInStatefulContexts(name) instead!
  2. In a non-JSF environment, use ContextualHttpServletRequest, for example, in a Servlet:
        @Override
        protected void service(HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException
        {
            //... do some stuff...
            new ContextualHttpServletRequest(request) 
            {
                @Override
                public void process() throws Exception
                {
                    // Access the components, do work.   The contexts will be properly set up here.
                    MyComponent component = (MyComponent)Component.getInstance("myComponent");
                }
            }.run();    // Run the request.
     
        }
    
    See this JBoss community post.   Personally, I strongly prefer using ContextFilter.
  3. In a non-JSF environment, apply the ContextFilter.   This will automatically wrap all requests in ContextualHttpServletRequest().

    For example:  <web:context-filter url-pattern="/servlet/*"/> in components.xml.
Note that when using ContextFilter or ContextualHttpServletRequest, exceptions may be handled differently than you might expect!

If anything inside the ContextFilter/ContextualHttpServletRequest throws an exception, then all the contexts will be torn down.   You may get other filters throwing java.lang.IllegalStateException: No active event context! after the ContextFilter/ContextualHttpServletRequest has finished!

Component Lookup - Component is not automatically created?

While injecting Seam components with @In is the simplest way to access another component, there are cases where a lookup is needed (e.g. in a Servlet).   The problem is, there is more than one way to look up components, and the method used to look up the component will determine the behavior:

  1. Contexts.lookupInStatefulContexts(name) - This is similar to @In : It will not create components automatically!
  2. Component.getInstance(name) - This is similar to @In(autocreate=true) : Components will be created automatically if they don't exist.
 Make sure you use the appropriate method for your use case.

Injected values are null?!?

If you are used to other DI frameworks, you may be expecting injected values to stick around.   Not always the case with Seam :

Seam will set injected fields to null when the request is finished.  Injection / uninjection happen before and after every method invocation.

So, if you access an instance outside of Seam's control, then the injected values might be null.


No comments:

Post a Comment