@Override public void configureForType(ConfigRegistry registry, Annotation annotation, Class<?> sqlObjectType) { RegisterFieldMapper registerFieldMapper = (RegisterFieldMapper) annotation; Class<?> type = registerFieldMapper.value(); String prefix = registerFieldMapper.prefix(); RowMappers mappers = registry.get(RowMappers.class); if (prefix.isEmpty()) { mappers.register(FieldMapper.factory(type)); } else { mappers.register(FieldMapper.factory(type, prefix)); } }
/** * Returns a mapper for the given bean class * * @param <T> the type to map * @param type the mapped class * @return a mapper for the given bean class */ public static <T> RowMapper<T> of(Class<T> type) { return FieldMapper.of(type, DEFAULT_PREFIX); }
Nested anno = field.getAnnotation(Nested.class); if (anno == null) { String paramName = prefix + paramName(field); findColumnIndex(paramName, columnNames, columnNameMatchers, () -> debugName(field)) .ifPresent(index -> { QualifiedType<?> type = QualifiedType.of(field.getGenericType()) .computeIfAbsent(field, f -> new FieldMapper<>(field.getType(), nestedPrefix)) .specialize0(ctx, columnNames, columnNameMatchers, unmatchedColumns) .ifPresent(mapper -> { mappers.add(mapper); T obj = construct(); writeField(obj, field, value);
/** * Returns a mapper for the given bean class * * @param <T> the type to map * @param type the mapped class * @param prefix the column name prefix for each mapped field * @return a mapper for the given bean class */ public static <T> RowMapper<T> of(Class<T> type, String prefix) { return new FieldMapper<>(type, prefix); }
@Override public T map(ResultSet rs, StatementContext ctx) throws SQLException { return specialize(rs, ctx).map(rs, ctx); }
private Optional<Field> fieldByColumn(String columnName, List<ColumnNameMatcher> columnNameMatchers) { Class<?> aClass = type; while(aClass != null) { for (Field field : aClass.getDeclaredFields()) { String paramName = paramName(field); for (ColumnNameMatcher strategy : columnNameMatchers) { if (strategy.columnNameMatches(columnName, paramName)) { return Optional.of(field); } } } aClass = aClass.getSuperclass(); } return Optional.empty(); }
@Override public RowMapper<T> specialize(ResultSet rs, StatementContext ctx) throws SQLException { final List<String> columnNames = getColumnNames(rs); final List<ColumnNameMatcher> columnNameMatchers = ctx.getConfig(ReflectionMappers.class).getColumnNameMatchers(); final List<String> unmatchedColumns = new ArrayList<>(columnNames); RowMapper<T> mapper = specialize0(ctx, columnNames, columnNameMatchers, unmatchedColumns) .orElseThrow(() -> new IllegalArgumentException(String.format(NO_MATCHING_COLUMNS, type))); if (ctx.getConfig(ReflectionMappers.class).isStrictMatching() && anyColumnsStartWithPrefix(unmatchedColumns, prefix, columnNameMatchers)) { throw new IllegalArgumentException( String.format(UNMATCHED_COLUMNS_STRICT, type.getSimpleName(), unmatchedColumns)); } return mapper; }
Optional<Field> maybeField = fieldByNameCache.computeIfAbsent(name, n -> fieldByColumn(n, columnNameMatchers));
/** * Returns a mapper for the given bean class * * @param <T> the type to map * @param type the mapped class * @param prefix the column name prefix for each mapped field * @return a mapper for the given bean class */ public static <T> RowMapper<T> of(Class<T> type, String prefix) { return new FieldMapper<>(type, prefix); }
@Override public T map(ResultSet rs, StatementContext ctx) throws SQLException { return specialize(rs, ctx).map(rs, ctx); }
@Test public void testNoRecognizedColumns() { Handle handle = dbRule.getSharedHandle(); assertThatThrownBy(() -> handle .registerRowMapper(FieldMapper.factory(NullableNestedThing.class)) .select("SELECT 'foo' bar") .mapTo(NullableNestedThing.class) .findOnly()) .isInstanceOf(IllegalArgumentException.class); }
/** * Returns a mapper factory that maps to the given bean class * * @param type the mapped class * @return a mapper factory that maps to the given bean class */ public static RowMapperFactory factory(Class<?> type) { return RowMapperFactory.of(type, FieldMapper.of(type)); }
@Before public void setUp() { Handle handle = dbRule.getSharedHandle(); handle.registerRowMapper(FieldMapper.factory(TestBindBeanList.Thing.class)); handle.execute("create table thing (id identity primary key, foo varchar(50), bar varchar(50), baz varchar(50))"); }
/** * Returns a mapper factory that maps to the given bean class * * @param type the mapped class * @param prefix the column name prefix for each mapped field * @return a mapper factory that maps to the given bean class */ public static RowMapperFactory factory(Class<?> type, String prefix) { return RowMapperFactory.of(type, FieldMapper.of(type, prefix)); }
@Test public void testNestedHalfPresent() { Handle handle = dbRule.getSharedHandle(); assertThat(handle .registerRowMapper(FieldMapper.factory(NullableNestedThing.class)) .select("SELECT 42 as testValue, '3' as s") .mapTo(NullableNestedThing.class) .findOnly()) .extracting("testValue", "nested.i", "nested.s") .containsExactly(42, null, "3"); }
@Test public void shouldSetValuesInSuperClassFields() throws Exception { mockColumns("longField", "blongField"); Long aLongVal = 100L; Long bLongVal = 200L; when(resultSet.getLong(1)).thenReturn(aLongVal); when(resultSet.getLong(2)).thenReturn(bLongVal); when(resultSet.wasNull()).thenReturn(false); RowMapper<DerivedBean> mapper = FieldMapper.of(DerivedBean.class); DerivedBean derivedBean = mapper.map(resultSet, ctx); assertThat(derivedBean.getLongField()).isEqualTo(aLongVal); assertThat(derivedBean.getBlongField()).isEqualTo(bLongVal); }
@Test public void testNestedPresent() { Handle handle = dbRule.getSharedHandle(); assertThat(handle .registerRowMapper(FieldMapper.factory(NullableNestedThing.class)) .select("SELECT 42 as testValue, 2 as i, '3' as s") .mapTo(NullableNestedThing.class) .findOnly()) .extracting("testValue", "nested.i", "nested.s") .containsExactly(42, 2, "3"); }
@Test public void testColumnNameAnnotation() { Handle handle = dbRule.getSharedHandle(); handle.execute("insert into something (id, name) values (1, 'foo')"); ColumnNameThing thing = handle.createQuery("select * from something") .map(FieldMapper.of(ColumnNameThing.class)) .findOnly(); assertThat(thing.i).isEqualTo(1); assertThat(thing.s).isEqualTo("foo"); }
@Test public void testNestedAbsent() { Handle handle = dbRule.getSharedHandle(); assertThat(handle .registerRowMapper(FieldMapper.factory(NullableNestedThing.class)) .select("SELECT 42 as testValue") .mapTo(NullableNestedThing.class) .findOnly()) .extracting("testValue", "nested") .containsExactly(42, null); }
/** * Returns a mapper for the given bean class * * @param <T> the type to map * @param type the mapped class * @return a mapper for the given bean class */ public static <T> RowMapper<T> of(Class<T> type) { return FieldMapper.of(type, DEFAULT_PREFIX); }