All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sfm.jdbc.JdbcMapperBuilder Maven / Gradle / Ivy

package org.sfm.jdbc;

import org.sfm.jdbc.impl.*;
import org.sfm.jdbc.impl.getter.ResultSetGetterFactory;
import org.sfm.map.*;
import org.sfm.map.impl.*;
import org.sfm.reflect.Instantiator;
import org.sfm.reflect.ReflectionService;
import org.sfm.reflect.TypeReference;
import org.sfm.reflect.meta.ClassMeta;
import org.sfm.reflect.meta.PropertyNameMatcherFactory;
import org.sfm.tuples.Tuple2;
import org.sfm.utils.ErrorHelper;

import java.lang.reflect.Type;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;

/**
 * @param  the targeted type of the mapper
 */
public final class JdbcMapperBuilder extends AbstractFieldMapperMapperBuilder {

    public static final int NO_ASM_MAPPER_THRESHOLD = 792; // see https://github.com/arnaudroger/SimpleFlatMapper/issues/152
    public static final JdbcColumnKey[] EMPTY_COLUMNKEYS = new JdbcColumnKey[0];

    private int calculatedIndex = 1;
    private RowHandlerErrorHandler jdbcMapperErrorHandler = new RethrowRowHandlerErrorHandler();
    private final boolean failOnAsm;
    private final int asmMapperNbFieldsLimit;

    /**
     * Build a new JdbcMapperBuilder targeting the type specified by the TypeReference. The TypeReference
     * allow you to provide a generic type with check of T
* new TypeReference<List<String>>() {} * * @param target the TypeReference to the type T to map to */ public JdbcMapperBuilder(final TypeReference target) { this(target.getType()); } /** * Build a new JdbcMapperBuilder targeting the specified type. * * @param target the type */ public JdbcMapperBuilder(final Type target) { this(target, ReflectionService.newInstance()); } /** * Build a new JdbcMapperBuilder targeting the specified type with the specified ReflectionService. * * @param target the type * @param reflectService the ReflectionService */ public JdbcMapperBuilder(final Type target, ReflectionService reflectService) { this(reflectService.getRootClassMeta(target), new RethrowMapperBuilderErrorHandler(), new IdentityFieldMapperColumnDefinitionProvider(), new DefaultPropertyNameMatcherFactory(), new ResultSetGetterFactory(), false, NO_ASM_MAPPER_THRESHOLD, new JdbcMappingContextFactoryBuilder()); } /** * @param classMeta the meta for the target class. * @param mapperBuilderErrorHandler the error handler. * @param columnDefinitions the predefined ColumnDefinition. * @param propertyNameMatcherFactory the PropertyNameMatcher factory. * @param getterFactory the Getter factory. * @param failOnAsm should we fail on asm generation. * @param parentBuilder the parent builder, null if none. */ public JdbcMapperBuilder(final ClassMeta classMeta, final MapperBuilderErrorHandler mapperBuilderErrorHandler, final ColumnDefinitionProvider, JdbcColumnKey> columnDefinitions, PropertyNameMatcherFactory propertyNameMatcherFactory, GetterFactory getterFactory, boolean failOnAsm, int asmMapperNbFieldsLimit, MappingContextFactoryBuilder parentBuilder) { super(ResultSet.class, classMeta, getterFactory, new ResultSetFieldMapperFactory(getterFactory), columnDefinitions, propertyNameMatcherFactory, mapperBuilderErrorHandler, parentBuilder); this.failOnAsm = failOnAsm; this.asmMapperNbFieldsLimit = asmMapperNbFieldsLimit; } /** * @return a new instance of the mapper based on the current state of the builder. */ @Override public JdbcMapper mapper() { JdbcMapper mapper = buildMapper(); if (!mappingContextFactoryBuilder.isRoot() || mappingContextFactoryBuilder.hasNoDependentKeys()) { return mapper; } else { return new JoinJdbcMapper(mapper, jdbcMapperErrorHandler); } } private JdbcMapper buildMapper() { FieldMapper[] fields = fields(); Tuple2[], Instantiator> constructorFieldMappersAndInstantiator = getConstructorFieldMappersAndInstantiator(); MappingContextFactory mappingContextFactory = null; if (mappingContextFactoryBuilder.isRoot()) { mappingContextFactory = mappingContextFactoryBuilder.newFactory(); } if (isEligibleForAsmMapper()) { try { return reflectionService.getAsmFactory().createJdbcMapper( getKeys(), fields, constructorFieldMappersAndInstantiator.first(), constructorFieldMappersAndInstantiator.second(), getTargetClass(), jdbcMapperErrorHandler, mappingContextFactory); } catch (Exception e) { if (failOnAsm) { return ErrorHelper.rethrow(e); } else { return new JdbcMapperImpl(fields, constructorFieldMappersAndInstantiator.first(), constructorFieldMappersAndInstantiator.second(), jdbcMapperErrorHandler, mappingContextFactory); } } } else { return new JdbcMapperImpl(fields, constructorFieldMappersAndInstantiator.first(), constructorFieldMappersAndInstantiator.second(), jdbcMapperErrorHandler, mappingContextFactory); } } private JdbcColumnKey[] getKeys() { return propertyMappingsBuilder.getKeys().toArray(EMPTY_COLUMNKEYS); } private boolean isEligibleForAsmMapper() { return reflectionService.isAsmActivated() && propertyMappingsBuilder.size() < asmMapperNbFieldsLimit; } /** * add a new mapping to the specified column with a key column definition and an undefined type. * The index is incremented for each non indexed column mapping. * * @param column the column name * @return the current builder */ public JdbcMapperBuilder addKey(String column) { return addMapping(column, calculatedIndex++, FieldMapperColumnDefinition.key()); } /** * add a new mapping to the specified column with an undefined type. The index is incremented for each non indexed column mapping. * * @param column the column name * @return the current builder */ public JdbcMapperBuilder addMapping(String column) { return addMapping(column, calculatedIndex++); } /** * add a new mapping to the specified column with the specified columnDefinition and an undefined type. The index is incremented for each non indexed column mapping. * * @param column the column name * @param columnDefinition the definition * @return the current builder */ public JdbcMapperBuilder addMapping(final String column, final FieldMapperColumnDefinition columnDefinition) { return addMapping(column, calculatedIndex++, columnDefinition); } /** * add a new mapping to the specified column with the specified index and an undefined type. * * @param column the column name * @param index the column index * @return the current builder */ public JdbcMapperBuilder addMapping(String column, int index) { return addMapping(column, index, JdbcColumnKey.UNDEFINED_TYPE); } /** * add a new mapping to the specified column with the specified index, specified column definition and an undefined type. * * @param column the column name * @param index the column index * @param columnDefinition the column definition * @return the current builder */ public JdbcMapperBuilder addMapping(String column, int index, final FieldMapperColumnDefinition columnDefinition) { return addMapping(column, index, JdbcColumnKey.UNDEFINED_TYPE, columnDefinition); } /** * append a FieldMapper to the mapping list. * * @param mapper the field mapper * @return the current builder */ public JdbcMapperBuilder addMapper(FieldMapper mapper) { _addMapper(mapper); return this; } /** * add a new mapping to the specified column with the specified index and the specified type. * * @param column the column name * @param index the column index * @param sqlType the column type, @see java.sql.Types * @return the current builder */ public JdbcMapperBuilder addMapping(final String column, final int index, final int sqlType) { addMapping(column, index, sqlType, FieldMapperColumnDefinition.identity()); return this; } /** * add a new mapping to the specified column with the specified index, the specified type. * * @param column the column name * @param index the column index * @param sqlType the column type, @see java.sql.Types * @param columnDefinition the column definition * @return the current builder */ public JdbcMapperBuilder addMapping(final String column, final int index, final int sqlType, FieldMapperColumnDefinition columnDefinition) { _addMapping(new JdbcColumnKey(column, index, sqlType), columnDefinition); return this; } /** * add the all the column present in the metaData * * @param metaData the metaDAta * @return the current builder * @throws SQLException when an error occurs getting the metaData */ public JdbcMapperBuilder addMapping(final ResultSetMetaData metaData) throws SQLException { for (int i = 1; i <= metaData.getColumnCount(); i++) { addMapping(metaData.getColumnLabel(i), i, metaData.getColumnType(i)); } return this; } @Override protected AbstractFieldMapperMapperBuilder newSubBuilder(Type type, ClassMeta classMeta, MappingContextFactoryBuilder mappingContextFactoryBuilder) { return new JdbcMapperBuilder(classMeta, mapperBuilderErrorHandler, columnDefinitions, propertyNameMatcherFactory, new ResultSetGetterFactory(), failOnAsm, asmMapperNbFieldsLimit, mappingContextFactoryBuilder); } /** * the FieldMapperErrorHandler is called when a error occurred when mapping a field from the source to the target. * By default it just throw the Exception. * @param errorHandler the new FieldMapperErrorHandler * @return the current builder */ public JdbcMapperBuilder fieldMapperErrorHandler(FieldMapperErrorHandler errorHandler) { setFieldMapperErrorHandler(errorHandler); return this; } /** * the RowHandlerErrorHandler is called when an exception is thrown by the RowHandler in the forEach call. * @param jdbcMapperErrorHandler the new RowHandlerErrorHandler * @return the current builder */ public JdbcMapperBuilder jdbcMapperErrorHandler(RowHandlerErrorHandler jdbcMapperErrorHandler) { this.jdbcMapperErrorHandler = jdbcMapperErrorHandler; return this; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy