Skip to content

Instantly share code, notes, and snippets.

@newjam
Created September 28, 2015 01:45
Show Gist options
  • Save newjam/650a6313ac7619571e55 to your computer and use it in GitHub Desktop.
Save newjam/650a6313ac7619571e55 to your computer and use it in GitHub Desktop.
Get free jdbi ResultSetMapper if your class has a constructor from a ResultSet
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import org.skife.jdbi.v2.ResultSetMapperFactory;
import org.skife.jdbi.v2.StatementContext;
import org.skife.jdbi.v2.tweak.ResultSetMapper;
/**
* Automatically create a ResultSetMapper if the type has a constructor that accepts a ResultSet
*/
@Slf4j
public class ConstructorResultSetMapperFactory implements ResultSetMapperFactory {
private static Optional<Constructor<?>> getConstructor(Class type) {
try {
return Optional.of(type.getConstructor(ResultSet.class));
} catch (NoSuchMethodException | SecurityException ex) {
return Optional.empty();
}
}
private static class ConstructorResultSetMapper implements ResultSetMapper {
private final Constructor constructor;
public ConstructorResultSetMapper(Constructor constructor) {
this.constructor = constructor;
}
@Override
public Object map(int i, ResultSet rs, StatementContext sc) throws SQLException {
try {
return constructor.newInstance(rs);
} catch(InvocationTargetException ex) {
Throwable cause = ex.getCause();
// Don't mangle useful exceptions!
if(cause != null && cause instanceof SQLException) {
throw (SQLException) cause;
} else {
throw new RuntimeException(ex);
}
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException ex) {
throw new RuntimeException(ex);
}
}
}
@Override
public boolean accepts(Class type, StatementContext sc) {
return getConstructor(type).isPresent();
}
private static ResultSetMapper fromConstructor(Constructor constructor) {
log.debug("Automatically creating ResultSetMapper<{}> from constructor.", constructor.getDeclaringClass().getSimpleName());
return new ConstructorResultSetMapper(constructor);
}
@Override
public ResultSetMapper mapperFor(Class type, StatementContext sc) {
return getConstructor(type)
.map(ConstructorResultSetMapperFactory::fromConstructor)
.orElseThrow(RuntimeException::new);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment