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.
Nice, but how do I test the method logBuzzAction()? In a simple JUnit test I would run into an NullPointerException (because bizzLog is null), wouldn't I?
RăspundețiȘtergereYou can try to use CDI alternatives (@Alternative) and/or mock test.
ȘtergereAlso, you can try Jglue (http://jglue.org/cdi-unit-user-guide/)
ȘtergereCheck this: http://www.omnifaces-fans.org/2016/06/cdi-jsf-testing-cdi-code.html
Ștergere