Code Pretty Print Script

Thursday, November 7, 2013

Clean Up After Yourself

When you open a lot of dynamic resources, are you tired of maintaining the finally block with excessive try - close - catch boilerplate? Does your project contain a lot of code that looks like this? Wouldn't it be nice if you could close(Connection, Statement, ResultSet) or close(ResultSet, Statement, Connection) or in fact call close on "Anything"‽ with a close method using "duck" typing?

java.sql.Connection conn = null;
java.sql.Statement stmt = null;
java.sql.ResultSet rs = null;
try {
  while (rs.next()) {

  }
} catch (SQLException e) {
} finally {
  if (rs != null) {
    try {
      rs.close();
    } catch (SQLException e) {
    }
  }
  if (stmt != null) {
    try {
      stmt.close();
    } catch (SQLException e) {
    }
  }
  if (conn != null) {
    try {
      conn.close();
    } catch (SQLException e) {
    }
  }
}
You can fix that boiler plate with this Close class!
/*
 * Copyright © 2013 - Elliott Frisch
 * 
 * THIS SOFTWARE IS PROVIDED UNDER THE CREATIVE COMMONS
 * LICENSE 3.0 "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR
 * A PARTICULAR PURPOSE.
 * 
 * To use this software you must agree to the complete
 * license terms available at:
 * http://creativecommons.org/licenses/by/3.0/us/deed.en_US
 * 
 * It is the intent of the author(s) that you may use or
 * modify this software for any purpose (including your own
 * commercial gain) provided that this notice remains in its
 * entirety.
 * 
 * Created by Elliott Frisch - www.frischcode.com
 */
package com.frischcode.util;

import java.io.Closeable;
import java.io.IOException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Set;
import java.util.TreeSet;

/**
 * <b>Rationale:</b> Frequently you're utilizing dynamic
 * resources, and you need those resources to be closed when
 * you're finished with them. <br />
 * 
 * <b>Common Examples:</b>
 * <ul>
 * <li>Performing JDBC Queries</li>
 * <li>Writing to File(s)</li>
 * <li>Writing to Stream(s)</li>
 * <li>Reading from Stream(s)</li>
 * <li>Etc.</li>
 * </ul>
 * 
 * <b>Note:</b> This class consists of only one public
 * static final method and it is not necessary to perform
 * instantiation. Import static on the close method and
 * <i>please</i> enjoy.
 * 
 * @author Elliott Frisch
 */
public final class Close {
  /**
   * Provide a simple demonstration.
   * 
   * @param args
   */
  public static void main(String[] args) {
    close(new AnythingTestClass());
  }

  /**
   * Call close on the provided objects while suppressing
   * exceptions and guaranteeing that the objects will be
   * closed in the following order -
   * <ol>
   * <li>java.sql.ResultSet(s)</li>
   * <li>java.sql.Statement(s)</li>
   * <li>java.sql.Connection(s)</li>
   * <li>java.io.Closeable(s)</li>
   * <li>"Anything"‽ with a close method through
   * "duck" typing</li>
   * </ol>
   * 
   * @param objects
   *          Any number of objects (of any type) to close.
   */
  public static final void close(
      final Object... objects) {
    if (objects == null || objects.length == 0) {
      return;
    } else if (objects.length == 1) {
      final Object obj = objects[0];
      if (obj != null) {
        if (obj instanceof ResultSet) {
          close((ResultSet) obj);
        } else if (obj instanceof Statement) {
          close((Statement) obj);
        } else if (obj instanceof Connection) {
          close((Connection) obj);
        } else if (obj instanceof Closeable) {
          close((Closeable) obj);
        } else {
          close(obj);
        }
      }
      return;
    }
    final Set<ResultSet> rsSet = new TreeSet<ResultSet>();
    final Set<Statement> stmtSet = new TreeSet<Statement>();
    final Set<Connection> connSet = new TreeSet<Connection>();
    final Set<Closeable> closeableSet = new TreeSet<Closeable>();
    final Set<Object> objSet = new TreeSet<Object>();
    for (final Object obj : objects) {
      if (obj == null) {
        continue;
      }
      if (obj instanceof ResultSet) {
        rsSet.add((ResultSet) obj);
      } else if (obj instanceof Statement) {
        stmtSet.add((Statement) obj);
      } else if (obj instanceof Connection) {
        connSet.add((Connection) obj);
      } else if (obj instanceof Closeable) {
        closeableSet.add((Closeable) obj);
      } else {
        objSet.add(obj);
      }
    }
    for (final ResultSet rs : rsSet) {
      close(rs);
    }
    for (final Statement stmt : stmtSet) {
      close(stmt);
    }
    for (final Connection conn : connSet) {
      close(conn);
    }
    for (final Closeable closeable : closeableSet) {
      close(closeable);
    }

    // Close the "Antyhing"(s)‽
    for (final Object obj : objSet) {
      close(obj);
    }
  }

  private static final void close(final ResultSet rs) {
    if (rs != null) {
      try {
        if (rs.isClosed()) {
          return;
        }
        rs.close();
      } catch (final SQLException ignored) {
      }
    }
  }

  private static final void close(final Statement stmt) {
    if (stmt != null) {
      try {
        if (stmt.isClosed()) {
          return;
        }
        stmt.close();
      } catch (final SQLException ignored) {
      }
    }
  }

  private static final void close(final Connection conn) {
    if (conn != null) {
      try {
        if (conn.isClosed()) {
          return;
        }
        conn.close();
      } catch (final SQLException ignored) {
      }
    }
  }

  private static final void close(final Closeable c) {
    if (c != null) {
      try {
        c.close();
      } catch (final IOException ignored) {
      }
    }
  }

  /**
   * Close the "Anything"‽ Reflect on the object. Does
   * it have a parameterless close method? If so, call close
   * on that object!
   * 
   * @param anything
   *          The "Anything"‽ to close.
   */
  private static final void close(final Object anything) {
    if (anything == null) {
      return;
    }
    final Class<?> cls = anything.getClass();
    try {
      final Method m = cls.getMethod("close",
          EMPTY_CLASSES);
      if (m != null) {
        m.invoke(anything, EMPTY_OBJECTS);
      }
    } catch (final Exception ignored) {
    }
  }

  private static final Class<?>[] EMPTY_CLASSES = //
      new Class<?>[] {};
  private static final Object[] EMPTY_OBJECTS = //
      new Object[] {};

  private static class AnythingTestClass {
    private AnythingTestClass() {
      System.out.println("Anything\u203d"
          + "TestClass Constructed");
    }

    /*
     * In this case static analysis (i.e. Eclipse) is
     * @WRONG.
     */
    @SuppressWarnings("unused")
    public void close() {
      System.out.println("Inside the Anything\u203d"
          + "TestClass.close() method.");
    }
  }

  // Help against "accidents".
  private Close() {
    super();
  }
}

No comments :

Post a Comment