Major refactor, more tests
This commit is contained in:
parent
e7639d740c
commit
efd1d44808
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* $Header:$
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.moparisthebest.jdbc;
|
||||||
|
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.ResultSetMetaData;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.Calendar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract base class for all row mappers.
|
||||||
|
*
|
||||||
|
* RowMappers are used to map the contents of a row in a ResultSet to the return type of an annotated method.
|
||||||
|
* Supported RowMapper types include: HashMap, Map, Object, XmlObject. When a ResultSetMapper is ready to
|
||||||
|
* map a ResultSet row to an object, it requests a RowMapper for the return type of the method from the
|
||||||
|
* RowMapperFactory.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class AbstractRowMapper<K, T> implements RowMapper<K,T> {
|
||||||
|
|
||||||
|
/** ResultSet to map. */
|
||||||
|
protected final ResultSet _resultSet;
|
||||||
|
|
||||||
|
/** Calendar instance for date/time mappings. */
|
||||||
|
protected final Calendar _cal;
|
||||||
|
|
||||||
|
/** Class to map ResultSet Rows to. */
|
||||||
|
protected final Class<T> _returnTypeClass;
|
||||||
|
|
||||||
|
protected final Class<K> _mapKeyType;
|
||||||
|
|
||||||
|
protected final int _columnCount;
|
||||||
|
|
||||||
|
protected final boolean mapOnlySecondColumn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new RowMapper for the specified ResultSet and return type Class.
|
||||||
|
* @param resultSet ResultSet to map
|
||||||
|
* @param returnTypeClass Class to map ResultSet rows to.
|
||||||
|
* @param cal Calendar instance for date/time values.
|
||||||
|
*/
|
||||||
|
protected AbstractRowMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<K> mapKeyType) {
|
||||||
|
_resultSet = resultSet;
|
||||||
|
_returnTypeClass = returnTypeClass;
|
||||||
|
_cal = cal;
|
||||||
|
_mapKeyType = mapKeyType;
|
||||||
|
|
||||||
|
try {
|
||||||
|
_columnCount = resultSet.getMetaData().getColumnCount();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new MapperException("RowToObjectMapper: SQLException: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
mapOnlySecondColumn = _mapKeyType != null && _columnCount == 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AbstractRowMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal) {
|
||||||
|
this(resultSet, returnTypeClass, cal, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a String array of column names from the ResultSet.
|
||||||
|
* @return A String array containing the column names contained within the ResultSet.
|
||||||
|
* @throws java.sql.SQLException on error
|
||||||
|
*/
|
||||||
|
protected String[] getKeysFromResultSet() throws SQLException {
|
||||||
|
|
||||||
|
String[] keys;
|
||||||
|
final ResultSetMetaData md = _resultSet.getMetaData();
|
||||||
|
|
||||||
|
keys = new String[_columnCount + 1];
|
||||||
|
for (int i = 1; i <= _columnCount; i++) {
|
||||||
|
keys[i] = md.getColumnName(i).toUpperCase();
|
||||||
|
}
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
}
|
@ -132,7 +132,7 @@ public class CachingResultSetMapper extends ResultSetMapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected <K, T> RowToObjectMapper<K, T> getRowMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType, Class<K> mapKeyType) {
|
public <K, T> RowMapper<K, T> getRowMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType, Class<K> mapKeyType) {
|
||||||
return new CachingRowToObjectMapper<K, T>(cache, resultSet, returnTypeClass, cal, mapValType, mapKeyType);
|
return new CachingRowToObjectMapper<K, T>(cache, resultSet, returnTypeClass, cal, mapValType, mapKeyType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ public class CaseInsensitiveMapResultSetMapper extends ResultSetMapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected <K, T> RowToObjectMapper<K, T> getRowMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType, Class<K> mapKeyType) {
|
public <K, T> RowMapper<K, T> getRowMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType, Class<K> mapKeyType) {
|
||||||
return new CaseInsensitiveMapRowToObjectMapper<K, T>(resultSet, returnTypeClass, cal, mapValType, mapKeyType);
|
return new RowToObjectMapper<K, T>(resultSet, returnTypeClass, cal, mapValType, mapKeyType, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
package com.moparisthebest.jdbc;
|
|
||||||
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by mopar on 5/15/14.
|
|
||||||
*/
|
|
||||||
public class CaseInsensitiveMapRowToObjectMapper<K, T> extends RowToObjectMapper<K, T> {
|
|
||||||
public CaseInsensitiveMapRowToObjectMapper(ResultSet resultSet, Class<T> returnTypeClass) {
|
|
||||||
super(resultSet, returnTypeClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CaseInsensitiveMapRowToObjectMapper(ResultSet resultSet, Class<T> returnTypeClass, Class<?> mapValType) {
|
|
||||||
super(resultSet, returnTypeClass, mapValType);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CaseInsensitiveMapRowToObjectMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal) {
|
|
||||||
super(resultSet, returnTypeClass, cal);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CaseInsensitiveMapRowToObjectMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType) {
|
|
||||||
super(resultSet, returnTypeClass, cal, mapValType);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CaseInsensitiveMapRowToObjectMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType, Class<K> mapKeyType) {
|
|
||||||
super(resultSet, returnTypeClass, cal, mapValType, mapKeyType);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Map<String, Object> getMapImplementation() throws IllegalAccessException, InstantiationException {
|
|
||||||
if(HashMap.class.equals(_returnTypeClass))
|
|
||||||
return new HashMap<String, Object>(){
|
|
||||||
@Override
|
|
||||||
public Object get(Object key) {
|
|
||||||
return super.get(key instanceof String ? ((String)key).toLowerCase() : key);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean containsKey(Object key) {
|
|
||||||
return super.containsKey(key instanceof String ? ((String)key).toLowerCase() : key);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return super.getMapImplementation();
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,68 @@
|
|||||||
|
package com.moparisthebest.jdbc;
|
||||||
|
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by mopar on 5/18/17.
|
||||||
|
*/
|
||||||
|
public class CleaningCachingResultSetMapper<E> extends CachingResultSetMapper {
|
||||||
|
|
||||||
|
private final Cleaner<E> cleaner;
|
||||||
|
|
||||||
|
public CleaningCachingResultSetMapper(final Cleaner<E> cleaner, final Calendar cal, final int arrayMaxLength, final int maxEntries) {
|
||||||
|
super(cal, arrayMaxLength, maxEntries);
|
||||||
|
this.cleaner = cleaner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CleaningCachingResultSetMapper(final Cleaner<E> cleaner, final Calendar cal, final int arrayMaxLength) {
|
||||||
|
super(cal, arrayMaxLength);
|
||||||
|
this.cleaner = cleaner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CleaningCachingResultSetMapper(final Cleaner<E> cleaner, final int arrayMaxLength) {
|
||||||
|
super(arrayMaxLength);
|
||||||
|
this.cleaner = cleaner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CleaningCachingResultSetMapper(final Cleaner<E> cleaner) {
|
||||||
|
this.cleaner = cleaner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CleaningCachingResultSetMapper(final Cleaner<E> cleaner, final Calendar cal, final int arrayMaxLength, final Map<CachingRowToObjectMapper.ResultSetKey, CachingRowToObjectMapper.FieldMapping<?>> cache) {
|
||||||
|
super(cal, arrayMaxLength, cache);
|
||||||
|
this.cleaner = cleaner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CleaningCachingResultSetMapper(final Cleaner<E> cleaner, final int arrayMaxLength, final Map<CachingRowToObjectMapper.ResultSetKey, CachingRowToObjectMapper.FieldMapping<?>> cache) {
|
||||||
|
super(arrayMaxLength, cache);
|
||||||
|
this.cleaner = cleaner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CleaningCachingResultSetMapper(final Cleaner<E> cleaner, final Map<CachingRowToObjectMapper.ResultSetKey, CachingRowToObjectMapper.FieldMapping<?>> cache) {
|
||||||
|
super(cache);
|
||||||
|
this.cleaner = cleaner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CleaningCachingResultSetMapper(final Cleaner<E> cleaner, final Calendar cal, final int arrayMaxLength, final boolean threadSafe) {
|
||||||
|
super(cal, arrayMaxLength, threadSafe);
|
||||||
|
this.cleaner = cleaner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CleaningCachingResultSetMapper(final Cleaner<E> cleaner, final int arrayMaxLength, final boolean threadSafe) {
|
||||||
|
super(arrayMaxLength, threadSafe);
|
||||||
|
this.cleaner = cleaner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CleaningCachingResultSetMapper(final Cleaner<E> cleaner, final boolean threadSafe) {
|
||||||
|
super(threadSafe);
|
||||||
|
this.cleaner = cleaner;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings({"unchecked"})
|
||||||
|
public <K, T> RowMapper<K, T> getRowMapper(final ResultSet resultSet, final Class<T> returnTypeClass, final Calendar cal, final Class<?> mapValType, final Class<K> mapKeyType) {
|
||||||
|
return new CleaningRowToObjectMapper((Cleaner<T>)cleaner, super.getRowMapper(resultSet, returnTypeClass, cal, mapValType, mapKeyType));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
package com.moparisthebest.jdbc;
|
||||||
|
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by mopar on 5/18/17.
|
||||||
|
*/
|
||||||
|
public class CleaningCompilingResultSetMapper<E> extends CompilingResultSetMapper {
|
||||||
|
|
||||||
|
private final Cleaner<E> cleaner;
|
||||||
|
|
||||||
|
public CleaningCompilingResultSetMapper(final Cleaner<E> cleaner, final Calendar cal, final int arrayMaxLength, final int maxEntries) {
|
||||||
|
super(cal, arrayMaxLength, maxEntries);
|
||||||
|
this.cleaner = cleaner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CleaningCompilingResultSetMapper(final Cleaner<E> cleaner, final Calendar cal, final int arrayMaxLength) {
|
||||||
|
super(cal, arrayMaxLength);
|
||||||
|
this.cleaner = cleaner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CleaningCompilingResultSetMapper(final Cleaner<E> cleaner, final int arrayMaxLength) {
|
||||||
|
super(arrayMaxLength);
|
||||||
|
this.cleaner = cleaner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CleaningCompilingResultSetMapper(final Cleaner<E> cleaner) {
|
||||||
|
this.cleaner = cleaner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CleaningCompilingResultSetMapper(final Cleaner<E> cleaner, final Calendar cal, final int arrayMaxLength, final Map<CachingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?, ?>> cache) {
|
||||||
|
super(cal, arrayMaxLength, cache);
|
||||||
|
this.cleaner = cleaner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CleaningCompilingResultSetMapper(final Cleaner<E> cleaner, final int arrayMaxLength, final Map<CachingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?, ?>> cache) {
|
||||||
|
super(arrayMaxLength, cache);
|
||||||
|
this.cleaner = cleaner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CleaningCompilingResultSetMapper(final Cleaner<E> cleaner, final Map<CachingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?, ?>> cache) {
|
||||||
|
super(cache);
|
||||||
|
this.cleaner = cleaner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CleaningCompilingResultSetMapper(final Cleaner<E> cleaner, final Calendar cal, final int arrayMaxLength, final boolean threadSafe) {
|
||||||
|
super(cal, arrayMaxLength, threadSafe);
|
||||||
|
this.cleaner = cleaner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CleaningCompilingResultSetMapper(final Cleaner<E> cleaner, final int arrayMaxLength, final boolean threadSafe) {
|
||||||
|
super(arrayMaxLength, threadSafe);
|
||||||
|
this.cleaner = cleaner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CleaningCompilingResultSetMapper(final Cleaner<E> cleaner, final boolean threadSafe) {
|
||||||
|
super(threadSafe);
|
||||||
|
this.cleaner = cleaner;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings({"unchecked"})
|
||||||
|
public <K, T> RowMapper<K, T> getRowMapper(final ResultSet resultSet, final Class<T> returnTypeClass, final Calendar cal, final Class<?> mapValType, final Class<K> mapKeyType) {
|
||||||
|
return new CleaningRowToObjectMapper((Cleaner<T>)cleaner, super.getRowMapper(resultSet, returnTypeClass, cal, mapValType, mapKeyType));
|
||||||
|
}
|
||||||
|
}
|
@ -19,7 +19,7 @@ public class CleaningResultSetMapper<E> extends ResultSetMapper {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings({"unchecked"})
|
@SuppressWarnings({"unchecked"})
|
||||||
protected <K, T> RowToObjectMapper<K, T> getRowMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType, Class<K> mapKeyType) {
|
public <K, T> RowMapper<K, T> getRowMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType, Class<K> mapKeyType) {
|
||||||
return new CleaningRowToObjectMapper<K, T>((Cleaner<T>)cleaner, resultSet, returnTypeClass, cal, mapValType, mapKeyType);
|
return new CleaningRowToObjectMapper<K, T>((Cleaner<T>)cleaner, resultSet, returnTypeClass, cal, mapValType, mapKeyType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,19 +4,27 @@ import java.sql.ResultSet;
|
|||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
|
||||||
public class CleaningRowToObjectMapper<K, T> extends RowToObjectMapper<K, T> {
|
public class CleaningRowToObjectMapper<K, T> implements RowMapper<K, T> {
|
||||||
|
|
||||||
private final Cleaner<T> cleaner;
|
private final Cleaner<T> cleaner;
|
||||||
|
private final RowMapper<K,T> delegate;
|
||||||
|
|
||||||
public CleaningRowToObjectMapper(Cleaner<T> cleaner, ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType, Class<K> mapKeyType) {
|
public CleaningRowToObjectMapper(Cleaner<T> cleaner, ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType, Class<K> mapKeyType) {
|
||||||
super(resultSet, returnTypeClass, cal, mapValType, mapKeyType);
|
this(cleaner, new RowToObjectMapper<K, T>(resultSet, returnTypeClass, cal, mapValType, mapKeyType));
|
||||||
if (cleaner == null)
|
}
|
||||||
throw new NullPointerException("cleaner cannot be null!");
|
|
||||||
|
public CleaningRowToObjectMapper(final Cleaner<T> cleaner, final RowMapper<K,T> delegate) {
|
||||||
this.cleaner = cleaner;
|
this.cleaner = cleaner;
|
||||||
|
this.delegate = delegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T mapRowToReturnType() throws SQLException {
|
public T mapRowToReturnType() throws SQLException {
|
||||||
return cleaner.clean(super.mapRowToReturnType());
|
return cleaner.clean(delegate.mapRowToReturnType());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public K getMapKey() throws SQLException {
|
||||||
|
return delegate.getMapKey();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -144,7 +144,7 @@ public class CompilingResultSetMapper extends ResultSetMapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected <K, T> RowToObjectMapper<K, T> getRowMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType, Class<K> mapKeyType) {
|
public <K, T> RowMapper<K, T> getRowMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType, Class<K> mapKeyType) {
|
||||||
return new CompilingRowToObjectMapper<K, T>(compiler, cache, resultSet, returnTypeClass, cal, mapValType, mapKeyType);
|
return new CompilingRowToObjectMapper<K, T>(compiler, cache, resultSet, returnTypeClass, cal, mapValType, mapKeyType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,13 +21,10 @@ import java.util.Map;
|
|||||||
* Usage differences:
|
* Usage differences:
|
||||||
* 1. Reflection can set non-public or final fields directly, direct java code cannot, so DTOs like that will result in
|
* 1. Reflection can set non-public or final fields directly, direct java code cannot, so DTOs like that will result in
|
||||||
* a compilation and therefore mapping error.
|
* a compilation and therefore mapping error.
|
||||||
* <p>
|
*/
|
||||||
* Subclass differences:
|
|
||||||
* 1. Normally a subclass of RowToObjectMapper can overload the getMapImplementation() method to change some behavior,
|
|
||||||
* @see CaseInsensitiveMapRowToObjectMapper , but that method is never called with this implementation.
|
|
||||||
*/
|
|
||||||
public class CompilingRowToObjectMapper<K, T> extends RowToObjectMapper<K, T> {
|
public class CompilingRowToObjectMapper<K, T> extends RowToObjectMapper<K, T> {
|
||||||
|
|
||||||
|
// do not remove, used from generated classes
|
||||||
public static final String firstColumnError = "Cannot call getFirstColumn when mapKeyType is null!";
|
public static final String firstColumnError = "Cannot call getFirstColumn when mapKeyType is null!";
|
||||||
|
|
||||||
protected final Compiler compiler;
|
protected final Compiler compiler;
|
||||||
@ -36,7 +33,11 @@ public class CompilingRowToObjectMapper<K, T> extends RowToObjectMapper<K, T> {
|
|||||||
protected String[] keys = null; // for caching if we must generate class
|
protected String[] keys = null; // for caching if we must generate class
|
||||||
|
|
||||||
public CompilingRowToObjectMapper(final Compiler compiler, final Map<CachingRowToObjectMapper.ResultSetKey, ResultSetToObject<?,?>> cache, ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType, Class<K> mapKeyType) {
|
public CompilingRowToObjectMapper(final Compiler compiler, final Map<CachingRowToObjectMapper.ResultSetKey, ResultSetToObject<?,?>> cache, ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType, Class<K> mapKeyType) {
|
||||||
super(resultSet, returnTypeClass, cal, mapValType, mapKeyType);
|
this(compiler, cache, resultSet, returnTypeClass, cal, mapValType, mapKeyType, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompilingRowToObjectMapper(final Compiler compiler, final Map<CachingRowToObjectMapper.ResultSetKey, ResultSetToObject<?,?>> cache, ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType, Class<K> mapKeyType, final boolean caseInsensitiveMap) {
|
||||||
|
super(resultSet, returnTypeClass, cal, mapValType, mapKeyType, caseInsensitiveMap);
|
||||||
this.compiler = compiler;
|
this.compiler = compiler;
|
||||||
try {
|
try {
|
||||||
final CachingRowToObjectMapper.ResultSetKey keys = new CachingRowToObjectMapper.ResultSetKey(super.getKeysFromResultSet(), _returnTypeClass, _mapKeyType);
|
final CachingRowToObjectMapper.ResultSetKey keys = new CachingRowToObjectMapper.ResultSetKey(super.getKeysFromResultSet(), _returnTypeClass, _mapKeyType);
|
||||||
@ -172,7 +173,7 @@ public class CompilingRowToObjectMapper<K, T> extends RowToObjectMapper<K, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
java.append(footer);
|
java.append(footer);
|
||||||
System.out.println(java);
|
//System.out.println(java);
|
||||||
return compiler.compile(className, java);
|
return compiler.compile(className, java);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ import java.util.concurrent.*;
|
|||||||
*
|
*
|
||||||
* @author Travis Burtrum (modifications from beehive)
|
* @author Travis Burtrum (modifications from beehive)
|
||||||
*/
|
*/
|
||||||
public class ResultSetMapper {
|
public class ResultSetMapper implements RowMapperProvider {
|
||||||
|
|
||||||
public static final Map<Class, Class> interfaceToConcrete = Collections.unmodifiableMap(new HashMap<Class, Class>() {{
|
public static final Map<Class, Class> interfaceToConcrete = Collections.unmodifiableMap(new HashMap<Class, Class>() {{
|
||||||
// Collection's
|
// Collection's
|
||||||
@ -151,7 +151,7 @@ public class ResultSetMapper {
|
|||||||
// a value of less than 1 indicates that all rows from the ResultSet should be included.
|
// a value of less than 1 indicates that all rows from the ResultSet should be included.
|
||||||
final boolean unlimitedRows = arrayMaxLength < 1;
|
final boolean unlimitedRows = arrayMaxLength < 1;
|
||||||
|
|
||||||
final RowToObjectMapper<?, E> rowMapper = getRowMapper(rs, componentType, cal, mapValType, null);
|
final RowMapper<?, E> rowMapper = getRowMapper(rs, componentType, cal, mapValType, null);
|
||||||
|
|
||||||
for (; (unlimitedRows || numRows != arrayMaxLength) && rs.next(); ++numRows) {
|
for (; (unlimitedRows || numRows != arrayMaxLength) && rs.next(); ++numRows) {
|
||||||
E object = rowMapper.mapRowToReturnType();
|
E object = rowMapper.mapRowToReturnType();
|
||||||
@ -230,7 +230,7 @@ public class ResultSetMapper {
|
|||||||
// a value of less than 1 indicates that all rows from the ResultSet should be included.
|
// a value of less than 1 indicates that all rows from the ResultSet should be included.
|
||||||
final boolean unlimitedRows = arrayMaxLength < 1;
|
final boolean unlimitedRows = arrayMaxLength < 1;
|
||||||
|
|
||||||
final RowToObjectMapper<K, E> rowMapper = getRowMapper(rs, componentType, cal, mapValType, mapKeyType);
|
final RowMapper<K, E> rowMapper = getRowMapper(rs, componentType, cal, mapValType, mapKeyType);
|
||||||
|
|
||||||
for (; (unlimitedRows || numRows != arrayMaxLength) && rs.next(); ++numRows) {
|
for (; (unlimitedRows || numRows != arrayMaxLength) && rs.next(); ++numRows) {
|
||||||
K key = rowMapper.getMapKey();
|
K key = rowMapper.getMapKey();
|
||||||
@ -311,7 +311,7 @@ public class ResultSetMapper {
|
|||||||
// a value of less than 1 indicates that all rows from the ResultSet should be included.
|
// a value of less than 1 indicates that all rows from the ResultSet should be included.
|
||||||
final boolean unlimitedRows = arrayMaxLength < 1;
|
final boolean unlimitedRows = arrayMaxLength < 1;
|
||||||
|
|
||||||
final RowToObjectMapper<K, C> rowMapper = getRowMapper(rs, componentType, cal, mapValType, mapKeyType);
|
final RowMapper<K, C> rowMapper = getRowMapper(rs, componentType, cal, mapValType, mapKeyType);
|
||||||
|
|
||||||
for (; (unlimitedRows || numRows != arrayMaxLength) && rs.next(); ++numRows) {
|
for (; (unlimitedRows || numRows != arrayMaxLength) && rs.next(); ++numRows) {
|
||||||
K key = rowMapper.getMapKey();
|
K key = rowMapper.getMapKey();
|
||||||
@ -404,7 +404,7 @@ public class ResultSetMapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// fairly un-interesting methods below here
|
// fairly un-interesting methods below here
|
||||||
protected <K, T> RowToObjectMapper<K, T> getRowMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType, Class<K> mapKeyType) {
|
public <K, T> RowMapper<K, T> getRowMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType, Class<K> mapKeyType) {
|
||||||
return new RowToObjectMapper<K, T>(resultSet, returnTypeClass, cal, mapValType, mapKeyType);
|
return new RowToObjectMapper<K, T>(resultSet, returnTypeClass, cal, mapValType, mapKeyType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,264 +1,21 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* $Header:$
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.moparisthebest.jdbc;
|
package com.moparisthebest.jdbc;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.ResultSetMetaData;
|
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract base class for all row mappers.
|
* Created by mopar on 5/18/17.
|
||||||
*
|
|
||||||
* RowMappers are used to map the contents of a row in a ResultSet to the return type of an annotated method.
|
|
||||||
* Supported RowMapper types include: HashMap, Map, Object, XmlObject. When a ResultSetMapper is ready to
|
|
||||||
* map a ResultSet row to an object, it requests a RowMapper for the return type of the method from the
|
|
||||||
* RowMapperFactory.
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public abstract class RowMapper<K, T> {
|
public interface RowMapper<K,T> {
|
||||||
|
/**
|
||||||
|
* Map a ResultSet row to the return type class
|
||||||
|
* @return An instance of class, if _mapKeyType is not null and _columnCount is 2, return only index 2
|
||||||
|
*/
|
||||||
|
T mapRowToReturnType() throws SQLException;
|
||||||
|
|
||||||
private static final String SETTER_NAME_REGEX = "^(set)([A-Z_]\\w*+)";
|
/**
|
||||||
protected static final TypeMappingsFactory _tmf = TypeMappingsFactory.getInstance();
|
* key for map
|
||||||
protected static final Pattern _setterRegex = Pattern.compile(SETTER_NAME_REGEX);
|
* @return index number 1, with type of _mapKeyType
|
||||||
|
* @throws MapperException if _mapKeyType is null
|
||||||
/** ResultSet to map. */
|
*/
|
||||||
protected final ResultSet _resultSet;
|
K getMapKey() throws SQLException;
|
||||||
|
|
||||||
/** Calendar instance for date/time mappings. */
|
|
||||||
protected final Calendar _cal;
|
|
||||||
|
|
||||||
/** Class to map ResultSet Rows to. */
|
|
||||||
protected final Class<T> _returnTypeClass;
|
|
||||||
|
|
||||||
protected final Class<K> _mapKeyType;
|
|
||||||
|
|
||||||
protected final int _columnCount;
|
|
||||||
|
|
||||||
protected final boolean mapOnlySecondColumn;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new RowMapper for the specified ResultSet and return type Class.
|
|
||||||
* @param resultSet ResultSet to map
|
|
||||||
* @param returnTypeClass Class to map ResultSet rows to.
|
|
||||||
* @param cal Calendar instance for date/time values.
|
|
||||||
*/
|
|
||||||
protected RowMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<K> mapKeyType) {
|
|
||||||
_resultSet = resultSet;
|
|
||||||
_returnTypeClass = returnTypeClass;
|
|
||||||
_cal = cal;
|
|
||||||
_mapKeyType = mapKeyType;
|
|
||||||
|
|
||||||
try {
|
|
||||||
_columnCount = resultSet.getMetaData().getColumnCount();
|
|
||||||
} catch (SQLException e) {
|
|
||||||
throw new MapperException("RowToObjectMapper: SQLException: " + e.getMessage(), e);
|
|
||||||
}
|
|
||||||
|
|
||||||
mapOnlySecondColumn = _mapKeyType != null && _columnCount == 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected RowMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal) {
|
|
||||||
this(resultSet, returnTypeClass, cal, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Map a ResultSet row to the return type class
|
|
||||||
* @return An instance of class, if _mapKeyType is not null and _columnCount is 2, return only index 2
|
|
||||||
*/
|
|
||||||
public abstract T mapRowToReturnType() throws SQLException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* key for map
|
|
||||||
* @return index number 1, with type of _mapKeyType
|
|
||||||
* @throws MapperException if _mapKeyType is null
|
|
||||||
*/
|
|
||||||
public abstract K getMapKey() throws SQLException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Build a String array of column names from the ResultSet.
|
|
||||||
* @return A String array containing the column names contained within the ResultSet.
|
|
||||||
* @throws java.sql.SQLException on error
|
|
||||||
*/
|
|
||||||
protected String[] getKeysFromResultSet() throws SQLException {
|
|
||||||
|
|
||||||
String[] keys;
|
|
||||||
final ResultSetMetaData md = _resultSet.getMetaData();
|
|
||||||
|
|
||||||
keys = new String[_columnCount + 1];
|
|
||||||
for (int i = 1; i <= _columnCount; i++) {
|
|
||||||
keys[i] = md.getColumnName(i).toUpperCase();
|
|
||||||
}
|
|
||||||
return keys;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine if the given method is a java bean setter method.
|
|
||||||
* @param method Method to check
|
|
||||||
* @return True if the method is a setter method.
|
|
||||||
*/
|
|
||||||
protected boolean isSetterMethod(Method method) {
|
|
||||||
Matcher matcher = _setterRegex.matcher(method.getName());
|
|
||||||
if (matcher.matches()) {
|
|
||||||
|
|
||||||
if (Modifier.isStatic(method.getModifiers())) return false;
|
|
||||||
if (!Modifier.isPublic(method.getModifiers())) return false;
|
|
||||||
if (!Void.TYPE.equals(method.getReturnType())) return false;
|
|
||||||
|
|
||||||
// method parameter checks
|
|
||||||
Class[] params = method.getParameterTypes();
|
|
||||||
if (params.length != 1) return false;
|
|
||||||
if (TypeMappingsFactory.TYPE_UNKNOWN == _tmf.getTypeId(params[0])) return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extract a column value from the ResultSet and return it as resultType.
|
|
||||||
*
|
|
||||||
* @param index The column index of the value to extract from the ResultSet.
|
|
||||||
* @param resultType The return type. Defined in TypeMappingsFactory.
|
|
||||||
* @return The extracted value
|
|
||||||
* @throws java.sql.SQLException on error.
|
|
||||||
*/
|
|
||||||
protected Object extractColumnValue(int index, int resultType) throws SQLException {
|
|
||||||
|
|
||||||
switch (resultType) {
|
|
||||||
case TypeMappingsFactory.TYPE_INT:
|
|
||||||
return new Integer(_resultSet.getInt(index));
|
|
||||||
case TypeMappingsFactory.TYPE_LONG:
|
|
||||||
return new Long(_resultSet.getLong(index));
|
|
||||||
case TypeMappingsFactory.TYPE_FLOAT:
|
|
||||||
return new Float(_resultSet.getFloat(index));
|
|
||||||
case TypeMappingsFactory.TYPE_DOUBLE:
|
|
||||||
return new Double(_resultSet.getDouble(index));
|
|
||||||
case TypeMappingsFactory.TYPE_BYTE:
|
|
||||||
return new Byte(_resultSet.getByte(index));
|
|
||||||
case TypeMappingsFactory.TYPE_SHORT:
|
|
||||||
return new Short(_resultSet.getShort(index));
|
|
||||||
case TypeMappingsFactory.TYPE_BOOLEAN:
|
|
||||||
return _resultSet.getBoolean(index) ? Boolean.TRUE : Boolean.FALSE;
|
|
||||||
case TypeMappingsFactory.TYPE_INT_OBJ:
|
|
||||||
{
|
|
||||||
int i = _resultSet.getInt(index);
|
|
||||||
return _resultSet.wasNull() ? null : new Integer(i);
|
|
||||||
}
|
|
||||||
case TypeMappingsFactory.TYPE_LONG_OBJ:
|
|
||||||
{
|
|
||||||
long i = _resultSet.getLong(index);
|
|
||||||
return _resultSet.wasNull() ? null : new Long(i);
|
|
||||||
}
|
|
||||||
case TypeMappingsFactory.TYPE_FLOAT_OBJ:
|
|
||||||
{
|
|
||||||
float i = _resultSet.getFloat(index);
|
|
||||||
return _resultSet.wasNull() ? null : new Float(i);
|
|
||||||
}
|
|
||||||
case TypeMappingsFactory.TYPE_DOUBLE_OBJ:
|
|
||||||
{
|
|
||||||
double i = _resultSet.getDouble(index);
|
|
||||||
return _resultSet.wasNull() ? null : new Double(i);
|
|
||||||
}
|
|
||||||
case TypeMappingsFactory.TYPE_BYTE_OBJ:
|
|
||||||
{
|
|
||||||
byte i = _resultSet.getByte(index);
|
|
||||||
return _resultSet.wasNull() ? null : new Byte(i);
|
|
||||||
}
|
|
||||||
case TypeMappingsFactory.TYPE_SHORT_OBJ:
|
|
||||||
{
|
|
||||||
short i = _resultSet.getShort(index);
|
|
||||||
return _resultSet.wasNull() ? null : new Short(i);
|
|
||||||
}
|
|
||||||
case TypeMappingsFactory.TYPE_BOOLEAN_OBJ:
|
|
||||||
{
|
|
||||||
boolean i = _resultSet.getBoolean(index);
|
|
||||||
return _resultSet.wasNull() ? null : (i ? Boolean.TRUE : Boolean.FALSE);
|
|
||||||
}
|
|
||||||
case TypeMappingsFactory.TYPE_STRING:
|
|
||||||
case TypeMappingsFactory.TYPE_XMLBEAN_ENUM:
|
|
||||||
return _resultSet.getString(index);
|
|
||||||
case TypeMappingsFactory.TYPE_BIG_DECIMAL:
|
|
||||||
return _resultSet.getBigDecimal(index);
|
|
||||||
case TypeMappingsFactory.TYPE_BYTES:
|
|
||||||
return _resultSet.getBytes(index);
|
|
||||||
case TypeMappingsFactory.TYPE_TIMESTAMP:
|
|
||||||
{
|
|
||||||
if (null == _cal)
|
|
||||||
return _resultSet.getTimestamp(index);
|
|
||||||
else
|
|
||||||
return _resultSet.getTimestamp(index, _cal);
|
|
||||||
}
|
|
||||||
case TypeMappingsFactory.TYPE_TIME:
|
|
||||||
{
|
|
||||||
if (null == _cal)
|
|
||||||
return _resultSet.getTime(index);
|
|
||||||
else
|
|
||||||
return _resultSet.getTime(index, _cal);
|
|
||||||
}
|
|
||||||
case TypeMappingsFactory.TYPE_SQLDATE:
|
|
||||||
{
|
|
||||||
if (null == _cal)
|
|
||||||
return _resultSet.getDate(index);
|
|
||||||
else
|
|
||||||
return _resultSet.getDate(index, _cal);
|
|
||||||
}
|
|
||||||
case TypeMappingsFactory.TYPE_DATE:
|
|
||||||
{
|
|
||||||
// convert explicity to java.util.Date
|
|
||||||
// 12918 | knex does not return java.sql.Date properly from web service
|
|
||||||
java.sql.Timestamp ts = (null == _cal) ? _resultSet.getTimestamp(index) : _resultSet.getTimestamp(index, _cal);
|
|
||||||
if (null == ts)
|
|
||||||
return null;
|
|
||||||
return new java.util.Date(ts.getTime());
|
|
||||||
}
|
|
||||||
case TypeMappingsFactory.TYPE_CALENDAR:
|
|
||||||
{
|
|
||||||
java.sql.Timestamp ts = (null == _cal) ? _resultSet.getTimestamp(index) : _resultSet.getTimestamp(index, _cal);
|
|
||||||
if (null == ts)
|
|
||||||
return null;
|
|
||||||
Calendar c = (null == _cal) ? Calendar.getInstance() : (Calendar) _cal.clone();
|
|
||||||
c.setTimeInMillis(ts.getTime());
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
case TypeMappingsFactory.TYPE_REF:
|
|
||||||
return _resultSet.getRef(index);
|
|
||||||
case TypeMappingsFactory.TYPE_BLOB:
|
|
||||||
return _resultSet.getBlob(index);
|
|
||||||
case TypeMappingsFactory.TYPE_CLOB:
|
|
||||||
return _resultSet.getClob(index);
|
|
||||||
case TypeMappingsFactory.TYPE_ARRAY:
|
|
||||||
return _resultSet.getArray(index);
|
|
||||||
case TypeMappingsFactory.TYPE_READER:
|
|
||||||
case TypeMappingsFactory.TYPE_STREAM:
|
|
||||||
throw new MapperException("streaming return types are not supported by the JdbcControl; use ResultSet instead");
|
|
||||||
case TypeMappingsFactory.TYPE_STRUCT:
|
|
||||||
case TypeMappingsFactory.TYPE_UNKNOWN:
|
|
||||||
// JAVA_TYPE (could be any), or REF
|
|
||||||
return _resultSet.getObject(index);
|
|
||||||
default:
|
|
||||||
throw new MapperException("internal error: unknown type ID: " + Integer.toString(resultType));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
package com.moparisthebest.jdbc;
|
||||||
|
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.util.Calendar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by mopar on 5/18/17.
|
||||||
|
*/
|
||||||
|
public interface RowMapperProvider {
|
||||||
|
<K, T> RowMapper<K, T> getRowMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType, Class<K> mapKeyType);
|
||||||
|
}
|
@ -19,6 +19,8 @@ package com.moparisthebest.jdbc;
|
|||||||
* $Header:$
|
* $Header:$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import com.moparisthebest.jdbc.util.CaseInsensitiveHashMap;
|
||||||
|
|
||||||
import java.lang.reflect.*;
|
import java.lang.reflect.*;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.ResultSetMetaData;
|
import java.sql.ResultSetMetaData;
|
||||||
@ -26,6 +28,8 @@ import java.sql.SQLException;
|
|||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import static com.moparisthebest.jdbc.UpdateableDTO.YES;
|
import static com.moparisthebest.jdbc.UpdateableDTO.YES;
|
||||||
import static com.moparisthebest.jdbc.UpdateableDTO.NO;
|
import static com.moparisthebest.jdbc.UpdateableDTO.NO;
|
||||||
@ -47,7 +51,11 @@ import static com.moparisthebest.jdbc.UpdateableDTO.NO;
|
|||||||
*
|
*
|
||||||
* @author Travis Burtrum (modifications from beehive)
|
* @author Travis Burtrum (modifications from beehive)
|
||||||
*/
|
*/
|
||||||
public class RowToObjectMapper<K, T> extends RowMapper<K, T> {
|
public class RowToObjectMapper<K, T> extends AbstractRowMapper<K, T> {
|
||||||
|
|
||||||
|
private static final String SETTER_NAME_REGEX = "^(set)([A-Z_]\\w*+)";
|
||||||
|
protected static final TypeMappingsFactory _tmf = TypeMappingsFactory.getInstance();
|
||||||
|
protected static final Pattern _setterRegex = Pattern.compile(SETTER_NAME_REGEX);
|
||||||
|
|
||||||
public static final int TYPE_BOOLEAN = _tmf.getTypeId(Boolean.TYPE);//TypeMappingsFactory.TYPE_BOOLEAN; // not public?
|
public static final int TYPE_BOOLEAN = _tmf.getTypeId(Boolean.TYPE);//TypeMappingsFactory.TYPE_BOOLEAN; // not public?
|
||||||
public static final int TYPE_BOOLEAN_OBJ = _tmf.getTypeId(Boolean.class);//TypeMappingsFactory.TYPE_BOOLEAN_OBJ; // not public?
|
public static final int TYPE_BOOLEAN_OBJ = _tmf.getTypeId(Boolean.class);//TypeMappingsFactory.TYPE_BOOLEAN_OBJ; // not public?
|
||||||
@ -82,6 +90,11 @@ public class RowToObjectMapper<K, T> extends RowMapper<K, T> {
|
|||||||
this(resultSet, returnTypeClass, cal, mapValType, null);
|
this(resultSet, returnTypeClass, cal, mapValType, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public RowToObjectMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType, Class<K> mapKeyType) {
|
||||||
|
this(resultSet, returnTypeClass, cal, mapValType, mapKeyType, false);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new RowToObjectMapper.
|
* Create a new RowToObjectMapper.
|
||||||
*
|
*
|
||||||
@ -89,11 +102,17 @@ public class RowToObjectMapper<K, T> extends RowMapper<K, T> {
|
|||||||
* @param returnTypeClass Class to map to.
|
* @param returnTypeClass Class to map to.
|
||||||
* @param cal Calendar instance for date/time mappings.
|
* @param cal Calendar instance for date/time mappings.
|
||||||
*/
|
*/
|
||||||
public RowToObjectMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType, Class<K> mapKeyType) {
|
public RowToObjectMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType, Class<K> mapKeyType, boolean caseInsensitiveMap) {
|
||||||
super(resultSet, returnTypeClass, cal, mapKeyType);
|
super(resultSet, returnTypeClass, cal, mapKeyType);
|
||||||
returnMap = Map.class.isAssignableFrom(returnTypeClass);
|
returnMap = Map.class.isAssignableFrom(returnTypeClass);
|
||||||
if(returnMap){
|
if(returnMap){
|
||||||
_returnTypeClass = ResultSetMapper.getConcreteClass(returnTypeClass, HashMap.class);
|
Class<? extends T> rtc = ResultSetMapper.getConcreteClass(returnTypeClass, HashMap.class);
|
||||||
|
if(caseInsensitiveMap && HashMap.class.equals(rtc)) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
final Class<? extends T> rtct = (Class<? extends T>) CaseInsensitiveHashMap.class;
|
||||||
|
rtc = rtct;
|
||||||
|
}
|
||||||
|
_returnTypeClass = rtc;
|
||||||
componentType = mapValType;
|
componentType = mapValType;
|
||||||
}else{
|
}else{
|
||||||
_returnTypeClass = returnTypeClass;
|
_returnTypeClass = returnTypeClass;
|
||||||
@ -137,7 +156,7 @@ public class RowToObjectMapper<K, T> extends RowMapper<K, T> {
|
|||||||
* like perhaps to implement the original beehive behavior of case-insensitive strings
|
* like perhaps to implement the original beehive behavior of case-insensitive strings
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings({"unchecked"})
|
@SuppressWarnings({"unchecked"})
|
||||||
protected Map<String, Object> getMapImplementation() throws IllegalAccessException, InstantiationException {
|
private Map<String, Object> getMapImplementation() throws IllegalAccessException, InstantiationException {
|
||||||
return (Map<String, Object>)_returnTypeClass.newInstance();
|
return (Map<String, Object>)_returnTypeClass.newInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -441,40 +460,178 @@ public class RowToObjectMapper<K, T> extends RowMapper<K, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public static <T> T fixNull(Class<T> returnType) {
|
||||||
|
return returnType.cast(_tmf.fixNull(returnType));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the given method is a java bean setter method.
|
||||||
|
* @param method Method to check
|
||||||
|
* @return True if the method is a setter method.
|
||||||
|
*/
|
||||||
|
protected boolean isSetterMethod(Method method) {
|
||||||
|
Matcher matcher = _setterRegex.matcher(method.getName());
|
||||||
|
if (matcher.matches()) {
|
||||||
|
|
||||||
|
if (Modifier.isStatic(method.getModifiers())) return false;
|
||||||
|
if (!Modifier.isPublic(method.getModifiers())) return false;
|
||||||
|
if (!Void.TYPE.equals(method.getReturnType())) return false;
|
||||||
|
|
||||||
|
// method parameter checks
|
||||||
|
Class[] params = method.getParameterTypes();
|
||||||
|
if (params.length != 1) return false;
|
||||||
|
if (TypeMappingsFactory.TYPE_UNKNOWN == _tmf.getTypeId(params[0])) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract a column value from the ResultSet and return it as resultType.
|
||||||
|
*
|
||||||
|
* @param index The column index of the value to extract from the ResultSet.
|
||||||
|
* @param resultType The return type. Defined in TypeMappingsFactory.
|
||||||
|
* @return The extracted value
|
||||||
|
* @throws java.sql.SQLException on error.
|
||||||
|
*/
|
||||||
protected Object extractColumnValue(int index, int resultType) throws SQLException {
|
protected Object extractColumnValue(int index, int resultType) throws SQLException {
|
||||||
try{
|
try{
|
||||||
if (resultType != TYPE_BOOLEAN && resultType != TYPE_BOOLEAN_OBJ)
|
switch (resultType) {
|
||||||
return super.extractColumnValue(index, resultType);
|
case TypeMappingsFactory.TYPE_INT:
|
||||||
else {
|
return new Integer(_resultSet.getInt(index));
|
||||||
// do some special handling to convert a database string to a boolean
|
case TypeMappingsFactory.TYPE_LONG:
|
||||||
boolean ret;
|
return new Long(_resultSet.getLong(index));
|
||||||
try {
|
case TypeMappingsFactory.TYPE_FLOAT:
|
||||||
// try to get an actual boolean from the database
|
return new Float(_resultSet.getFloat(index));
|
||||||
ret = _resultSet.getBoolean(index);
|
case TypeMappingsFactory.TYPE_DOUBLE:
|
||||||
// null seems to get returned as false above, so String code won't run if its null
|
return new Double(_resultSet.getDouble(index));
|
||||||
if (_resultSet.wasNull())
|
case TypeMappingsFactory.TYPE_BYTE:
|
||||||
if (resultType == TYPE_BOOLEAN_OBJ)
|
return new Byte(_resultSet.getByte(index));
|
||||||
return null; // only return null for Boolean object
|
case TypeMappingsFactory.TYPE_SHORT:
|
||||||
else
|
return new Short(_resultSet.getShort(index));
|
||||||
throw new MapperException(String.format("Implicit conversion of database string to boolean failed on column '%d'. Returned string needs to be 'Y' or 'N' and was instead 'null'. If you want to accept null values, make it an object Boolean instead of primitive boolean.", index));
|
case TypeMappingsFactory.TYPE_INT_OBJ:
|
||||||
} catch (SQLException e) {
|
{
|
||||||
// if we are here, it wasn't a boolean or null, so try to grab a string instead
|
int i = _resultSet.getInt(index);
|
||||||
String bool = _resultSet.getString(index);//.toUpperCase(); // do we want it case-insensitive?
|
return _resultSet.wasNull() ? null : new Integer(i);
|
||||||
ret = YES.equals(bool);
|
|
||||||
if (!ret && !NO.equals(bool))
|
|
||||||
throw new MapperException(String.format("Implicit conversion of database string to boolean failed on column '%d'. Returned string needs to be 'Y' or 'N' and was instead '%s'.", index, bool));
|
|
||||||
//throw e;
|
|
||||||
}
|
}
|
||||||
return ret ? Boolean.TRUE : Boolean.FALSE;
|
case TypeMappingsFactory.TYPE_LONG_OBJ:
|
||||||
|
{
|
||||||
|
long i = _resultSet.getLong(index);
|
||||||
|
return _resultSet.wasNull() ? null : new Long(i);
|
||||||
|
}
|
||||||
|
case TypeMappingsFactory.TYPE_FLOAT_OBJ:
|
||||||
|
{
|
||||||
|
float i = _resultSet.getFloat(index);
|
||||||
|
return _resultSet.wasNull() ? null : new Float(i);
|
||||||
|
}
|
||||||
|
case TypeMappingsFactory.TYPE_DOUBLE_OBJ:
|
||||||
|
{
|
||||||
|
double i = _resultSet.getDouble(index);
|
||||||
|
return _resultSet.wasNull() ? null : new Double(i);
|
||||||
|
}
|
||||||
|
case TypeMappingsFactory.TYPE_BYTE_OBJ:
|
||||||
|
{
|
||||||
|
byte i = _resultSet.getByte(index);
|
||||||
|
return _resultSet.wasNull() ? null : new Byte(i);
|
||||||
|
}
|
||||||
|
case TypeMappingsFactory.TYPE_SHORT_OBJ:
|
||||||
|
{
|
||||||
|
short i = _resultSet.getShort(index);
|
||||||
|
return _resultSet.wasNull() ? null : new Short(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
case TypeMappingsFactory.TYPE_BOOLEAN:
|
||||||
|
case TypeMappingsFactory.TYPE_BOOLEAN_OBJ:
|
||||||
|
{
|
||||||
|
// do some special handling to convert a database string to a boolean
|
||||||
|
boolean ret;
|
||||||
|
try {
|
||||||
|
// try to get an actual boolean from the database
|
||||||
|
ret = _resultSet.getBoolean(index);
|
||||||
|
// null seems to get returned as false above, so String code won't run if its null
|
||||||
|
if (_resultSet.wasNull())
|
||||||
|
if (resultType == TYPE_BOOLEAN_OBJ)
|
||||||
|
return null; // only return null for Boolean object
|
||||||
|
else
|
||||||
|
throw new MapperException(String.format("Implicit conversion of database string to boolean failed on column '%d'. Returned string needs to be 'Y' or 'N' and was instead 'null'. If you want to accept null values, make it an object Boolean instead of primitive boolean.", index));
|
||||||
|
} catch (SQLException e) {
|
||||||
|
// if we are here, it wasn't a boolean or null, so try to grab a string instead
|
||||||
|
String bool = _resultSet.getString(index);//.toUpperCase(); // do we want it case-insensitive?
|
||||||
|
ret = YES.equals(bool);
|
||||||
|
if (!ret && !NO.equals(bool))
|
||||||
|
throw new MapperException(String.format("Implicit conversion of database string to boolean failed on column '%d'. Returned string needs to be 'Y' or 'N' and was instead '%s'.", index, bool));
|
||||||
|
//throw e;
|
||||||
|
}
|
||||||
|
return ret ? Boolean.TRUE : Boolean.FALSE;
|
||||||
|
}
|
||||||
|
case TypeMappingsFactory.TYPE_STRING:
|
||||||
|
case TypeMappingsFactory.TYPE_XMLBEAN_ENUM:
|
||||||
|
return _resultSet.getString(index);
|
||||||
|
case TypeMappingsFactory.TYPE_BIG_DECIMAL:
|
||||||
|
return _resultSet.getBigDecimal(index);
|
||||||
|
case TypeMappingsFactory.TYPE_BYTES:
|
||||||
|
return _resultSet.getBytes(index);
|
||||||
|
case TypeMappingsFactory.TYPE_TIMESTAMP:
|
||||||
|
{
|
||||||
|
if (null == _cal)
|
||||||
|
return _resultSet.getTimestamp(index);
|
||||||
|
else
|
||||||
|
return _resultSet.getTimestamp(index, _cal);
|
||||||
|
}
|
||||||
|
case TypeMappingsFactory.TYPE_TIME:
|
||||||
|
{
|
||||||
|
if (null == _cal)
|
||||||
|
return _resultSet.getTime(index);
|
||||||
|
else
|
||||||
|
return _resultSet.getTime(index, _cal);
|
||||||
|
}
|
||||||
|
case TypeMappingsFactory.TYPE_SQLDATE:
|
||||||
|
{
|
||||||
|
if (null == _cal)
|
||||||
|
return _resultSet.getDate(index);
|
||||||
|
else
|
||||||
|
return _resultSet.getDate(index, _cal);
|
||||||
|
}
|
||||||
|
case TypeMappingsFactory.TYPE_DATE:
|
||||||
|
{
|
||||||
|
// convert explicity to java.util.Date
|
||||||
|
// 12918 | knex does not return java.sql.Date properly from web service
|
||||||
|
java.sql.Timestamp ts = (null == _cal) ? _resultSet.getTimestamp(index) : _resultSet.getTimestamp(index, _cal);
|
||||||
|
if (null == ts)
|
||||||
|
return null;
|
||||||
|
return new java.util.Date(ts.getTime());
|
||||||
|
}
|
||||||
|
case TypeMappingsFactory.TYPE_CALENDAR:
|
||||||
|
{
|
||||||
|
java.sql.Timestamp ts = (null == _cal) ? _resultSet.getTimestamp(index) : _resultSet.getTimestamp(index, _cal);
|
||||||
|
if (null == ts)
|
||||||
|
return null;
|
||||||
|
Calendar c = (null == _cal) ? Calendar.getInstance() : (Calendar) _cal.clone();
|
||||||
|
c.setTimeInMillis(ts.getTime());
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
case TypeMappingsFactory.TYPE_REF:
|
||||||
|
return _resultSet.getRef(index);
|
||||||
|
case TypeMappingsFactory.TYPE_BLOB:
|
||||||
|
return _resultSet.getBlob(index);
|
||||||
|
case TypeMappingsFactory.TYPE_CLOB:
|
||||||
|
return _resultSet.getClob(index);
|
||||||
|
case TypeMappingsFactory.TYPE_ARRAY:
|
||||||
|
return _resultSet.getArray(index);
|
||||||
|
case TypeMappingsFactory.TYPE_READER:
|
||||||
|
case TypeMappingsFactory.TYPE_STREAM:
|
||||||
|
throw new MapperException("streaming return types are not supported by the JdbcControl; use ResultSet instead");
|
||||||
|
case TypeMappingsFactory.TYPE_STRUCT:
|
||||||
|
case TypeMappingsFactory.TYPE_UNKNOWN:
|
||||||
|
// JAVA_TYPE (could be any), or REF
|
||||||
|
return _resultSet.getObject(index);
|
||||||
|
default:
|
||||||
|
throw new MapperException("internal error: unknown type ID: " + Integer.toString(resultType));
|
||||||
}
|
}
|
||||||
}catch(SQLException e){
|
}catch(SQLException e){
|
||||||
throw new SQLExceptionColumnNum(e, index);
|
throw new SQLExceptionColumnNum(e, index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> T fixNull(Class<T> returnType) {
|
|
||||||
return returnType.cast(_tmf.fixNull(returnType));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
package com.moparisthebest.jdbc.util;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by mopar on 5/18/17.
|
||||||
|
*/
|
||||||
|
public class CaseInsensitiveHashMap<String, V> extends HashMap<String, V> {
|
||||||
|
@Override
|
||||||
|
public V get(Object key) {
|
||||||
|
return super.get(key instanceof java.lang.String ? ((java.lang.String) key).toLowerCase() : key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean containsKey(Object key) {
|
||||||
|
return super.containsKey(key instanceof java.lang.String ? ((java.lang.String) key).toLowerCase() : key);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,81 @@
|
|||||||
|
package com.moparisthebest.jdbc;
|
||||||
|
|
||||||
|
import com.moparisthebest.jdbc.dto.*;
|
||||||
|
import org.junit.*;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.Parameterized;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.DriverManager;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static com.moparisthebest.jdbc.QueryMapperTest.fieldPerson1;
|
||||||
|
import static com.moparisthebest.jdbc.QueryMapperTest.getConnection;
|
||||||
|
import static com.moparisthebest.jdbc.QueryMapperTest.personRegular;
|
||||||
|
import static com.moparisthebest.jdbc.TryClose.tryClose;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by mopar on 6/10/14.
|
||||||
|
*/
|
||||||
|
@RunWith(Parameterized.class)
|
||||||
|
public class CleaningQueryMapperTest {
|
||||||
|
|
||||||
|
private static Connection conn;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUp() throws Throwable {
|
||||||
|
conn = getConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void tearDown() throws Throwable {
|
||||||
|
tryClose(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected QueryMapper qm;
|
||||||
|
protected final ResultSetMapper rsm;
|
||||||
|
|
||||||
|
public CleaningQueryMapperTest(final ResultSetMapper rsm) {
|
||||||
|
this.rsm = rsm;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void open() {
|
||||||
|
this.qm = new QueryMapper(conn, rsm);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void close() {
|
||||||
|
tryClose(qm);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Parameterized.Parameters(name="{0}")
|
||||||
|
public static Collection<Object[]> getParameters()
|
||||||
|
{
|
||||||
|
final Cleaner<FieldPerson> personCleaner = new Cleaner<FieldPerson>() {
|
||||||
|
@Override
|
||||||
|
public FieldPerson clean(final FieldPerson dto) {
|
||||||
|
dto.firstName += " " + dto.lastName;
|
||||||
|
dto.lastName = null;
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return Arrays.asList(new Object[][] {
|
||||||
|
{ new CleaningResultSetMapper<FieldPerson>(personCleaner) },
|
||||||
|
{ new CleaningCachingResultSetMapper<FieldPerson>(personCleaner) },
|
||||||
|
{ new CleaningCompilingResultSetMapper<FieldPerson>(personCleaner) },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// fields
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFieldRegularPerson() throws Throwable {
|
||||||
|
final Person expected = fieldPerson1;
|
||||||
|
final Person actual = qm.toObject(personRegular, expected.getClass(), expected.getPersonNo());
|
||||||
|
assertEquals(expected.getFirstName() + " " + expected.getLastName(), actual.getFirstName());
|
||||||
|
assertNull(actual.getLastName());
|
||||||
|
}
|
||||||
|
}
|
@ -10,6 +10,8 @@ import java.sql.DriverManager;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static com.moparisthebest.jdbc.TryClose.tryClose;
|
import static com.moparisthebest.jdbc.TryClose.tryClose;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by mopar on 6/10/14.
|
* Created by mopar on 6/10/14.
|
||||||
@ -19,48 +21,47 @@ public class QueryMapperTest {
|
|||||||
|
|
||||||
private static Connection conn;
|
private static Connection conn;
|
||||||
|
|
||||||
protected static final Person fieldPerson1 = new FieldPerson(1, new Date(0), "First", "Person");
|
public static final Person fieldPerson1 = new FieldPerson(1, new Date(0), "First", "Person");
|
||||||
protected static final Boss fieldBoss1 = new FieldBoss(2, new Date(0), "Second", "Person", "Finance", "Second");
|
public static final Boss fieldBoss1 = new FieldBoss(2, new Date(0), "Second", "Person", "Finance", "Second");
|
||||||
protected static final Boss fieldBoss2 = new FieldBoss(3, new Date(0), "Third", "Person", "Finance", null);
|
public static final Boss fieldBoss2 = new FieldBoss(3, new Date(0), "Third", "Person", "Finance", null);
|
||||||
protected static final Boss fieldBoss3 = new FieldBoss(4, new Date(0), null, "Person", "Finance", "Fourth");
|
public static final Boss fieldBoss3 = new FieldBoss(4, new Date(0), null, "Person", "Finance", "Fourth");
|
||||||
|
|
||||||
protected static final Person setPerson1 = new SetPerson(fieldPerson1);
|
public static final Person setPerson1 = new SetPerson(fieldPerson1);
|
||||||
protected static final Boss setBoss1 = new SetBoss(fieldBoss1);
|
public static final Boss setBoss1 = new SetBoss(fieldBoss1);
|
||||||
protected static final Boss setBoss2 = new SetBoss(fieldBoss2);
|
public static final Boss setBoss2 = new SetBoss(fieldBoss2);
|
||||||
protected static final Boss setBoss3 = new SetBoss(fieldBoss3);
|
public static final Boss setBoss3 = new SetBoss(fieldBoss3);
|
||||||
|
|
||||||
protected static final Person reverseFieldPerson1 = new ReverseFieldPerson(fieldPerson1);
|
public static final Person reverseFieldPerson1 = new ReverseFieldPerson(fieldPerson1);
|
||||||
protected static final Boss reverseFieldBoss1 = new ReverseFieldBoss(fieldBoss1);
|
public static final Boss reverseFieldBoss1 = new ReverseFieldBoss(fieldBoss1);
|
||||||
protected static final Boss reverseFieldBoss2 = new ReverseFieldBoss(fieldBoss2);
|
public static final Boss reverseFieldBoss2 = new ReverseFieldBoss(fieldBoss2);
|
||||||
protected static final Boss reverseFieldBoss3 = new ReverseFieldBoss(fieldBoss3);
|
public static final Boss reverseFieldBoss3 = new ReverseFieldBoss(fieldBoss3);
|
||||||
|
|
||||||
protected static final Person reverseSetPerson1 = new ReverseSetPerson(fieldPerson1);
|
public static final Person reverseSetPerson1 = new ReverseSetPerson(fieldPerson1);
|
||||||
protected static final Boss reverseSetBoss1 = new ReverseSetBoss(fieldBoss1);
|
public static final Boss reverseSetBoss1 = new ReverseSetBoss(fieldBoss1);
|
||||||
protected static final Boss reverseSetBoss2 = new ReverseSetBoss(fieldBoss2);
|
public static final Boss reverseSetBoss2 = new ReverseSetBoss(fieldBoss2);
|
||||||
protected static final Boss reverseSetBoss3 = new ReverseSetBoss(fieldBoss3);
|
public static final Boss reverseSetBoss3 = new ReverseSetBoss(fieldBoss3);
|
||||||
|
|
||||||
protected static final String personRegular = "SELECT * FROM person WHERE person_no = ?";
|
public static final String personRegular = "SELECT * FROM person WHERE person_no = ?";
|
||||||
protected static final String bossRegularAndUnderscore = "SELECT p.person_no, p.first_name AS firstName, p.last_name, p.birth_date, b.department, p.first_name " +
|
public static final String bossRegularAndUnderscore = "SELECT p.person_no, p.first_name AS firstName, p.last_name, p.birth_date, b.department, p.first_name " +
|
||||||
"FROM person p " +
|
"FROM person p " +
|
||||||
"JOIN boss b ON p.person_no = b.person_no " +
|
"JOIN boss b ON p.person_no = b.person_no " +
|
||||||
"WHERE p.person_no = ?";
|
"WHERE p.person_no = ?";
|
||||||
protected static final String bossRegularAndUnderscoreReverse = "SELECT p.person_no, p.first_name, p.last_name, p.birth_date, b.department, p.first_name AS firstName " +
|
public static final String bossRegularAndUnderscoreReverse = "SELECT p.person_no, p.first_name, p.last_name, p.birth_date, b.department, p.first_name AS firstName " +
|
||||||
"FROM person p " +
|
"FROM person p " +
|
||||||
"JOIN boss b ON p.person_no = b.person_no " +
|
"JOIN boss b ON p.person_no = b.person_no " +
|
||||||
"WHERE p.person_no = ?";
|
"WHERE p.person_no = ?";
|
||||||
protected static final String bossRegular = "SELECT p.person_no, p.first_name AS firstName, p.last_name, p.birth_date, b.department " +
|
public static final String bossRegular = "SELECT p.person_no, p.first_name AS firstName, p.last_name, p.birth_date, b.department " +
|
||||||
"FROM person p " +
|
"FROM person p " +
|
||||||
"JOIN boss b ON p.person_no = b.person_no " +
|
"JOIN boss b ON p.person_no = b.person_no " +
|
||||||
"WHERE p.person_no = ?";
|
"WHERE p.person_no = ?";
|
||||||
protected static final String bossUnderscore = "SELECT p.person_no, p.first_name, p.last_name, p.birth_date, b.department " +
|
public static final String bossUnderscore = "SELECT p.person_no, p.first_name, p.last_name, p.birth_date, b.department " +
|
||||||
"FROM person p " +
|
"FROM person p " +
|
||||||
"JOIN boss b ON p.person_no = b.person_no " +
|
"JOIN boss b ON p.person_no = b.person_no " +
|
||||||
"WHERE p.person_no = ?";
|
"WHERE p.person_no = ?";
|
||||||
|
|
||||||
@BeforeClass
|
public static Connection getConnection() throws Throwable {
|
||||||
public static void setUp() throws Throwable {
|
|
||||||
Class.forName("org.apache.derby.jdbc.EmbeddedDriver").newInstance();
|
Class.forName("org.apache.derby.jdbc.EmbeddedDriver").newInstance();
|
||||||
conn = DriverManager.getConnection("jdbc:derby:memory:derbyDB;create=true");
|
final Connection conn = DriverManager.getConnection("jdbc:derby:memory:derbyDB;create=true");
|
||||||
QueryMapper qm = null;
|
QueryMapper qm = null;
|
||||||
try {
|
try {
|
||||||
qm = new QueryMapper(conn);
|
qm = new QueryMapper(conn);
|
||||||
@ -75,6 +76,12 @@ public class QueryMapperTest {
|
|||||||
} finally {
|
} finally {
|
||||||
tryClose(qm);
|
tryClose(qm);
|
||||||
}
|
}
|
||||||
|
return conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUp() throws Throwable {
|
||||||
|
conn = getConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
@ -105,6 +112,7 @@ public class QueryMapperTest {
|
|||||||
return Arrays.asList(new Object[][] {
|
return Arrays.asList(new Object[][] {
|
||||||
{ new ResultSetMapper() },
|
{ new ResultSetMapper() },
|
||||||
{ new CachingResultSetMapper() },
|
{ new CachingResultSetMapper() },
|
||||||
|
{ new CaseInsensitiveMapResultSetMapper() },
|
||||||
{ new CompilingResultSetMapper() },
|
{ new CompilingResultSetMapper() },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -231,7 +239,7 @@ public class QueryMapperTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testSelectArrayMap() throws Throwable {
|
public void testSelectArrayMap() throws Throwable {
|
||||||
final List<Map<String, String>> arrayMap = getListMap();
|
final List<Map<String, String>> arrayMap = getListMap();
|
||||||
Assert.assertEquals(arrayMap.toArray(new Map[arrayMap.size()]), qm.toArrayMap("SELECT first_name, last_name FROM person WHERE person_no < 4", arrayMap.get(0).getClass(), String.class));
|
Assert.assertArrayEquals(arrayMap.toArray(new Map[arrayMap.size()]), qm.toArrayMap("SELECT first_name, last_name FROM person WHERE person_no < 4", arrayMap.get(0).getClass(), String.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -325,4 +333,32 @@ public class QueryMapperTest {
|
|||||||
*/
|
*/
|
||||||
Assert.assertEquals(expected, actual);
|
Assert.assertEquals(expected, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCaseInsensitiveMap() throws Throwable {
|
||||||
|
final Map<String, String> map = qm.toListMap("SELECT 'bob' as bob, 'tom' as tom FROM person WHERE person_no = ?", String.class, 1).get(0);
|
||||||
|
if (rsm instanceof CaseInsensitiveMapResultSetMapper) {
|
||||||
|
assertEquals("bob", map.get("bob"));
|
||||||
|
assertEquals("bob", map.get("Bob"));
|
||||||
|
assertEquals("bob", map.get("BoB"));
|
||||||
|
assertEquals("bob", map.get("BOb"));
|
||||||
|
assertEquals("bob", map.get("BOB"));
|
||||||
|
assertEquals("tom", map.get("tom"));
|
||||||
|
assertEquals("tom", map.get("Tom"));
|
||||||
|
assertEquals("tom", map.get("ToM"));
|
||||||
|
assertEquals("tom", map.get("TOm"));
|
||||||
|
assertEquals("tom", map.get("TOM"));
|
||||||
|
} else {
|
||||||
|
assertEquals("bob", map.get("bob"));
|
||||||
|
assertNull(map.get("Bob"));
|
||||||
|
assertNull(map.get("BoB"));
|
||||||
|
assertNull(map.get("BOb"));
|
||||||
|
assertNull(map.get("BOB"));
|
||||||
|
assertEquals("tom", map.get("tom"));
|
||||||
|
assertNull(map.get("Tom"));
|
||||||
|
assertNull(map.get("ToM"));
|
||||||
|
assertNull(map.get("TOm"));
|
||||||
|
assertNull(map.get("TOM"));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user