This site demonstrates the pitfalls with using returns & finally:

http://www.cs.arizona.edu/sumatra/hallofshame/

It seems like this behaviour is not specified by the Java Language 
Specification.

Cheers,
Scott

Greg Davis wrote:
> This deals with try/catch blocks and finallys. I always believed that "no
> matter what" a finally block is always called.  While this seems to remain
> true, it does not seem to necessarily properly call the code within the
> block.  In the section below I have some code and explanation of how a
> finally gets called, but does not execute the code within.
> 
> There seems to be an issue with closing a JDBC connection if a method
> returns in the middle of the try/catch block.  It seems to call the finally,
> but does not close the connection.  It does seem to call static methods like
> System.out.println() perfectly fine.  I don't know if it being static has
> anything to do with it.  I haven't researched it too far since it was really
> hard to find.  First off you have to have a Factory like a ConnectionPool
> that spawns out inscances of an object for other classes to use. Then it
> must need to have the user close it's connection at some point so the
> Factory can control resources. The only example I really have on hand is a
> JDBC connection pool in a J2EE app server.  This is where the problem occurd
> for us.  If the methods "returns" are moved outside the try/catch block, the
> Connection.close() happens properly and the ConnectionPool does not
> complain.
> 
> I realize the getColumnClose() is the better way to implement the code
> ayway, but I wanted to show everyone this problem in case they accidentally
> do it in their code somewhere.  Any returns in the try or catches seemed to
> make the finally not be properly executed. I seem to remember some wierd
> rule about this at JavaOne last year, but my head is still racing from all
> that information. :-)
> 
> Any comments?
> 
> package test;
> 
> import java.sql.*;
> import javax.sql.DataSource;
> import javax.naming.*;
> 
> /**
>  * <p>Title: TryCatchTest</p>
>  * <p>Description: This is a test application for try/catch problem.  If
> using
>  * a Connection Pool in JDBC and you try to "return" a value within a
> try/catch
>  * that is inside a method, the finally of that try/catch is not completely
> run.
>  * It seems to go through the finally(I.E. Sytem.out.println() works, but
> the
>  * Connection.close() is either never called or not executed.  If the
> "return"
>  * is moved to the outside of the catch block, the connection is properly
> closed.
>  * <br>
>  * We found this because a J2EE server which had a connection pool was
> telling
>  * us we were not closing our connections.  I dn't know if there is some
> rule that
>  * when a "return" has been called only static methods or something like
> that can
>  * be called.</p>
>  * <p>Copyright: Copyright (c) 2002</p>
>  * <p>Company: Western Electronics </p>
>  * @author <a href="mail:[EMAIL PROTECTED]">Greg Davis</a>
>  * @version 1.0
>  */
> 
> public class TryCatchTest
> {
>   Context jndiContext;
> 
>   public TryCatchTest()
>   {
>     try
>     {
>       jndiContext = new InitialContext();
>     }
>     catch(NamingException ne)
>     {}
>   }
> 
>   public String getColumnNoClose()
>   {
>     Connection conn = null;
>     PreparedStatement ps = null;
>     ResultSet rs = null;
>     try
>     {
>       String sql ="SELECT table_name FROM sequence";
>       conn
> =((DataSource)jndiContext.lookup("jdbc/mySourceDS")).getConnection();
>       ps = conn.prepareStatement(sql);
>       rs = ps.executeQuery();
>       if(rs != null && rs.next())
>       {
>         //This return causes the ?non-static? code within the finally to not
> to be run.
>         return rs.getString("table_name");
>       }
>       //same here, the finally ?non-static? code is not called.
>       return null;
>     }
>     catch(NamingException ne)
>     {
>       //same here, the finally ?non-static? code is not called.
>       return null;
>     }
>     catch(SQLException sqle)
>     {
>       sqle.printStackTrace();
>       //The same problem occurs here.  The finally ?non-static? code is not
> called
>       return null;
>     }
>     finally
>     {
>       //This system out works, but the conn.close() does not.  The only way
> I
>       //know how to check this is to create a ConnectionPool yourself that
> watches
>       //the connections it spawns out, or user a pre-built one that does the
> same.
>       //We use Orion 1.5.4 J2EE App server (free for development). if you
> want
>       //to test this out.
>       System.out.println("Finally called in noClose()");
>       try
>       {
>         if(rs != null)
>           rs.close();
>         if(ps != null)
>           ps.close();
>         if(conn != null)
>           conn.close();
>       }
>       catch(SQLException sqle)
>       {
>         sqle.printStackTrace();
>       }
>     }
>   }
> 
>   public String getColumnClose()
>   {
>     String returnValue = null;
>     Connection conn = null;
>     PreparedStatement ps = null;
>     ResultSet rs = null;
>     try
>     {
>       String sql ="SELECT table_name FROM sequence";
>       conn
> =((DataSource)jndiContext.lookup("jdbc/mySourceDS")).getConnection();
>       ps = conn.prepareStatement(sql);
>       rs = ps.executeQuery();
>       if(rs != null && rs.next())
>       {
>         //This does call the finally
>         returnValue = rs.getString("table_name");
>       }
> 
>     }
>     catch(NamingException ne)
>     {}
>     catch(SQLException sqle)
>     {
>       //This allso calles the finally if I break the quey
>       sqle.printStackTrace();
>     }
>     finally
>     {
>       //This one works normally
>       System.out.println("Finally called in Close()");
>       try
>       {
>         if(rs != null)
>           rs.close();
>         if(ps != null)
>           ps.close();
>         if(conn != null)
>           conn.close();
>       }
>       catch(SQLException sqle)
>       {
>         sqle.printStackTrace();
>       }
>     }
>     return returnValue;
>   }
> 
>   public static void main(String[] args)
>   {
>     TryCatchTest tct1 = new TryCatchTest();
>     System.out.println("tct1.getColumnNoClose():" +
> tct1.getColumnNoClose());
>     System.out.println("tct1.getColumnClose():" +tct1.getColumnClose());
>   }
> }
> 
> 


-- 
Scott Farquhar :: [EMAIL PROTECTED]

Atlassian :: http://www.atlassian.com
      Supporting YOUR J2EE World



Reply via email to