SqlNullCheckedResultSet.java
- /*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.apache.commons.dbutils.wrappers;
- import java.io.InputStream;
- import java.io.Reader;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- import java.math.BigDecimal;
- import java.net.URL;
- import java.sql.Blob;
- import java.sql.Clob;
- import java.sql.Date;
- import java.sql.Ref;
- import java.sql.ResultSet;
- import java.sql.Time;
- import java.sql.Timestamp;
- import java.util.HashMap;
- import java.util.Map;
- import org.apache.commons.dbutils.ProxyFactory;
- /**
- * Decorates a {@code ResultSet} with checks for a SQL NULL value on each
- * {@code getXXX} method. If a column value obtained by a
- * {@code getXXX} method is not SQL NULL, the column value is returned. If
- * the column value is SQL null, an alternate value is returned. The alternate
- * value defaults to the Java {@code null} value, which can be overridden
- * for instances of the class.
- *
- * <p>
- * Usage example:
- * <blockquote>
- * <pre>
- * Connection conn = // somehow get a connection
- * Statement stmt = conn.createStatement();
- * ResultSet resultSet = stmt.executeQuery("SELECT col1, col2 FROM table1");
- *
- * // Wrap the result set for SQL NULL checking
- * SqlNullCheckedResultSet wrapper = new SqlNullCheckedResultSet(resultSet);
- * wrapper.setNullString("---N/A---"); // Set null string
- * wrapper.setNullInt(-999); // Set null integer
- * resultSet = ProxyFactory.instance().createResultSet(wrapper);
- *
- * while (resultSet.next()) {
- * // If col1 is SQL NULL, value returned will be "---N/A---"
- * String col1 = resultSet.getString("col1");
- * // If col2 is SQL NULL, value returned will be -999
- * int col2 = resultSet.getInt("col2");
- * }
- * resultSet.close();
- * </pre>
- * </blockquote>
- * </p>
- * <p>Unlike some other classes in DbUtils, this class is NOT thread-safe.</p>
- */
- public class SqlNullCheckedResultSet implements InvocationHandler {
- /**
- * Maps normal method names (ie. "getBigDecimal") to the corresponding null
- * Method object (ie. getNullBigDecimal).
- */
- private static final Map<String, Method> NULL_METHODS = new HashMap<>();
- /**
- * The {@code getNull} string prefix.
- * @since 1.4
- */
- private static final String GET_NULL_PREFIX = "getNull";
- static {
- final Method[] methods = SqlNullCheckedResultSet.class.getMethods();
- for (final Method method : methods) {
- final String methodName = method.getName();
- if (methodName.startsWith(GET_NULL_PREFIX)) {
- final String normalName = "get" + methodName.substring(GET_NULL_PREFIX.length());
- NULL_METHODS.put(normalName, method);
- }
- }
- }
- /**
- * The factory to create proxies with.
- */
- private static final ProxyFactory factory = ProxyFactory.instance();
- /**
- * Wraps the {@code ResultSet} in an instance of this class. This is
- * equivalent to:
- * <pre>
- * ProxyFactory.instance().createResultSet(new SqlNullCheckedResultSet(resultSet));
- * </pre>
- *
- * @param resultSet The {@code ResultSet} to wrap.
- * @return wrapped ResultSet
- */
- public static ResultSet wrap(final ResultSet resultSet) {
- return factory.createResultSet(new SqlNullCheckedResultSet(resultSet));
- }
- private InputStream nullAsciiStream;
- private BigDecimal nullBigDecimal;
- private InputStream nullBinaryStream;
- private Blob nullBlob;
- private boolean nullBoolean;
- private byte nullByte;
- private byte[] nullBytes;
- private Reader nullCharacterStream;
- private Clob nullClob;
- private Date nullDate;
- private double nullDouble;
- private float nullFloat;
- private int nullInt;
- private long nullLong;
- private Object nullObject;
- private Ref nullRef;
- private short nullShort;
- private String nullString;
- private Time nullTime;
- private Timestamp nullTimestamp;
- private URL nullURL;
- /**
- * The wrapped result.
- */
- private final ResultSet resultSet;
- /**
- * Constructs a new instance of
- * {@code SqlNullCheckedResultSet}
- * to wrap the specified {@code ResultSet}.
- * @param resultSet ResultSet to wrap
- */
- public SqlNullCheckedResultSet(final ResultSet resultSet) {
- this.resultSet = resultSet;
- }
- /**
- * Returns the value when a SQL null is encountered as the result of
- * invoking a {@code getAsciiStream} method.
- *
- * @return the value
- */
- public InputStream getNullAsciiStream() {
- return this.nullAsciiStream;
- }
- /**
- * Returns the value when a SQL null is encountered as the result of
- * invoking a {@code getBigDecimal} method.
- *
- * @return the value
- */
- public BigDecimal getNullBigDecimal() {
- return this.nullBigDecimal;
- }
- /**
- * Returns the value when a SQL null is encountered as the result of
- * invoking a {@code getBinaryStream} method.
- *
- * @return the value
- */
- public InputStream getNullBinaryStream() {
- return this.nullBinaryStream;
- }
- /**
- * Returns the value when a SQL null is encountered as the result of
- * invoking a {@code getBlob} method.
- *
- * @return the value
- */
- public Blob getNullBlob() {
- return this.nullBlob;
- }
- /**
- * Returns the value when a SQL null is encountered as the result of
- * invoking a {@code getBoolean} method.
- *
- * @return the value
- */
- public boolean getNullBoolean() {
- return this.nullBoolean;
- }
- /**
- * Returns the value when a SQL null is encountered as the result of
- * invoking a {@code getByte} method.
- *
- * @return the value
- */
- public byte getNullByte() {
- return this.nullByte;
- }
- /**
- * Returns the value when a SQL null is encountered as the result of
- * invoking a {@code getBytes} method.
- *
- * @return the value
- */
- public byte[] getNullBytes() {
- if (this.nullBytes == null) {
- return null;
- }
- return this.nullBytes.clone();
- }
- /**
- * Returns the value when a SQL null is encountered as the result of
- * invoking a {@code getCharacterStream} method.
- *
- * @return the value
- */
- public Reader getNullCharacterStream() {
- return this.nullCharacterStream;
- }
- /**
- * Returns the value when a SQL null is encountered as the result of
- * invoking a {@code getClob} method.
- *
- * @return the value
- */
- public Clob getNullClob() {
- return this.nullClob;
- }
- /**
- * Returns the value when a SQL null is encountered as the result of
- * invoking a {@code getDate} method.
- *
- * @return the value
- */
- public Date getNullDate() {
- return this.nullDate != null ? new Date(this.nullDate.getTime()) : null;
- }
- /**
- * Returns the value when a SQL null is encountered as the result of
- * invoking a {@code getDouble} method.
- *
- * @return the value
- */
- public double getNullDouble() {
- return this.nullDouble;
- }
- /**
- * Returns the value when a SQL null is encountered as the result of
- * invoking a {@code getFloat} method.
- *
- * @return the value
- */
- public float getNullFloat() {
- return this.nullFloat;
- }
- /**
- * Returns the value when a SQL null is encountered as the result of
- * invoking a {@code getInt} method.
- *
- * @return the value
- */
- public int getNullInt() {
- return this.nullInt;
- }
- /**
- * Returns the value when a SQL null is encountered as the result of
- * invoking a {@code getLong} method.
- *
- * @return the value
- */
- public long getNullLong() {
- return this.nullLong;
- }
- /**
- * Returns the value when a SQL null is encountered as the result of
- * invoking a {@code getObject} method.
- *
- * @return the value
- */
- public Object getNullObject() {
- return this.nullObject;
- }
- /**
- * Returns the value when a SQL null is encountered as the result of
- * invoking a {@code getRef} method.
- *
- * @return the value
- */
- public Ref getNullRef() {
- return this.nullRef;
- }
- /**
- * Returns the value when a SQL null is encountered as the result of
- * invoking a {@code getShort} method.
- *
- * @return the value
- */
- public short getNullShort() {
- return this.nullShort;
- }
- /**
- * Returns the value when a SQL null is encountered as the result of
- * invoking a {@code getString} method.
- *
- * @return the value
- */
- public String getNullString() {
- return this.nullString;
- }
- /**
- * Returns the value when a SQL null is encountered as the result of
- * invoking a {@code getTime} method.
- *
- * @return the value
- */
- public Time getNullTime() {
- return this.nullTime != null ? new Time(this.nullTime.getTime()) : null;
- }
- /**
- * Returns the value when a SQL null is encountered as the result of
- * invoking a {@code getTimestamp} method.
- *
- * @return the value
- */
- public Timestamp getNullTimestamp() {
- if (this.nullTimestamp == null) {
- return null;
- }
- final Timestamp ts = new Timestamp(this.nullTimestamp.getTime());
- ts.setNanos(this.nullTimestamp.getNanos());
- return ts;
- }
- /**
- * Returns the value when a SQL null is encountered as the result of
- * invoking a {@code getURL} method.
- *
- * @return the value
- */
- public URL getNullURL() {
- return this.nullURL;
- }
- /**
- * Intercepts calls to {@code get*} methods and calls the appropriate
- * {@code getNull*} method if the {@code ResultSet} returned
- * {@code null}.
- *
- * @see java.lang.reflect.InvocationHandler#invoke(Object, java.lang.reflect.Method, Object[])
- * @param proxy Not used; all method calls go to the internal result set
- * @param method The method to invoke on the result set
- * @param args The arguments to pass to the result set
- * @return null checked result
- * @throws Throwable error
- */
- @Override
- public Object invoke(final Object proxy, final Method method, final Object[] args)
- throws Throwable {
- final Object result = method.invoke(this.resultSet, args);
- final Method nullMethod = NULL_METHODS.get(method.getName());
- // Check nullMethod != null first so that we don't call wasNull()
- // before a true getter method was invoked on the ResultSet.
- return nullMethod != null && this.resultSet.wasNull()
- ? nullMethod.invoke(this, (Object[]) null)
- : result;
- }
- /**
- * Sets the value to return when a SQL null is encountered as the result of
- * invoking a {@code getAsciiStream} method.
- *
- * @param nullAsciiStream the value
- */
- public void setNullAsciiStream(final InputStream nullAsciiStream) {
- this.nullAsciiStream = nullAsciiStream;
- }
- /**
- * Sets the value to return when a SQL null is encountered as the result of
- * invoking a {@code getBigDecimal} method.
- *
- * @param nullBigDecimal the value
- */
- public void setNullBigDecimal(final BigDecimal nullBigDecimal) {
- this.nullBigDecimal = nullBigDecimal;
- }
- /**
- * Sets the value to return when a SQL null is encountered as the result of
- * invoking a {@code getBinaryStream} method.
- *
- * @param nullBinaryStream the value
- */
- public void setNullBinaryStream(final InputStream nullBinaryStream) {
- this.nullBinaryStream = nullBinaryStream;
- }
- /**
- * Sets the value to return when a SQL null is encountered as the result of
- * invoking a {@code getBlob} method.
- *
- * @param nullBlob the value
- */
- public void setNullBlob(final Blob nullBlob) {
- this.nullBlob = nullBlob;
- }
- /**
- * Sets the value to return when a SQL null is encountered as the result of
- * invoking a {@code getBoolean} method.
- *
- * @param nullBoolean the value
- */
- public void setNullBoolean(final boolean nullBoolean) {
- this.nullBoolean = nullBoolean;
- }
- /**
- * Sets the value to return when a SQL null is encountered as the result of
- * invoking a {@code getByte} method.
- *
- * @param nullByte the value
- */
- public void setNullByte(final byte nullByte) {
- this.nullByte = nullByte;
- }
- /**
- * Sets the value to return when a SQL null is encountered as the result of
- * invoking a {@code getBytes} method.
- *
- * @param nullBytes the value
- */
- public void setNullBytes(final byte[] nullBytes) {
- if (nullBytes != null) {
- this.nullBytes = nullBytes.clone();
- } else {
- this.nullBytes = null;
- }
- }
- /**
- * Sets the value to return when a SQL null is encountered as the result of
- * invoking a {@code getCharacterStream} method.
- *
- * @param nullCharacterStream the value
- */
- public void setNullCharacterStream(final Reader nullCharacterStream) {
- this.nullCharacterStream = nullCharacterStream;
- }
- /**
- * Sets the value to return when a SQL null is encountered as the result of
- * invoking a {@code getClob} method.
- *
- * @param nullClob the value
- */
- public void setNullClob(final Clob nullClob) {
- this.nullClob = nullClob;
- }
- /**
- * Sets the value to return when a SQL null is encountered as the result of
- * invoking a {@code getDate} method.
- *
- * @param nullDate the value
- */
- public void setNullDate(final Date nullDate) {
- this.nullDate = nullDate != null ? new Date(nullDate.getTime()) : null;
- }
- /**
- * Sets the value to return when a SQL null is encountered as the result of
- * invoking a {@code getDouble} method.
- *
- * @param nullDouble the value
- */
- public void setNullDouble(final double nullDouble) {
- this.nullDouble = nullDouble;
- }
- /**
- * Sets the value to return when a SQL null is encountered as the result of
- * invoking a {@code getFloat} method.
- *
- * @param nullFloat the value
- */
- public void setNullFloat(final float nullFloat) {
- this.nullFloat = nullFloat;
- }
- /**
- * Sets the value to return when a SQL null is encountered as the result of
- * invoking a {@code getInt} method.
- *
- * @param nullInt the value
- */
- public void setNullInt(final int nullInt) {
- this.nullInt = nullInt;
- }
- /**
- * Sets the value to return when a SQL null is encountered as the result of
- * invoking a {@code getLong} method.
- *
- * @param nullLong the value
- */
- public void setNullLong(final long nullLong) {
- this.nullLong = nullLong;
- }
- /**
- * Sets the value to return when a SQL null is encountered as the result of
- * invoking a {@code getObject} method.
- *
- * @param nullObject the value
- */
- public void setNullObject(final Object nullObject) {
- this.nullObject = nullObject;
- }
- /**
- * Sets the value to return when a SQL null is encountered as the result of
- * invoking a {@code getRef} method.
- *
- * @param nullRef the value
- */
- public void setNullRef(final Ref nullRef) {
- this.nullRef = nullRef;
- }
- /**
- * Sets the value to return when a SQL null is encountered as the result of
- * invoking a {@code getShort} method.
- *
- * @param nullShort the value
- */
- public void setNullShort(final short nullShort) {
- this.nullShort = nullShort;
- }
- /**
- * Sets the value to return when a SQL null is encountered as the result of
- * invoking a {@code getString} method.
- *
- * @param nullString the value
- */
- public void setNullString(final String nullString) {
- this.nullString = nullString;
- }
- /**
- * Sets the value to return when a SQL null is encountered as the result of
- * invoking a {@code getTime} method.
- *
- * @param nullTime the value
- */
- public void setNullTime(final Time nullTime) {
- this.nullTime = nullTime != null ? new Time(nullTime.getTime()) : null;
- }
- /**
- * Sets the value to return when a SQL null is encountered as the result of
- * invoking a {@code getTimestamp} method.
- *
- * @param nullTimestamp the value
- */
- public void setNullTimestamp(final Timestamp nullTimestamp) {
- if (nullTimestamp != null) {
- this.nullTimestamp = new Timestamp(nullTimestamp.getTime());
- this.nullTimestamp.setNanos(nullTimestamp.getNanos());
- } else {
- this.nullTimestamp = null;
- }
- }
- /**
- * Sets the value to return when a SQL null is encountered as the result of
- * invoking a {@code getURL} method.
- *
- * @param nullURL the value
- */
- public void setNullURL(final URL nullURL) {
- this.nullURL = nullURL;
- }
- }