Introduction
I was recently tasked with looking at some mechanisms to control logging in our JSF applications. This included a number of proof of concept ideas to see which Dependency Injection (DI) mechanisms we could use. We are currently using CDI (Weld), and OpenWebbeans in our applications. I had previously used Guice for doing DI in some other applications especially in Java SE which I found it very easy to use.As I looked around, I found that I could not find a good example of how to use Guice with JSF 2.x. There were a number of articles from over the years for using Guice with JSF 1.2 primarily, but nothing that used some of the great enhancements to JSF 2. I also found very little on how to implement
FacesWrapper
to wrap ApplicationFactory
, Application
, and ELResolver
. The exception being ELResolver
code that you can find in OmniFaces. Implementation
The implementation uses a number of techniques to inject our customELResolver
. First we will use a FacesWrapper
to wrap the ApplicationFactory
. Our implementation will return a custom ApplicationWrapper
implementation, that will return a custom FacesWrapper
for our ELResolver
. This arrangement may seem complex, but separates the concerns to allow us to refactor them as necessary.The code for this project can be found here: jsf-guice-logger-integration
GuiceServletContextListenerImpl.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | package com.bluelotussoftware.guice; import com.bluelotussoftware.guice.slf4j.SLF4JModule; import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.servlet.GuiceServletContextListener; /** * An implementation of {@link GuiceServletContextListener} that injects * {@link SLF4JModule}. * * @author John Yeary <jyeary@bluelotussoftware.com> * @version 1.0 */ public class GuiceServletContextListenerImpl extends GuiceServletContextListener { @Override protected Injector getInjector() { return Guice.createInjector( new SLF4JModule()); } } |
FacesApplicationFactoryWrapper.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | package com.bluelotussoftware.jsf.application; import javax.faces.application.Application; import javax.faces.application.ApplicationFactory; /** * An implementation of {@link ApplicationFactory}. * * @author John Yeary * @version 1.0 */ public class FacesApplicationFactoryWrapper extends ApplicationFactory { private ApplicationFactory factory; /** * Constructor that wraps an {@link ApplicationFactory} instance. * * @param factory The factory instance to be wrapped. */ public FacesApplicationFactoryWrapper( final ApplicationFactory factory) { this .factory = factory; } /** * {@inheritDoc} * <p> * This method returns a {@link FacesApplicationWrapper} instance.</p> */ @Override public Application getApplication() { Application application = factory.getApplication(); return new FacesApplicationWrapper(application); } /** * {@inheritDoc} */ @Override public void setApplication( final Application application) { factory.setApplication(application); } } |
FacesApplicationWrapper.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | package com.bluelotussoftware.jsf.application; import com.bluelotussoftware.jsf.el.GuiceELResolverWrapper; import javax.el.ELResolver; import javax.faces.application.Application; import javax.faces.application.ApplicationWrapper; /** * An implementation of {@link ApplicationWrapper}. * * @author John Yeary * @version 1.0 */ public class FacesApplicationWrapper extends ApplicationWrapper { private Application wrapped; /** * Constructor that wraps an {@link Application} instance. * * @param wrapped The {@link Appplication} to be wrapped. */ public FacesApplicationWrapper( final Application wrapped) { this .wrapped = wrapped; } /** * {@inheritDoc} */ @Override public Application getWrapped() { return wrapped; } /** * {@inheritDoc} * <p> * This method returns a {@link GuiceELResolverWrapper} that wraps the * default {@link ELResolver}. */ @Override public ELResolver getELResolver() { return new GuiceELResolverWrapper(getWrapped().getELResolver()); } } |
GuiceELResolverWrapper.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | package com.bluelotussoftware.jsf.el; import com.google.inject.Injector; import java.beans.FeatureDescriptor; import java.util.Iterator; import java.util.Map; import javax.el.ELContext; import javax.el.ELResolver; import javax.faces.FacesWrapper; import javax.faces.context.FacesContext; /** * A {@link FacesWrapper} implementation that wraps an {@link ELResolver} and * provides a mechanism to inject Guice {@link Injector} implementations. * * @author John Yeary * @version 1.0 */ public class GuiceELResolverWrapper extends ELResolver implements FacesWrapper<elresolver> { private ELResolver wrapped; /** * Default constructor. */ public GuiceELResolverWrapper() { } /** * Constructor that wraps an {@link ELResolver}. * * @param wrapped The resolver to wrap; */ public GuiceELResolverWrapper( final ELResolver wrapped) { this .wrapped = wrapped; } /** * {@inheritDoc} */ @Override public ELResolver getWrapped() { return wrapped; } /** * {@inheritDoc} * <p> * <strong>Note:</strong> This implementation checks to see if the property * can be resolved using the wrapped instance. If the property is resolved, * this method will inject the Guice {@link Injector} implementations. */ @Override public Object getValue( final ELContext context, final Object base, final Object property) { Object obj = getWrapped().getValue(context, base, property); if ( null != obj) { FacesContext fctx = (FacesContext) context.getContext(FacesContext. class ); if ( null != fctx) { Map map = fctx.getExternalContext().getApplicationMap(); Injector injector = (Injector) map.get(Injector. class .getName()); if (injector == null ) { throw new NullPointerException( "Could not locate " + "Guice Injector in application scope using" + " key '" + Injector. class .getName() + "'" ); } injector.injectMembers(obj); } } return obj; } /** * {@inheritDoc} * <p> * <strong>Note:</strong> This returns the wrapped implementation.</p> */ @Override public Class<?> getType( final ELContext context, final Object base, final Object property) { return getWrapped().getType(context, base, property); } /** * {@inheritDoc} * <p> * <strong>Note:</strong> This returns the wrapped implementation.</p> */ @Override public void setValue( final ELContext context, final Object base, final Object property, final Object value) { getWrapped().setValue(context, base, property, value); } /** * {@inheritDoc} * <p> * <strong>Note:</strong> This returns the wrapped implementation.</p> */ @Override public boolean isReadOnly( final ELContext context, final Object base, final Object property) { return getWrapped().isReadOnly(context, base, property); } /** * {@inheritDoc} * <p> * <strong>Note:</strong> This returns the wrapped implementation.</p> */ @Override public Iterator<featuredescriptor> getFeatureDescriptors( final ELContext context, final Object base) { return getWrapped().getFeatureDescriptors(context, base); } /** * {@inheritDoc} * <p> * <strong>Note:</strong> This returns the wrapped implementation.</p> */ @Override public Class<?> getCommonPropertyType( final ELContext context, final Object base) { return getWrapped().getCommonPropertyType(context, base); } } |
faces-config.xml
1 2 3 4 5 6 7 8 9 | <? xml version = '1.0' encoding = 'UTF-8' ?> < faces-config version = "2.0" xsi:schemaLocation = "http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd" > < factory > < application-factory >com.bluelotussoftware.jsf.application.FacesApplicationFactoryWrapper</ application-factory > </ factory > </ faces-config > |
ELResolver
implementation that will resolve our Guice injections. I hope this demonstration of JSF 2.x wrappers can show you how easy it is to implement custom wrappers including a custom ELResolver
.
References
- Integrating Guice and JSF - This is a JSF 1.2 example.
- JSF ELResolver Example
- Custom Injections
- SLF4J Logger Injection with Guice
- Logging with SLF4J and Guice
- DZone - Guice EL Resolver For JSF - This is a JSF 1.2 implementation
0 comments :
Post a Comment