As I’m sure you can tell from previous entries, I’ve been playing with JSF 2 in Google App Engine. I decided to give Google’s Guice a try for dependency injection instead of Spring. Why? This is really just a learning app and why not try something new.
So how do you get Guice to play nicely with JSF? One solution I saw online was to write a custom ELResolver for JSF that will do the injection. I found this resource http://snippets.dzone.com/posts/show/7171 that had a full ELResolver implementation. I had to modify it slightly to get it to work. Namely, I had to move the Guice Injector creation out of getValue and into a private static variable. I suspect I could make it not static, but I never gave it a try. Here’s the source just in case that link dies at some point. Again, I take no credit for this code other than the small modification mentioned.
/**
* Bulk of the code taken from
* http://snippets.dzone.com/posts/show/7171
**/
package jota.soc.guice;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.servlet.ServletModule;
import java.beans.FeatureDescriptor;
import java.lang.ref.WeakReference;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import javax.el.ELContext;
import javax.el.ELResolver;
/**
*/
public class GuiceResolver extends ELResolver
{
Injector injector = Guice.createInjector(
new ServletModule(),
new SocGuiceModule() );
//We only need to see the currently processed Objects in our Thread, that
//prevents multithread issues without synchronization
private static ThreadLocal currentlyProcessedThreadLocal = new ThreadLocal()
{
@Override
protected Object initialValue()
{
return new LinkedList();
}
};
//Im not sure if the synchronized lists seriously slow down the whole EL
//resolving process
private static List<WeakReference> alreadyInjectedObjects = Collections.
synchronizedList( new LinkedList() );
@Override
public Object getValue( ELContext context, Object base, Object property )
{
//if the list of currently processed property objects doesnt exist for this
//thread, create it
List<Object> currentlyProcessedPropertyObjects = (List<Object>) currentlyProcessedThreadLocal.
get();
//Handle only root inquiries, we wont handle property resolving
if ( base != null )
{
return null;
}
//checking if this property is currently processed, if so ignore it -> prevent
//endless loop
if ( checkIfObjectIsContained( property,
currentlyProcessedPropertyObjects ) )
{
return null;
}
//add the to-be-resolved object to the currently processed list
currentlyProcessedPropertyObjects.add( property );
//now we can savely invoke the getValue() Method of the composite EL
//resolver, we wont process it again
Object resolvedObj = context.getELResolver().getValue( context, base,
property );
//ok, we got our result, remove the object from the currently processed list
removeObject( property, currentlyProcessedPropertyObjects );
if ( resolvedObj == null )
{
return null;
}
//ok we got an object
context.setPropertyResolved( true );
//check if the object was already injected
if ( !checkIfObjectIsContainedWeak( resolvedObj, alreadyInjectedObjects ) )
{
injector.injectMembers( resolvedObj );
//prevent a second injection by adding it as weakreference to our list
alreadyInjectedObjects.add( new WeakReference( resolvedObj ) );
}
return resolvedObj;
}
/**
* This method will search for an object in a Weak List. If there are any
* WeakReferences on the way that were removed by the garbage collection
* we will remove them from this list
* @param object
* @param list
* @return
*/
private boolean checkIfObjectIsContainedWeak( Object object,
List<WeakReference> list )
{
for ( int i = 0; i < list.size(); i++ )
{
WeakReference curReference = list.get( i );
Object curObject = curReference.get();
if ( curObject == null )
{
//ok, there is are slight chance that could go wrong, if you
//have to prevent a double injection by all means, you might
//want to add a synchronized block here
list.remove( i );
i--;
}
else
{
if ( curObject == object )
{
return true;
}
}
}
return false;
}
/**
* checks if an object is contained in a collection (really the same object '==' not equals)
* @param object
* @param collection
* @return
*/
private boolean checkIfObjectIsContained( Object object,
Collection collection )
{
for ( Object curObject : collection )
{
if ( object == curObject )
{
return true;
}
}
return false;
}
/**
* removes an object from a list. really removes the given instance, not an other
* object that fits equals
* @param object
* @param list
*/
private void removeObject( Object object, List list )
{
for ( int i = 0; i < list.size(); i++ )
{
if ( list.get( i ) == object )
{
list.remove( i );
}
}
}
@Override
public Class<?> getType( ELContext context, Object base, Object property )
{
return null;
}
@Override
public void setValue( ELContext context, Object base, Object property,
Object value )
{
}
@Override
public boolean isReadOnly( ELContext context, Object base, Object property )
{
return false;
}
@Override
public Iterator<FeatureDescriptor> getFeatureDescriptors( ELContext context,
Object base )
{
return null;
}
@Override
public Class<?> getCommonPropertyType( ELContext context, Object base )
{
return null;
}
}
That sure looks like a lot of code to me. I know Spring also provides a custom ELResolver for dependency injection. I found two links talking about resource injection here and here and thought I would try writing my own resource injector. Here’s how it ended up:
package jota.soc.guice;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.servlet.ServletModule;
import com.sun.faces.spi.InjectionProvider;
import com.sun.faces.spi.InjectionProviderException;
import com.sun.faces.vendor.WebContainerInjectionProvider;
/**
* JSF injection provider for Guice.
* @author Joel Weight
*/
public class GuiceInjectionProvider implements InjectionProvider
{
public GuiceInjectionProvider()
{
System.out.println( "creating guice injection provider" );
}
/**
* default injector provided by the web container.
*/
private static final WebContainerInjectionProvider con =
new WebContainerInjectionProvider();
/**
* Custom guice injector that will load our modules.
*/
private static final Injector injector = Guice.createInjector(
new ServletModule(),
new SocGuiceModule() );
@Override
public void inject( Object managedBean ) throws InjectionProviderException
{
// allow the default injector to inject the bean.
con.inject( managedBean );
// then inject with the google injector.
injector.injectMembers( managedBean );
}
@Override
public void invokePostConstruct( Object managedBean )
throws InjectionProviderException
{
// don't do anything here for guice, just let the default do its thing
con.invokePostConstruct( managedBean );
}
@Override
public void invokePreDestroy( Object managedBean ) throws
InjectionProviderException
{
con.invokePreDestroy( managedBean );
}
}
It’s a very simple implementation. It delegates everything to the default container InjectionProvider, and then adds a touch of Guice. I then added this to web.xml:
<context-param>
<param-name>com.sun.faces.injectionProvider</param-name>
<param-value>jota.soc.guice.GuiceInjectionProvider</param-value>
</context-param>
And all my guice injections are occurring as expected. I am no longer using the custom ELResolver implementation. Obviously it’s not a general solution since I am instantiating my guice modules right in the provider rather than configuring it somehow, but it was enough for me right now.
If I run into any problems with this solution I’ll let you know, otherwise I would love to hear from any gurus as to how this could be problematic.