Most commonly, when we need to log something via a Java logger, we write something like this:
private static final Logger LOG = Logger.getLogger(MyClass.class.getName());
Check out the part of the code that is highlighted in red. Well, that part tell us that the above line of code is dependent of the class name where it appears, and this may rise refactoring issues. Moreover, this line must appear in each class that want to use the logger, which is a little bit verbose.
But, CDI comes with a very handy and bidder feature that consist in the fact that we can easily obtained information about the injection point of an artifact. For example, an instance of InjectionPoint can access metadata of the class where the artifact is injected. A bean without an explicit scope (so, having the @Dependent default scope) can inject an instance of InjectionPoint. CDI will take care of providing this instance for us, so all we need to do is to exploit its methods.
Now, if we take a look at the logger case, we can easily conclude that the logger is dependent of a metadata, or more exactly is dependent on the class name. So, if we write something like below, we can actually obtain the desired metadata in an @Dependent bean:
public class MyLogger {
@Produces
Logger produceLogger(InjectionPoint injectionPoint) {
// get the field injection (e.g. fooLog, buzzLog, bizzLog)
Member field = injectionPoint.getMember();
System.out.println("Member: " + field);
// get the class containing the field injection
Class<?> fieldClass = field.getDeclaringClass();
System.out.println("Class: " + fieldClass);
// get the class name
String className = fieldClass.getName();
System.out.println("Class name: " + className);
return Logger.getLogger(className);
// or shortly:
return Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName());
// or shortly:
return Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName());
}
}
First, we declare the produceLogger()method as a CDI producer method via the @Produces annotation, highlighted in blue. By making this method a producer method, we allow the return value of the method -in this case a Logger- to be injected.
As you can see, the part highlighted in red is responsible to use the instance of InjectionPoint for extracting the name of the class where the artifact is injected. Further, we use the extracted class name to create a logger for that class and return it.
So, now we can simply use a logger via injection. For example, we can inject it in FooBean:
@Named
@RequestScoped
public class FooBean {
@Inject
Logger fooLog;
public void logFooAction() {
fooLog.info("Log message from FooBean !");
}
}
Or, in BuzzBean:
@Named
@RequestScoped
public class BuzzBean {
@Inject
Logger buzzLog;
public void logBuzzAction() {
buzzLog.info("Log message from BuzzBean !");
}
}
Or, in BizzBean:
@Named
@RequestScoped
public class BizzBean {
@Inject
Logger bizzLog;
public void logBizzAction() {
bizzLog.info("Log message from BizzBean !");
}
}
Or, in ... any other bean.
Well, a possible output will be:
The complete example is available here.