@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)); } } }
@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"); }
@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)"); }
@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); }
@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[] }
@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"); }
@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[]
@Before public void getHandle() { db = dbRule.getJdbi(); handle = dbRule.getHandle(); handle.registerRowMapper(ConstructorMapper.factory(User.class)); }
@Test public void columnMapper() { handle.registerColumnMapper(userNameFactory); handle.registerRowMapper(ConstructorMapper.factory(NamedUser.class)); NamedUser bob = handle.createQuery("SELECT id, name FROM user WHERE name = :name") .bind("name", "Bob") .mapTo(NamedUser.class) .findOnly(); assertThat(bob.name.name).isEqualTo("Bob"); } // end::columnMapper[]
@Test public void testOptionWithinObjectIfMissingShouldBeNone() { final SomethingWithOption result = dbRule.getSharedHandle() .registerRowMapper(ConstructorMapper.factory(SomethingWithOption.class)) .createQuery("select id, name from something where id = 2") .mapTo(SomethingWithOption.class) .findOnly(); assertThat(result.getName()).isInstanceOf(Option.class); assertThat(result).isEqualTo(new SomethingWithOption(2, Option.none())); }
@Test public void testOptionMappedWithinObjectIfPresentShouldContainValue() { final SomethingWithOption result = dbRule.getSharedHandle() .registerRowMapper(ConstructorMapper.factory(SomethingWithOption.class)) .createQuery("select id, name from something where id = 1") .mapTo(SomethingWithOption.class) .findOnly(); assertThat(result.getName()).isInstanceOf(Option.class); assertThat(result).isEqualTo(new SomethingWithOption(1, Option.of("eric"))); }
@Test public void nestedParameters() { assertThat(dbRule.getSharedHandle() .registerRowMapper(ConstructorMapper.factory(NestedBean.class)) .select("select s, i from bean") .mapTo(NestedBean.class) .findOnly()) .extracting("nested.s", "nested.i") .containsExactly("3", 2); }
@Test public void mapConstructorQualifiedParam() { dbRule.getJdbi() .registerColumnMapper(new ReversedStringMapper()) .registerRowMapper(ConstructorMapper.factory(QualifiedConstructorParamThing.class)) .useHandle(handle -> { handle.execute("INSERT INTO something (id, name) VALUES (1, 'abc')"); assertThat(handle.select("SELECT * FROM something") .mapTo(QualifiedConstructorParamThing.class) .findOnly()) .isEqualTo(new QualifiedConstructorParamThing(1, "cba")); }); }
@Test public void nestedParametersStrict() { Handle handle = dbRule.getSharedHandle(); handle.getConfig(ReflectionMappers.class).setStrictMatching(true); handle.registerRowMapper(ConstructorMapper.factory(NestedBean.class)); assertThat(dbRule.getSharedHandle() .registerRowMapper(ConstructorMapper.factory(NestedBean.class)) .select("select s, i from bean") .mapTo(NestedBean.class) .findOnly()) .extracting("nested.s", "nested.i") .containsExactly("3", 2); assertThatThrownBy(() -> handle .createQuery("select s, i, 1 as other from bean") .mapTo(NestedBean.class) .findOnly()) .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("could not match parameters for columns: [other]"); }
@Test public void nestedPrefixParametersStrict() { Handle handle = dbRule.getSharedHandle(); handle.getConfig(ReflectionMappers.class).setStrictMatching(true); handle.registerRowMapper(ConstructorMapper.factory(NestedPrefixBean.class)); assertThat(handle .createQuery("select i nested_i, s nested_s from bean") .mapTo(NestedPrefixBean.class) .findOnly()) .extracting("nested.s", "nested.i") .containsExactly("3", 2); assertThatThrownBy(() -> handle .createQuery("select i nested_i, s nested_s, 1 as other from bean") .mapTo(NestedPrefixBean.class) .findOnly()) .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("could not match parameters for columns: [other]"); assertThatThrownBy(() -> handle .createQuery("select i nested_i, s nested_s, 1 as nested_other from bean") .mapTo(NestedPrefixBean.class) .findOnly()) .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("could not match parameters for columns: [nested_other]"); }
@Test public void testNonUniqueIndexWithMultimap() { Handle h = dbRule.getSharedHandle(); h.execute("create table user (id int, name varchar)"); h.prepareBatch("insert into user (id, name) values (?, ?)") .add(1, "alice") .add(2, "bob") .add(3, "alice") .execute(); Multimap<String, User> usersByName = h.createQuery("select * from user") .setMapKeyColumn("name") .registerRowMapper(ConstructorMapper.factory(User.class)) .collectInto(new GenericType<Multimap<String, User>>() {}); assertThat(usersByName.apply("alice")).hasSize(2).containsExactly( new User(1, "alice"), new User(3, "alice") ); assertThat(usersByName.apply("bob")).hasSize(1).containsExactly( new User(2, "bob") ); }
@Test public void testMultipleExecuteBindFields() { h.registerRowMapper(ConstructorMapper.factory(PublicSomething.class)); final PreparedBatch b = h.prepareBatch("insert into something (id, name) values (:id, :name)"); b.bindFields(new PublicSomething(1, "Eric")).add(); b.bindFields(new PublicSomething(2, "Brian")).add(); b.execute(); // bindings should be cleared after execute() b.bindFields(new PublicSomething(3, "Keith")).add(); b.execute(); final List<PublicSomething> r = h.createQuery("select * from something order by id").mapTo(PublicSomething.class).list(); assertThat(r).extracting(s -> s.id, s -> s.name).containsExactly(tuple(1, "Eric"), tuple(2, "Brian"), tuple(3, "Keith")); }
@Test public void uniqueIndex() { h.execute("create table user (id int, name varchar)"); h.prepareBatch("insert into user (id, name) values (?, ?)") .add(1, "alice") .add(2, "bob") .add(3, "cathy") .add(4, "dilbert") .execute(); // tag::uniqueIndex[] Map<Integer, User> map = h.createQuery("select * from user") .setMapKeyColumn("id") .registerRowMapper(ConstructorMapper.factory(User.class)) .collectInto(new GenericType<Map<Integer, User>>() {}); // end::uniqueIndex[] assertThat(map).containsOnly( entry(1, new User(1, "alice")), entry(2, new User(2, "bob")), entry(3, new User(3, "cathy")), entry(4, new User(4, "dilbert"))); }
/** * from {@link org.jdbi.v3.core.mapper.MapEntryMapperTest} */ @Test public void uniqueIndex() { Handle h = dbRule.getSharedHandle(); h.execute("create table user (id int, name varchar)"); h.prepareBatch("insert into user (id, name) values (?, ?)") .add(1, "alice") .add(2, "bob") .add(3, "cathy") .add(4, "dilbert") .execute(); Map<Integer, User> map = h.createQuery("select * from user") .setMapKeyColumn("id") .registerRowMapper(ConstructorMapper.factory(User.class)) .collectInto(new GenericType<Map<Integer, User>>() {}); assertThat(map).containsOnly( Tuple.of(1, new User(1, "alice")), Tuple.of(2, new User(2, "bob")), Tuple.of(3, new User(3, "cathy")), Tuple.of(4, new User(4, "dilbert"))); }
@Test public void index() { h.execute("create table user (id int, manager_id int, name varchar)"); h.prepareBatch("insert into user (id, manager_id, name) values (?, ?, ?)") .add(1, 0, "alice") .add(2, 1, "bob") .add(3, 1, "cathy") .add(4, 3, "dilbert") .execute(); // tag::index[] Multimap<Integer, User> map = h.createQuery("select id, manager_id, name from user") .setMapKeyColumn("manager_id") .registerRowMapper(ConstructorMapper.factory(User.class)) .collectInto(new GenericType<Multimap<Integer, User>>() {}); // end::index[] Multimap<Integer, User> expected = ImmutableListMultimap.<Integer, User>builder() .put(0, new User(1, "alice")) .putAll(1, new User(2, "bob"), new User(3, "cathy")) .put(3, new User(4, "dilbert")) .build(); assertThat(map).isEqualTo(expected); }