@Override public void configureForType(ConfigRegistry registry, Annotation annotation, Class<?> sqlObjectType) { RegisterConstructorMapper registerConstructorMapper = (RegisterConstructorMapper) annotation; RowMappers mappers = registry.get(RowMappers.class); Class<?> type = registerConstructorMapper.value(); String prefix = registerConstructorMapper.prefix(); if (prefix.isEmpty()) { mappers.register(ConstructorMapper.factory(type)); } else { mappers.register(ConstructorMapper.factory(type, prefix)); } } }
/** * Return a ConstructorMapper using the given constructor * * @param <T> the type to map * @param constructor the constructor to be used in mapping * @return the mapper */ public static <T> RowMapper<T> of(Constructor<T> constructor) { return ConstructorMapper.of(constructor, DEFAULT_PREFIX); }
final Parameter parameter = parameters[i]; boolean nullable = isNullable(parameter); Nested anno = parameter.getAnnotation(Nested.class); if (anno == null) { final String paramName = prefix + paramName(parameters, i, constructorProperties); () -> debugName(parameter)); new ConstructorMapper<>(findFactoryFor(p.getType()), nestedPrefix)) .specialize0(ctx, columnNames, columnNameMatchers, unmatchedColumns); mappers[i] = (r, c) -> null; } else { unmatchedParameters.add(paramName(parameters, i, constructorProperties));
/** * Return a ConstructorMapper for the given type and prefix. * * @param <T> the type to map * @param type the mapped type * @param prefix the column name prefix * @return the mapper */ public static <T> RowMapper<T> of(Class<T> type, String prefix) { return new ConstructorMapper<>(findFactoryFor(type), prefix); }
final String paramName = paramName(constructor.getParameters(), i, constructorProperties); final int columnIndex = columnIndexForParameter(columnNames, paramName, columnNameMatchers);
@Override public T map(ResultSet rs, StatementContext ctx) throws SQLException { return specialize(rs, ctx).map(rs, ctx); }
/** * Instantiate a ConstructorMapper using the given constructor and prefix * * @param <T> the type to map * @param constructor the constructor to be used in mapping * @param prefix the column name prefix * @return the mapper */ public static <T> RowMapper<T> of(Constructor<T> constructor, String prefix) { return new ConstructorMapper<>(new ConstructorInstanceFactory<>(constructor), prefix); }
@Override public T map(ResultSet rs, StatementContext ctx) throws SQLException { return specialize(rs, ctx).map(rs, ctx); }
@Test public void testMultipleFactoryMethods() { assertThatThrownBy(() -> ConstructorMapper.factory(MultipleStaticFactoryMethodsBean.class)) .isInstanceOf(IllegalArgumentException.class) .hasMessageMatching("class .* may have at most one constructor or static factory method annotated @JdbiConstructor"); }
/** * Return a ConstructorMapper for the given type. * * @param <T> the type to map * @param type the mapped type * @return the mapper */ public static <T> RowMapper<T> of(Class<T> type) { return ConstructorMapper.of(type, DEFAULT_PREFIX); }
/** * Instantiate a ConstructorMapper using the given constructor and prefix * * @param <T> the type to map * @param constructor the constructor to be used in mapping * @param prefix the column name prefix * @return the mapper */ public static <T> RowMapper<T> of(Constructor<T> constructor, String prefix) { return new ConstructorMapper<>(constructor, prefix); }
@Before public void setUp() { dbRule.getSharedHandle() .registerRowMapper(ConstructorMapper.factory(ConstructorBean.class)) .registerRowMapper(ConstructorMapper.factory(ConstructorPropertiesBean.class)) .registerRowMapper(ConstructorMapper.factory(NamedParameterBean.class)) .registerRowMapper(ConstructorMapper.factory(NullableNestedBean.class)) .registerRowMapper(ConstructorMapper.factory(NullableParameterBean.class)) .registerRowMapper(ConstructorMapper.factory(StaticFactoryMethodBean.class)); dbRule.getSharedHandle().execute("CREATE TABLE bean (s varchar, i integer)"); dbRule.getSharedHandle().execute("INSERT INTO bean VALUES('3', 2)"); }
/** * Use a {@code Constructor<T>} to map its declaring type. * * @param constructor the constructor to invoke * @return the factory */ public static RowMapperFactory factory(Constructor<?> constructor) { return RowMapperFactory.of(constructor.getDeclaringClass(), ConstructorMapper.of(constructor)); }
@Test public void nestedPrefixParameters() { NestedPrefixBean result = dbRule.getSharedHandle() .registerRowMapper(ConstructorMapper.factory(NestedPrefixBean.class)) .select("select i nested_i, s nested_s from bean") .mapTo(NestedPrefixBean.class) .findOnly(); assertThat(result.nested.s).isEqualTo("3"); assertThat(result.nested.i).isEqualTo(2); }
/** * Use the only declared constructor to map a class. * * @param clazz the class to find a constructor of * @param prefix a prefix for the parameter names * @return the factory */ public static RowMapperFactory factory(Class<?> clazz, String prefix) { return RowMapperFactory.of(clazz, ConstructorMapper.of(clazz, prefix)); }
@Test public void testOptionMappedWithoutGenericParameterShouldFail() { assertThatThrownBy(() -> dbRule.getSharedHandle() .registerRowMapper(ConstructorMapper.factory(SomethingWithOption.class)) .createQuery("select name from something") .collectInto(new GenericType<Set<Option>>() {})) .isInstanceOf(NoSuchMapperException.class) .hasMessageContaining("raw"); }
/** * Use the only declared constructor to map a class. * * @param clazz the class to find a constructor of * @return the factory */ public static RowMapperFactory factory(Class<?> clazz) { return RowMapperFactory.of(clazz, ConstructorMapper.of(clazz)); }
@Test public void constructorMapper() { // tag::constructorMapper[] handle.registerRowMapper(ConstructorMapper.factory(User.class)); Set<User> userSet = handle.createQuery("SELECT * FROM user ORDER BY id ASC") .mapTo(User.class) .collect(Collectors.toSet()); assertThat(userSet).hasSize(4); // end::constructorMapper[] }
/** * Use a {@code Constructor<T>} to map its declaring type. * * @param constructor the constructor to invoke * @param prefix a prefix to the constructor parameter names * @return the factory */ public static RowMapperFactory factory(Constructor<?> constructor, String prefix) { return RowMapperFactory.of(constructor.getDeclaringClass(), ConstructorMapper.of(constructor, prefix)); }
@Before public void setUp() { db.useHandle(h -> h.execute("CREATE TABLE users (id SERIAL PRIMARY KEY, name VARCHAR)")); db.registerRowMapper(ConstructorMapper.factory(User.class)); } // end::setup[]