Java tutorial
/** * Copyright 2014 Nortal AS * * Licensed 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 com.nortal.petit.converter.util; import java.math.BigDecimal; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Timestamp; import java.util.Date; import java.util.HashMap; import java.util.Map; import org.springframework.jdbc.core.simple.ParameterizedRowMapper; import com.nortal.petit.converter.Converter; import com.nortal.petit.converter.ConverterFactory; import com.nortal.petit.converter.ConverterGroup; import com.nortal.petit.core.model.Id; /** * Helper class for correct reception of certain types of data from the * database. It can also wrap a ResultSet object. * * @author Aleksei Lissitsin <aleksei.lissitsin@webmedia.ee> */ // 11.02.2013 Lauri Ltteme - removed support for Day public class ResultSetHelper { public static String converterGroup = ConverterGroup.DEFAULT_GROUP; public static class ColumnPosition { private final boolean isNamed; private String name; private int index; // 1-based public ColumnPosition(String columnName) { isNamed = true; this.name = columnName; } public ColumnPosition(int index) { isNamed = false; this.index = index; } public String getName() { return name; } public int getIndex() { return index; } } public enum Type { LONG(new LongColumnRetrievalStrategy()), ID(new IdColumnRetrievalStrategy<Object>()), INTEGER( new IntegerColumnRetrievalStrategy()), STRING(new StringColumnRetrievalStrategy()), DATE( new DateColumnRetrievalStrategy()), TIMESTAMP( new TimestampColumnRetrievalStrategy()), BOOLEAN( new BooleanColumnRetrievalStrategy()), DOUBLE( new DoubleColumnRetrievalStrategy()), BIG_DECIMAL( new BigDecimalColumnRetrievalStrategy()); private ColumnRetrievalStrategy<?> columnRetrievalStrategy; private Type(ColumnRetrievalStrategy<?> columnRetrievalStrategy) { this.columnRetrievalStrategy = columnRetrievalStrategy; } ColumnRetrievalStrategy<?> getColumnRetrievalStrategy() { return columnRetrievalStrategy; } } protected static final Map<Class<?>, Type> CLASS_TO_TYPE = new HashMap<Class<?>, Type>(7); static { CLASS_TO_TYPE.put(Long.class, Type.LONG); CLASS_TO_TYPE.put(long.class, Type.LONG); CLASS_TO_TYPE.put(Id.class, Type.ID); CLASS_TO_TYPE.put(String.class, Type.STRING); CLASS_TO_TYPE.put(Date.class, Type.DATE); CLASS_TO_TYPE.put(Timestamp.class, Type.TIMESTAMP); CLASS_TO_TYPE.put(Boolean.class, Type.BOOLEAN); CLASS_TO_TYPE.put(boolean.class, Type.BOOLEAN); CLASS_TO_TYPE.put(Integer.class, Type.INTEGER); CLASS_TO_TYPE.put(BigDecimal.class, Type.BIG_DECIMAL); CLASS_TO_TYPE.put(Double.class, Type.DOUBLE); } private ResultSet rs; public ResultSetHelper(ResultSet rs) { this.rs = rs; } public static Long getLong(ResultSet rs, String column) throws SQLException { return getLong(rs, new ColumnPosition(column)); } public static Long getLong(ResultSet rs, ColumnPosition column) throws SQLException { BigDecimal bd = getBigDecimal(rs, column); return bd == null ? null : Long.valueOf(bd.longValue()); } public static Integer getInteger(ResultSet rs, ColumnPosition column) throws SQLException { BigDecimal bd = getBigDecimal(rs, column); return bd == null ? null : Integer.valueOf(bd.intValue()); } public static String getString(ResultSet rs, ColumnPosition column) throws SQLException { return column.isNamed ? rs.getString(column.getName()) : rs.getString(column.getIndex()); } public static Date getDate(ResultSet rs, ColumnPosition column) throws SQLException { Long milliseconds = getMilliseconds(rs, column); return milliseconds == null ? null : new Date(milliseconds); } public static Timestamp getTimestamp(ResultSet rs, ColumnPosition column) throws SQLException { Long milliseconds = getMilliseconds(rs, column); return milliseconds == null ? null : new Timestamp(milliseconds); } private static Long getMilliseconds(ResultSet rs, ColumnPosition column) throws SQLException { Timestamp timestamp = column.isNamed ? rs.getTimestamp(column.getName()) : rs.getTimestamp(column.getIndex()); return timestamp == null ? null : timestamp.getTime(); } public static Boolean getBoolean(ResultSet rs, ColumnPosition column) throws SQLException { String s = getString(rs, column); return s == null ? null : Boolean.valueOf("1".equals(s)); } public static Double getDouble(ResultSet rs, ColumnPosition column) throws SQLException { BigDecimal bd = getBigDecimal(rs, column); return bd == null ? null : Double.valueOf(bd.doubleValue()); } public static BigDecimal getBigDecimal(ResultSet rs, ColumnPosition column) throws SQLException { return column.isNamed ? rs.getBigDecimal(column.getName()) : rs.getBigDecimal(column.getIndex()); } public static Object get(Type type, ResultSet rs, String column) throws SQLException { try { ColumnRetrievalStrategy<?> strategy = type == null ? new NopColumnRetrievalStrategy() : type.getColumnRetrievalStrategy(); return strategy.getColumnValue(rs, column); } catch (SQLException e) { SQLException exception = new SQLException("Failed to get data from column " + column); e.setNextException(exception); throw e; } } /** * Queries resultSet for data of given class. Should be used mainly for * single object queries. Consider using {@link #get(Type, ResultSet, String)} for lists of data(e.g. in * RowMapper). Returns null if given class is not supported. */ public static Object getSimpleTyped(Class<?> clazz, ResultSet rs, String column) throws SQLException { return get(classToType(clazz), rs, column); } @SuppressWarnings("unchecked") public static <T> T get(Class<T> clazz, ResultSet rs, String column) throws SQLException { Converter<String, T> converter = ConverterFactory.getConverter(converterGroup, String.class, clazz); if (converter != null) { return converter.convert(rs.getString(column)); } return (T) getSimpleTyped(clazz, rs, column); } /** * Converts Class value to supported Type value which can be used for faster * access to methods. Returns null if given class is not supported. */ public static Type classToType(Class<?> clazz) { return CLASS_TO_TYPE.get(clazz); } /** * Converts Class value to supported Type value which can be used for faster * access to methods. Throws RuntimeException if given class is not * supported. */ public static Type convertToType(Class<?> clazz) { Type type = classToType(clazz); if (type == null) { throw new IllegalArgumentException("Field of type " + clazz + " not supported!"); } return type; } public Long getLong(String column) throws SQLException { return getLong(rs, new ColumnPosition(column)); } public Integer getInteger(String column) throws SQLException { return getInteger(rs, new ColumnPosition(column)); } public String getString(String column) throws SQLException { return getString(rs, new ColumnPosition(column)); } public Double getDouble(String column) throws SQLException { return getDouble(rs, new ColumnPosition(column)); } public Date getDate(String column) throws SQLException { return getDate(rs, new ColumnPosition(column)); } public Timestamp getTimestamp(String column) throws SQLException { return getTimestamp(rs, new ColumnPosition(column)); } public Boolean getBoolean(String column) throws SQLException { return getBoolean(rs, new ColumnPosition(column)); } public BigDecimal getBigDecimal(String column) throws SQLException { return getBigDecimal(rs, new ColumnPosition(column)); } public boolean next() throws SQLException { return rs.next(); } private static abstract class ColumnRetrievalStrategy<T> { abstract T getColumnValue(ResultSet rs, ColumnPosition columnPosition) throws SQLException; T getColumnValue(ResultSet rs, String columnName) throws SQLException { return getColumnValue(rs, new ColumnPosition(columnName)); } } public static class IdColumnRetrievalStrategy<T> extends ColumnRetrievalStrategy<Id<T>> { @Override public Id<T> getColumnValue(ResultSet rs, ColumnPosition column) throws SQLException { Long result = getLong(rs, column); return Id.create(result); } } private static class LongColumnRetrievalStrategy extends ColumnRetrievalStrategy<Long> { @Override public Long getColumnValue(ResultSet rs, ColumnPosition column) throws SQLException { return getLong(rs, column); } } private static class IntegerColumnRetrievalStrategy extends ColumnRetrievalStrategy<Integer> { @Override public Integer getColumnValue(ResultSet rs, ColumnPosition column) throws SQLException { return getInteger(rs, column); } } private static class StringColumnRetrievalStrategy extends ColumnRetrievalStrategy<String> { @Override public String getColumnValue(ResultSet rs, ColumnPosition column) throws SQLException { return getString(rs, column); } } private static class DateColumnRetrievalStrategy extends ColumnRetrievalStrategy<Date> { @Override public Date getColumnValue(ResultSet rs, ColumnPosition column) throws SQLException { return getDate(rs, column); } } private static class TimestampColumnRetrievalStrategy extends ColumnRetrievalStrategy<Timestamp> { @Override public Timestamp getColumnValue(ResultSet rs, ColumnPosition column) throws SQLException { return getTimestamp(rs, column); } } private static class BooleanColumnRetrievalStrategy extends ColumnRetrievalStrategy<Boolean> { @Override public Boolean getColumnValue(ResultSet rs, ColumnPosition column) throws SQLException { return getBoolean(rs, column); } } private static class DoubleColumnRetrievalStrategy extends ColumnRetrievalStrategy<Double> { @Override public Double getColumnValue(ResultSet rs, ColumnPosition column) throws SQLException { return getDouble(rs, column); } } private static class BigDecimalColumnRetrievalStrategy extends ColumnRetrievalStrategy<BigDecimal> { @Override public BigDecimal getColumnValue(ResultSet rs, ColumnPosition column) throws SQLException { return getBigDecimal(rs, column); } } private static class NopColumnRetrievalStrategy extends ColumnRetrievalStrategy<Object> { @Override public Object getColumnValue(ResultSet rs, ColumnPosition column) throws SQLException { return null; } } public static <T> ParameterizedRowMapper<T> createSingleRowMapperFromStrategy( final ColumnRetrievalStrategy<T> strategy) { return new ParameterizedRowMapper<T>() { @Override public T mapRow(ResultSet rs, int rowNum) throws SQLException { return strategy.getColumnValue(rs, new ColumnPosition(1)); } }; } }