Friday, August 19, 2011

JDK7: ARM (Automatic Resource Management) or try-with-resources - Using Java 7 in Java EE 6/GlassFish

Java 7 is now available, NetBeans 7.0.1 provide complete tooling around it, and GlassFish 3.1.1 allow you to leverage JDK7 features in your Java EE 6 applications. this article will explain a new feature introduced in JDK7 and how it can be used to simplify your Java EE 6 application code.

Automatic Resource Management (ARM) or try-with-resources is one of the functionality coming from Project Coin as part of Java 7. It simplifies working with external resources such as JDBC connection/statement and xxxInput/OutputStream which need to be explicitly closed in case of an error or successful completion of a code block.

@javax.annotation.PostConstruct

 void startup() {
   Connection c = null;
   Statement s = null;
   try {
     InitialContext ctx = new InitialContext();
     DataSource ds = (DataSource)ctx.lookup("jdbc/__default");
     c = ds.getConnection();
     s = c.createStatement();
 // invoke SQL here
   } catch (SQLException ex) {
     System.err.println("ouch!");
   } catch (NamingException ex) {
     System.err.println("ouch!");
   } finally {
     try {
       if (s != null)
         s.close();
       if (c != null)
         c.close();
     } catch (SQLException ex) {
       System.err.println("ouch!");;
     }
   }
 }
This is a lot of boilerplate code, couple of specific points to note here:
  • Because Connection and Statement need to be closed in "finally" block, they need to be declared outside of the "try" block.
  • "s.close()" and "c.close()" can further throw an SQLException and so there is a nested exception in the "finally" block.
 This code can also be rewritten as:
@Resource(name="jdbc/sample")
DataSource ds;

@javax.annotation.PostConstruct
 void startup() {
   Connection c = null;
   Statement s = null;
   try {
     c = ds.getConnection();
     s = c.createStatement();
     // invoke SQL here
   } catch (SQLException ex) {
     System.err.println("ouch!");
   } finally {
     try {
       if (s != null)
         s.close();
       if (c != null)
         c.close();
     } catch (SQLException ex) {
       System.err.println("ouch!");;
     }
   }
 }
It still has tons of boilerplate code. This can be easily simplified using JDK 7 Automatic Resource Management by changing the code to:

@Resource(name="jdbc/sample")
DataSource ds;
@javax.annotation.PostConstruct
void startup() {
 try (Connection c = ds.getConnection();
     Statement s = c.createStatement())

       // invoke SQL here
     } catch (SQLException ex) {
       System.err.println("ouch!");;
     }
   }
 }

The resources defined in the "try" block are automatically closed as they get out of scope and there is no boilerplate code here. The code is much more semantically readable and contains 285 characters instead of 629 in the first version.

NOTE: The code fragments in this blog are updated because throwing a checked exception from a @PostConstruct method is not permitted by the Managed Beans specification.

How does this all work under the hood ?

A new java.lang.Autocloseable API has been added to the platform which has a single "close()" method that automatically closes the resource. The java.io.Closeable extends this new API ensuring that xxxInputStream and xxxOutputStream are candidates for ARM. Any resource implementing this interface can be used for ARM so if there are any custom resources in your project then they can leverage this functionality as well.

No comments :

Post a Comment