package org.simpleflatmapper.jdbi; import org.simpleflatmapper.jdbc.DynamicJdbcMapper; import org.simpleflatmapper.jdbc.JdbcMapperFactory; import org.simpleflatmapper.map.Mapper; import org.simpleflatmapper.util.BiPredicate; import org.simpleflatmapper.util.UnaryFactory; import org.skife.jdbi.v2.ResultSetMapperFactory; import org.skife.jdbi.v2.StatementContext; import org.skife.jdbi.v2.tweak.ResultSetMapper; import java.sql.ResultSet; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; public class SfmResultSetMapperFactory implements ResultSetMapperFactory { private static final UnaryFactory<Class<?>, Mapper<ResultSet, ?>> DEFAULT_FACTORY = new UnaryFactory<Class<?>, Mapper<ResultSet, ?>>() { @Override public Mapper<ResultSet, ?> newInstance(Class<?> aClass) { return JdbcMapperFactory.newInstance().newMapper(aClass); } }; private static final BiPredicate<Class<?>, StatementContext> DEFAULT_ACCEPT_PREDICATE = new BiPredicate<Class<?>, StatementContext>() { @Override public boolean test(Class<?> aClass, StatementContext statementContext) { return true; } }; private final UnaryFactory<Class<?>, Mapper<ResultSet, ?>> mapperFactory; private final ConcurrentMap<Class<?>, ResultSetMapper<?>> cache = new ConcurrentHashMap<Class<?>, ResultSetMapper<?>>(); private final BiPredicate<Class<?>, StatementContext> acceptsPredicate; public SfmResultSetMapperFactory() { this(DEFAULT_FACTORY); } public SfmResultSetMapperFactory(UnaryFactory<Class<?>, Mapper<ResultSet, ?>> mapperFactory) { this(DEFAULT_ACCEPT_PREDICATE, mapperFactory); } public SfmResultSetMapperFactory(BiPredicate<Class<?>, StatementContext> acceptsPredicate, UnaryFactory<Class<?>, Mapper<ResultSet, ?>> mapperFactory) { this.mapperFactory = mapperFactory; this.acceptsPredicate = acceptsPredicate; } @Override public boolean accepts(Class aClass, StatementContext statementContext) { return acceptsPredicate.test(aClass, statementContext); } @SuppressWarnings("unchecked") @Override public ResultSetMapper mapperFor(Class aClass, StatementContext statementContext) { ResultSetMapper mapper = cache.get(aClass); if (mapper == null) { Mapper<ResultSet, ?> resultSetMapper = mapperFactory.newInstance(aClass); mapper = toResultSetMapper(resultSetMapper); ResultSetMapper<?> cachedMapper = cache.putIfAbsent(aClass, mapper); if (cachedMapper != null) { mapper = cachedMapper; } } return mapper; } private <T> ResultSetMapper<T> toResultSetMapper(Mapper<ResultSet, T> resultSetMapper) { ResultSetMapper mapper; if (resultSetMapper instanceof DynamicJdbcMapper) { mapper = new DynamicSfmResultSetMapper<T>((DynamicJdbcMapper<T>) resultSetMapper); } else { mapper = new DefaultSfmResultSetMapper<T>(resultSetMapper); } return mapper; } }