Friday, January 11, 2013

Portable Logger Names with Java 7 Method Handles

Java 7 introduced the Method Handles with the java.lang.invoke.MethodHandle and java.lang.invoke.MethodHandles classes. The Well-Grounded Java Developer (which I have previously reviewed) covers method handles in Chapter 5 (Section 5.2) and concludes with a trivial but highly useful example of what one can do with method handles and logger naming. I briefly explain this idea in this blog post.

When acquiring a logger for a particular Java class, it is common for the Java developer to use that very class to name the logger. In Log4j, this is typically done with a reference to the class itself. For java.util.logging, this is typically done with a reference to the fully qualified name of the class. Although this is easy to do, it is possible to mistakenly provide the wrong class, especially when the incorrectly provided class is in the same package and a logger definition statement is copied and pasted from an existing class to a new class. As the authors of The Well-Grounded Java Developer suggest, the newly introduced MethodHandles class can make this declaration more portable and always based contextually on the class in which the declaration resides.

The MethodHandes.lookup() method returns an instance of MethodHandles.Lookup, from which the lookupClass() method can be invoked. This latter method's return value can be used directly in naming the Log4j logger or can have that returned Class's getCanonicalName() method return its name as a String for naming the java.util.logging logger.

The following two code snippets show this for a class specifying its Log4j logger and for a class specifying its java.util.logging logger. Note that there are more characters in these examples than might normally be present when hard-coding the class or class name into the logger declaration, but this code ensures that the actual class or class name is always used.

MethodHandles Approach to Naming log4j Logger
package dustin.examples.methodhandles;

import java.lang.invoke.MethodHandles;
import org.apache.log4j.Logger;

/**
 * Demonstrating use of MethodHandles with Log4j.
 * 
 * @author Dustin
 */
public class MethodHandlesLoggerLog4j
{
   /** Use Java 7 MethodHandles to get my class for logger. */
   private static final Logger LOGGER = Logger.getLogger(MethodHandles.lookup().lookupClass());

   public static void main(final String[] arguments)
   {
      final String msg = "Hello World: Using MethodHandles for Class to associate with Log4j logger.";
      LOGGER.info(msg);
   }
}
MethodHandles Approach to Naming java.util.logging Logger
package dustin.examples.methodhandles;

import java.lang.invoke.MethodHandles;
import java.util.logging.Logger;

/**
 * Demonstrating use of MethodHandles with java.util.logging.
 * 
 * @author Dustin
 */
public class MethodHandlesLoggerJavaUtilLogging
{
   /** Use Java 7 MethodHandles to get my class name for logger. */
   private static final Logger LOGGER =
           Logger.getLogger(MethodHandles.lookup().lookupClass().getCanonicalName());

   public static void main(final String[] arguments)
   {
      final String msg = "Hello World: Using MethodHandles for Class to associate with java.util.logging logger.";
      LOGGER.info(msg);
   }  
}

This post has looked at an idea for a very simple use of the newly available Java 7 MethodHandles class as covered in The Well-Grounded Java Developer. Although this is a small thing, it is illustrative of a convenient use of a lesser advertised Java 7 language feature that provides many more and far more powerful (and more complex) uses.

2 comments:

Phil H said...

Dustin, would love to see a post about the recent security hole in Java7-- what it was, how it could be exploited, and how they're fixing it...

@DustinMarx said...

Phil,

Two interesting reads on that are The Java Security Exploit in (Mostly) Plain English and 0 day 1.7u10 (CVE-2013-0422) spotted in the Wild - Disable Java Plugin NOW !.

Dustin