org.sfm.jdbc.AbstractResultSetMapperBuilder Maven / Gradle / Ivy
package org.sfm.jdbc;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import org.sfm.map.FieldMapper;
import org.sfm.map.FieldMapperErrorHandler;
import org.sfm.map.FieldMapperImpl;
import org.sfm.map.LogFieldMapperErrorHandler;
import org.sfm.map.MapperBuilderErrorHandler;
import org.sfm.map.RethrowMapperBuilderErrorHandler;
import org.sfm.reflect.Getter;
import org.sfm.reflect.Instantiator;
import org.sfm.reflect.InstantiatorFactory;
import org.sfm.reflect.Setter;
import org.sfm.reflect.SetterFactory;
import org.sfm.reflect.asm.AsmFactory;
import org.sfm.reflect.asm.ConstructorDefinition;
import org.sfm.reflect.asm.Parameter;
import org.sfm.utils.PropertyNameMatcher;
public abstract class AbstractResultSetMapperBuilder implements ResultSetMapperBuilder {
private FieldMapperErrorHandler fieldMapperErrorHandler = new LogFieldMapperErrorHandler();
private MapperBuilderErrorHandler mapperBuilderErrorHandler = new RethrowMapperBuilderErrorHandler();
private final Class target;
private final PrimitiveFieldMapperFactory primitiveFieldMapperFactory;
private final AsmFactory asmFactory;
private final InstantiatorFactory instantiatorFactory;
private final List> fields = new ArrayList>();
private final List> constructors;
private final Map> constructorInjection;
public AbstractResultSetMapperBuilder(Class target, SetterFactory setterFactory) throws NoSuchMethodException, SecurityException, IOException {
this.target = target;
this.primitiveFieldMapperFactory = new PrimitiveFieldMapperFactory<>(setterFactory);
this.asmFactory = setterFactory.getAsmFactory();
this.instantiatorFactory = new InstantiatorFactory(asmFactory);
if (AsmHelper.isAsmPresent()) {
this.constructors = ConstructorDefinition.extractConstructors(target);
this.constructorInjection = new HashMap>();
} else {
this.constructors = null;
this.constructorInjection = null;
}
}
@Override
public final ResultSetMapperBuilder fieldMapperErrorHandler(final FieldMapperErrorHandler errorHandler) {
if (!fields.isEmpty()) {
throw new IllegalStateException(
"Error Handler need to be set before adding fields");
}
fieldMapperErrorHandler = errorHandler;
return this;
}
@Override
public final ResultSetMapperBuilder mapperBuilderErrorHandler(final MapperBuilderErrorHandler errorHandler) {
mapperBuilderErrorHandler = errorHandler;
return this;
}
@Override
public final ResultSetMapperBuilder addNamedColumn(final String column) {
return addNamedColumn(column, ResultSetGetterFactory.UNDEFINED);
}
@Override
public final ResultSetMapperBuilder addIndexedColumn(final String column) {
return addIndexedColumn(column, fields.size() + 1);
}
@Override
public final ResultSetMapperBuilder addIndexedColumn(final String column, final int columnIndex) {
return addIndexedColumn(column, columnIndex, ResultSetGetterFactory.UNDEFINED);
}
@Override
public final ResultSetMapperBuilder addMapping(final String property, final String column) {
return addMapping(property, column, ResultSetGetterFactory.UNDEFINED);
}
@Override
public final ResultSetMapperBuilder addMapping(final String property, final int column) {
return addMapping(property, column, ResultSetGetterFactory.UNDEFINED);
}
@Override
public final ResultSetMapperBuilder addNamedColumn(final String column, final int sqlType) {
Parameter param = hasMatchingConstructor(column);
if (param != null) {
removeNonMatchingConstructor(param);
constructorInjection.put(param, ResultSetGetterFactory.newGetter(param.getType(), column, sqlType));
} else {
final Setter setter = findSetter(column);
if (setter == null) {
mapperBuilderErrorHandler.setterNotFound(target, column);
} else {
addMapping(setter, column, sqlType);
}
}
return this;
}
@Override
public final ResultSetMapperBuilder addIndexedColumn(final String column, final int columnIndex, final int sqlType) {
Parameter param = hasMatchingConstructor(column);
if (param != null) {
removeNonMatchingConstructor(param);
constructorInjection.put(param, ResultSetGetterFactory.newGetter(param.getType(), columnIndex, sqlType));
} else {
final Setter setter = findSetter(column);
if (setter == null) {
mapperBuilderErrorHandler.setterNotFound(target, column);
} else {
addMapping(setter, columnIndex, sqlType);
}
}
return this;
}
@Override
public final ResultSetMapperBuilder addMapping(final String property, final String column, final int sqlType) {
Parameter param = hasMatchingConstructor(column);
if (param != null) {
removeNonMatchingConstructor(param);
constructorInjection.put(param, ResultSetGetterFactory.newGetter(param.getType(), column, sqlType));
} else {
final Setter setter = getSetter(property);
if (setter == null) {
mapperBuilderErrorHandler.setterNotFound(target, property);
} else {
addMapping(setter, column, sqlType);
}
}
return this;
}
@Override
public final ResultSetMapperBuilder addMapping(final String property, final int column, final int sqlType) {
Parameter param = hasMatchingConstructor(property);
if (param != null) {
removeNonMatchingConstructor(param);
constructorInjection.put(param, ResultSetGetterFactory.newGetter(param.getType(), column, sqlType));
} else {
final Setter setter = getSetter(property);
if (setter == null) {
mapperBuilderErrorHandler.setterNotFound(target, property);
} else {
addMapping(setter, column, sqlType);
}
}
return this;
}
@Override
public final ResultSetMapperBuilder addMapping(final ResultSetMetaData metaData) throws SQLException {
for(int i = 1; i <= metaData.getColumnCount(); i++) {
addIndexedColumn(metaData.getColumnName(i), i, metaData.getColumnType(i));
}
return this;
}
@Override
public final JdbcMapper mapper() throws NoSuchMethodException, SecurityException {
if (asmFactory != null) {
try {
return asmFactory.createJdbcMapper(fields(), getInstantiator(), target);
} catch(Exception e) {
return new JdbcMapperImpl(fields(), getInstantiator());
}
} else {
return new JdbcMapperImpl(fields(), getInstantiator());
}
}
private Instantiator getInstantiator() throws NoSuchMethodException, SecurityException {
if (constructors == null) {
return instantiatorFactory.getInstantiator(ResultSet.class, target);
} else {
return instantiatorFactory.getInstantiator(ResultSet.class, constructors, constructorInjection);
}
}
public final Class getTarget() {
return target;
}
@Override
@SuppressWarnings("unchecked")
public final FieldMapper[] fields() {
return fields.toArray(new FieldMapper[fields.size()]);
}
private void addMapping(Setter setter, String column, int sqlType) {
FieldMapper fieldMapper;
if (setter.getPropertyType().isPrimitive()) {
fieldMapper = primitiveFieldMapperFactory.primitiveFieldMapper(column, setter, column, fieldMapperErrorHandler);
} else {
fieldMapper = objectFieldMapper(column, setter, sqlType);
}
fields.add(fieldMapper);
}
private void addMapping(Setter setter, int column, int sqlType) {
FieldMapper fieldMapper;
if (setter.getPropertyType().isPrimitive()) {
fieldMapper = primitiveFieldMapperFactory.primitiveFieldMapper(column, setter, String.valueOf(column), fieldMapperErrorHandler);
} else {
fieldMapper = objectFieldMapper(column, setter, sqlType);
}
fields.add(fieldMapper);
}
private FieldMapper objectFieldMapper(String column, Setter setter, int sqlType) {
Class extends Object> type = setter.getPropertyType();
Getter getter = ResultSetGetterFactory.newGetter(type, column, sqlType);
if (getter == null) {
mapperBuilderErrorHandler.getterNotFound("No getter for column "
+ column + " type " + type);
return null;
} else {
return new FieldMapperImpl(column, getter,
setter, fieldMapperErrorHandler);
}
}
private FieldMapper objectFieldMapper(int column, Setter setter, int sqlType) {
Class extends Object> type = setter.getPropertyType();
Getter getter = ResultSetGetterFactory.newGetter(type, column, sqlType);
if (getter == null) {
mapperBuilderErrorHandler.getterNotFound("No getter for column "
+ column + " type " + type);
return null;
} else {
return new FieldMapperImpl(
String.valueOf(column), getter, setter,
fieldMapperErrorHandler);
}
}
private void removeNonMatchingConstructor(Parameter param) {
ListIterator> li = constructors.listIterator();
while(li.hasNext()){
ConstructorDefinition cd = li.next();
if (!cd.hasParam(param)) {
li.remove();
}
}
}
private Parameter hasMatchingConstructor(String column) {
if (constructors == null) return null;
for(ConstructorDefinition cd : constructors) {
Parameter param = cd.lookFor(new PropertyNameMatcher(column));
if (param != null) {
return param;
}
}
return null;
}
protected abstract Setter findSetter(String column);
protected abstract Setter getSetter(String property);
} © 2015 - 2025 Weber Informatics LLC | Privacy Policy