Question

Looking at the following code snippet, the scenario given is about fetching a database connection from a database connection pool in the Tomcat Server.

public final class DatabaseConnection {

    private static DataSource dataSource;

    static {
        try {
            Context initContext = new InitialContext();
            Context context = (Context) initContext.lookup("java:comp/env");
            dataSource = (DataSource) context.lookup("jdbc/assignment_db");
        } catch (NamingException e) {
            Logger.getLogger(DatabaseConnection.class.getName()).log(Level.SEVERE, null, e);
        }
    }

    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }
}

I would like making the only field in the class final. If I make it a final field then, the compiler complains,

variable dataSource might not have been initialized.

After making it final, if it is initialized to null at the declaration place then, further initialization of this field in the try block is severely forbidden causing a compilation error,

cannot assign a value to final variable dataSource.

NamingException is a checked exception. Hence, it must be caught or declared to be thrown.


Earlier, there was a different scenario. The strategy was to use Apache DBCP as follows.

public final class DatabaseConnection {

    private static final BasicDataSource basicDataSource;

    static {
        basicDataSource = new BasicDataSource();
        basicDataSource.setDriverClassName("com.mysql.jdbc.Driver");
        basicDataSource.setUrl("jdbc:mysql://localhost:3306/assignment_db");
        basicDataSource.setUsername("Tiny");
        basicDataSource.setPassword("root");
    }

    public static Connection getConnection() throws SQLException {
        return basicDataSource.getConnection();
    }
}

In which, the field could be declared final because there is no checked exception and try...catch is unnecessary.

Can I somehow make dataSource final as in the first case?

Was it helpful?

Solution

This has got me stuck many times, until I found out a workaround. You can use a temporary variable in the static block, and assign the dataSource after try-catch ends using that variable:

private static final DataSource dataSource;

static
{
    DataSource tempDataSource = null;
    try
    {                
        Context initContext = new InitialContext();
        Context context = (Context) initContext.lookup("java:comp/env");
        tempDataSource = (DataSource) context.lookup("jdbc/assignment_db");
    } catch (NamingException ex) {
        Logger.getLogger(DatabaseConnection.class.getName()).log(Level.SEVERE, null, ex);
    }
    dataSource = tempDataSource;
}

However, I would rather not follow normally, and throw the exception from the catch block only if dataSource is not initialized, in which case, you won't need a local variable:

static
{
    try
    {                
        Context initContext = new InitialContext();
        Context context = (Context) initContext.lookup("java:comp/env");
        dataSource = (DataSource) context.lookup("jdbc/assignment_db");
    } catch (NamingException ex) {
        Logger.getLogger(DatabaseConnection.class.getName()).log(Level.SEVERE, null, ex);
        throw new ExceptionInInitializerError("dataSource not initialized");
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top