SR-71 |
@Postconstruct
. I was unsuccessful with this technique, but it was not a total loss. The examples I found on interceptors for life-cycle interception were "empty". They generally mention you can do it, but they did not show any real useful examples.I hope to change that with this example. The example I demonstrate could be easily done with constructor injection, but in the case of a no-args constructor this may be your only opportunity to inject objects during
@PostConstruct
. I am going to suggest that if you want to make this functionality more general, you should use an interface and call the interface methods.The
InvocationContext
will return Class<? extends T>
using context.getTarget()
. We can use this concept to control our injection to the object. In my case, I use setter injection on the object. Pretty cool!
The code for this example can be downloaded from here: cdi-lifecycle-interceptor-example
There are a couple of classes needed to set up our
@Interceptor
. The first is an interface we will call Loggable
and the second is an @InterceptorBinding
.
Loggable.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | package com.bluelotussoftware.example.cdi; import java.util.logging.Logger; /** * This allows for setting a {@link Logger} in an implementing class. * * @author John Yeary * @version 1.0 */ public interface Loggable { /** * Sets the logger for a class. * * @param logger the logger to be set. */ void setLogger(Logger logger); } |
Interceptable.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | package com.bluelotussoftware.example.cdi; import static java.lang.annotation.ElementType.TYPE; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Target; import javax.interceptor.InterceptorBinding; /** * An interceptor binding. * * @author John Yeary * @version 1.0 */ @Inherited @InterceptorBinding @Retention (RUNTIME) @Target ({TYPE}) public @interface Interceptable { } |
@Interceptor
. This code contains all of the magic we need for the target class which we are intercepting.
PostConstructInterceptor.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 | package com.bluelotussoftware.example.cdi; import java.util.Map; import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; import javax.annotation.PostConstruct; import javax.interceptor.Interceptor; import javax.interceptor.InvocationContext; /** * * @author John Yeary * @version 1.0 */ @Interceptable @Interceptor public class PostConstructInterceptor { private static final Logger log = Logger.getLogger(PostConstructInterceptor. class .getName()); /** * This is the method that handles the {@link @PostConstruct} event. The * method name can be called any legal Java method name. I chose * <code>intercept</code> since it is an action describing what we are * doing. * * @param context The current invocation context. * @throws Exception If any {@link Exception} occurs during processing. */ @PostConstruct public void intercept(InvocationContext context) throws Exception { log.setLevel(Level.FINE); log.info( "Before call to @PostConstuct." ); Map<String, Object> map = context.getContextData(); for (String key : map.keySet()) { log.log(Level.INFO, "Context data key --> {0} data --> {1}" , new Object[]{key, map.get(key)}); } log.log(Level.INFO, "Examining object: {0}" , context.getTarget().getClass().getName()); // Best practice is to check if the object is an instanceof an interface. if (context.getTarget() instanceof Loggable) { Loggable loggable = (Loggable) context.getTarget(); loggable.setLogger(Logger.getLogger(context.getTarget().getClass().getName())); } /* * This checks for an instanceof a specific bean. This is not the preferred approach * unless you are really expecting to only check for a specific class. */ if (context.getTarget() instanceof IndexBean) { IndexBean indexBean = (IndexBean) context.getTarget(); indexBean.setFactory( new UUIDFactory() { @Override public UUID generateUUID() { return UUID.randomUUID(); } }); } context.proceed(); log.info( "After call to to @PostConstuct." ); } } |
@PostConstruct
method is executed, i.e., context.proceed()
.
Finally, we need to have our class that we are intercepting. In this case, it is a simple
@Named
and @RequestScoped
CDI bean.
IndexBean.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 | package com.bluelotussoftware.example.cdi; import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; import javax.annotation.PostConstruct; import javax.enterprise.context.RequestScoped; import javax.inject.Named; /** * A page backing bean for the * <code>index.xhtml</code> page. * * @author John Yeary <jyeary@bluelotussoftware.com> * @version 1.0 */ @Named @RequestScoped @Interceptable public class IndexBean implements Loggable { private UUIDFactory factory; private Logger log; /** * Default no-argument constructor. */ public IndexBean() { } @PostConstruct private void initialize() { // This should cause an NPE since logger is not initialized, but we will do our magic here. log.info( "I am an injected logger" ); } /** * {@inheritDoc} */ @Override public void setLogger( final Logger logger) { this .log = logger; } /** * This sets the UUID factory for the bean. * * @param factory the factory to be set. */ public void setFactory( final UUIDFactory factory) { log.log(Level.INFO, "Factory being set to {0}" , factory); this .factory = factory; } /** * This returns a randomly generated {@link UUID#randomUUID()#toString()} * * @return a randomly generated UUID value, or {@code null} if the factory * is not initialized. */ public String getUUID() { if ( null != factory) { return factory.generateUUID().toString(); } else { return null ; } } } |
Our final output is shown here.
![]() |
UUID Please? |
0 comments :
Post a Comment