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.