Nicolas Frankel is an IT consultant with 10 years experience in Java / JEE environments. He likes his job so much he writes technical articles on his blog and reviews technical books in his spare time. He also tries to find other geeks like him in universities, as a part-time lecturer. Nicolas is a DZone MVB and is not an employee of DZone and has posted 224 posts at DZone. You can read more from them at their website. View Full User Profile

Managing unmanaged beans in CDI

01.05.2012
| 5698 views |
  • submit to reddit

During these (much deserved) vacations, I worked on a pet project of mine which uses CDI with the Weld implementation and SLF4J with the Logback implementation.

The terms of the problem were very simple:  Iwanted the logs of my application to be displayed in a Swing table, i.e. a Logback appender had to write in a table. The table was managed in CDI but the appender was not: this was no surprise since many older-generation frameworks have a lifecycle management on their own. Prior-to-JEE6 Servlets, Log4J appenders, Struts actions all have their own lifecycle management, completely unrelated to CDI. Worse, dependency injection frameworks are in large part incompatible with one another (Spring comes to mind) and need an adapter to bridge between their contexts, so this use-case is a common one.

My first lead was to bootstrap Logback myself but since Weld uses SLF4J under the cover, I found no way. After some time, the conclusion was that CDI provided no means to inject my managed table into the Logback appender. That was a sad conclusion, but I didn’t stop there: when the specification doesn’t address your needs, jump to the implementation (but with remorse…).

There’s a nice complementary module to Weld called Weld Extensions, that provide additional features not mentioned in the JSR. Note that Weld Extensions seems to have been replaced by Seam Solder, but the logic stays the same: obtain a reference to the BeanManager and forcibly inject the table in the appender through it.

In Extension, the callback is made through the Extension marker interface. Such extensions are looked up by Weld using the service provider mechanism. If you’re not familiar with it, have a look at it, it’s elegant and useful in many use-cases. So, I created my META-INF/services/javax.enterprise.inject.spi.Extension file.

Now, let’s have a look at the extension itself:

import java.util.List;
 
import javax.annotation.PostConstruct;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.Extension;
import javax.enterprise.inject.spi.InjectionTarget;
 
import org.jboss.weld.environment.se.events.ContainerInitialized;
import org.slf4j.impl.StaticLoggerBinder;
 
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.Appender;
 
public class LogbackWeldExtension implements Extension {
 
  public void bind(@Observes ContainerInitialized event, BeanManager manager) {
 
    LoggerContext loggerContext = (LoggerContext) StaticLoggerBinder.getSingleton().getLoggerFactory();
 
    List loggers = loggerContext.getLoggerList();
 
    for (Logger logger : loggers) {
 
      Appender appender = logger.getAppender("Table");
 
      if (appender != null) {
 
        AnnotatedType type = manager.createAnnotatedType(appender.getClass());
 
        InjectionTarget target = manager.createInjectionTarget(type);
 
        CreationalContext creationalContext = manager.createCreationalContext(null);
 
        target.inject(appender, creationalContext);
      }
    }
  }
}
  • At line 19, we inherit from Extension
  • At line 21, we observe the container initialized event, meaning the method is called when the Weld context is initialized. Note the BeanManager is the second parameter and is injected automatically by the framework!
  • From line 23 to 31, we use Logback’s API to get the handle on the unmanaged appender. Note that we get the reference by name, which I did because I was lazy at the time… The future version will browse through all appenders and get the correct one by class name.
  • Frome line 33 to 39, we use Weld’s API to inject the unmanaged logger into the beans that needs it. Note there’s no reference to the injected table bean, it’s just standard DI if the managed beans are correctly annotated. If you use this code, also note the compiler will warn you about the unused generics (those are a pain to work with!).

That’s it!

To go further:

 

From http://blog.frankel.ch/managing-unmanaged-beans-in-cdi

Published at DZone with permission of Nicolas Frankel, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags: