diff --git a/core/src/main/java/org/jdbi/v3/core/argument/ObjectFieldArguments.java b/core/src/main/java/org/jdbi/v3/core/argument/ObjectFieldArguments.java index 4d1ab25a55..4e4e0b1d0c 100644 --- a/core/src/main/java/org/jdbi/v3/core/argument/ObjectFieldArguments.java +++ b/core/src/main/java/org/jdbi/v3/core/argument/ObjectFieldArguments.java @@ -41,7 +41,7 @@ public class ObjectFieldArguments extends ObjectPropertyNamedArgumentFinder { JdbiCaches.declare((config, beanClass) -> Stream.of(beanClass.getFields()) .collect(Collectors.toMap(Field::getName, f -> { - QualifiedType qualifiedType = QualifiedType.of(f.getType()) + QualifiedType qualifiedType = QualifiedType.of(f.getGenericType()) .withAnnotations(config.get(Qualifiers.class).findFor(f)); Function getter = Unchecked.function( Unchecked.function(MethodHandles.lookup()::unreflectGetter).apply(f)::invoke); diff --git a/core/src/main/java/org/jdbi/v3/core/argument/ObjectMethodArguments.java b/core/src/main/java/org/jdbi/v3/core/argument/ObjectMethodArguments.java index 50361a87c9..d50bd4419b 100644 --- a/core/src/main/java/org/jdbi/v3/core/argument/ObjectMethodArguments.java +++ b/core/src/main/java/org/jdbi/v3/core/argument/ObjectMethodArguments.java @@ -60,7 +60,7 @@ private static Map> load(ConfigRegistry con Function.identity(), ObjectMethodArguments::bridgeMethodMerge)) .forEach((name, method) -> { - QualifiedType qualifiedType = QualifiedType.of(method.getReturnType()) + QualifiedType qualifiedType = QualifiedType.of(method.getGenericReturnType()) .withAnnotations(config.get(Qualifiers.class).findFor(method)); MethodHandle mh = Unchecked.function(MethodHandles.lookup()::unreflect).apply(method); methodMap.put(name, Unchecked.function( diff --git a/core/src/main/java/org/jdbi/v3/core/h2/H2DatabasePlugin.java b/core/src/main/java/org/jdbi/v3/core/h2/H2DatabasePlugin.java index 6ede9da236..fbe6d1fe71 100644 --- a/core/src/main/java/org/jdbi/v3/core/h2/H2DatabasePlugin.java +++ b/core/src/main/java/org/jdbi/v3/core/h2/H2DatabasePlugin.java @@ -26,7 +26,18 @@ public class H2DatabasePlugin extends JdbiPlugin.Singleton { @Override public void customizeJdbi(Jdbi db) { db.setSqlArrayArgumentStrategy(SqlArrayArgumentStrategy.OBJECT_ARRAY); - db.registerArrayType(UUID.class, "uuid"); - db.registerArrayType(int.class, "integer"); + db.registerArrayType(UUID.class, "uuid") + .registerArrayType(short.class, "smallint") + .registerArrayType(Short.class, "smallint") + .registerArrayType(int.class, "integer") + .registerArrayType(Integer.class, "integer") + .registerArrayType(long.class, "bigint") + .registerArrayType(Long.class, "bigint") + .registerArrayType(String.class, "varchar") + .registerArrayType(UUID.class, "uuid") + .registerArrayType(float.class, "float4") + .registerArrayType(Float.class, "float4") + .registerArrayType(double.class, "float8") + .registerArrayType(Double.class, "float8"); } } diff --git a/generator/src/main/java/org/jdbi/v3/generator/GenerateSqlObjectProcessor.java b/generator/src/main/java/org/jdbi/v3/generator/GenerateSqlObjectProcessor.java index 675d07b590..f0e6bf4a33 100644 --- a/generator/src/main/java/org/jdbi/v3/generator/GenerateSqlObjectProcessor.java +++ b/generator/src/main/java/org/jdbi/v3/generator/GenerateSqlObjectProcessor.java @@ -113,6 +113,7 @@ private void generate(Element sqlObjE) throws IOException { .forEach(implSpec::addMethod); final TypeSpec.Builder onDemand = TypeSpec.classBuilder("OnDemand"); + onDemand.addSuperinterface(SqlObject.class); onDemand.addModifiers(Modifier.PUBLIC, Modifier.STATIC); onDemand.addField(Jdbi.class, "db", Modifier.PRIVATE, Modifier.FINAL); onDemand.addMethod(MethodSpec.constructorBuilder() @@ -194,10 +195,11 @@ private MethodSpec generateMethod(TypeSpec.Builder typeBuilder, CodeBlock.Builde private MethodSpec generateOnDemand(TypeElement sqlObjectType, ExecutableElement method) { return MethodSpec.overriding(method) .addCode(CodeBlock.builder() - .add("$L db.$L($T.class, e -> e.$L($L));\n", + .add("$L db.$L($T.class, e -> (($L) e).$L($L));\n", method.getReturnType().getKind() == TypeKind.VOID ? "" : ("return (" + method.getReturnType().toString() + ")"), // NOPMD method.getReturnType().getKind() == TypeKind.VOID ? "useExtension" : "withExtension", sqlObjectType.asType(), + sqlObjectType.getSimpleName() + "Impl", method.getSimpleName(), paramList(method)) .build()) diff --git a/generator/src/test/java/org/jdbi/v3/generator/ArrayBindingTest.java b/generator/src/test/java/org/jdbi/v3/generator/ArrayBindingTest.java new file mode 100644 index 0000000000..2f51f1e36b --- /dev/null +++ b/generator/src/test/java/org/jdbi/v3/generator/ArrayBindingTest.java @@ -0,0 +1,88 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jdbi.v3.generator; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import org.jdbi.v3.core.Handle; +import org.jdbi.v3.core.rule.H2DatabaseRule; +import org.jdbi.v3.sqlobject.GenerateSqlObject; +import org.jdbi.v3.sqlobject.config.RegisterConstructorMapper; +import org.jdbi.v3.sqlobject.customizer.BindFields; +import org.jdbi.v3.sqlobject.statement.SqlQuery; +import org.jdbi.v3.sqlobject.statement.SqlUpdate; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ArrayBindingTest { + @Rule + public H2DatabaseRule dbRule = GeneratorH2Rule.rule(); + + private Handle handle; + private BazDao dao; + + @Before + public void setUp() { + handle = dbRule.getSharedHandle(); + handle.execute("create table baz (baz array)"); + dao = handle.attach(BazDao.class); + } + + @Test + public void simpleGeneratedClass() { + final Baz baz1 = new Baz(1, 2, 3); + dao.insert(baz1); + final Baz baz2 = new Baz(2, 3, 4); + dao.insert(baz2); + + assertThat(dao.list()) + .containsExactlyInAnyOrder(baz1, baz2); + } + + @GenerateSqlObject + @RegisterConstructorMapper(Baz.class) + interface BazDao { + @SqlUpdate("insert into baz (baz) values (:baz)") + void insert(@BindFields Baz value); + + @SqlQuery("select baz from baz") + List list(); + } + + public static class Baz { + public Baz(final int... baz) { + this.baz = IntStream.of(baz) + .boxed() + .collect(Collectors.toList()); + } + + public final List baz; + + @Override + public int hashCode() { + return baz.hashCode(); + } + + @Override + public boolean equals(final Object obj) { + return obj instanceof Baz && Objects.equals(((Baz) obj).baz, baz); + } + } +} diff --git a/generator/src/test/java/org/jdbi/v3/generator/GeneratorH2Rule.java b/generator/src/test/java/org/jdbi/v3/generator/GeneratorH2Rule.java new file mode 100644 index 0000000000..c869ac20fb --- /dev/null +++ b/generator/src/test/java/org/jdbi/v3/generator/GeneratorH2Rule.java @@ -0,0 +1,28 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jdbi.v3.generator; + +import org.jdbi.v3.core.extension.Extensions; +import org.jdbi.v3.core.h2.H2DatabasePlugin; +import org.jdbi.v3.core.rule.H2DatabaseRule; +import org.jdbi.v3.sqlobject.SqlObjectPlugin; + +public class GeneratorH2Rule { + public static H2DatabaseRule rule() { + return new H2DatabaseRule() + .withPlugin(new H2DatabasePlugin()) + .withPlugin(new SqlObjectPlugin()) + .withConfig(Extensions.class, c -> c.setAllowProxy(false)); + } +} diff --git a/generator/src/test/java/org/jdbi/v3/generator/NonpublicSubclassTest.java b/generator/src/test/java/org/jdbi/v3/generator/NonpublicSubclassTest.java index bd341af573..b7f5edd78e 100644 --- a/generator/src/test/java/org/jdbi/v3/generator/NonpublicSubclassTest.java +++ b/generator/src/test/java/org/jdbi/v3/generator/NonpublicSubclassTest.java @@ -27,12 +27,10 @@ import org.jdbi.v3.core.Something; import org.jdbi.v3.core.config.ConfigRegistry; import org.jdbi.v3.core.config.JdbiConfig; -import org.jdbi.v3.core.extension.Extensions; import org.jdbi.v3.core.mapper.SomethingMapper; import org.jdbi.v3.core.rule.H2DatabaseRule; import org.jdbi.v3.sqlobject.GenerateSqlObject; import org.jdbi.v3.sqlobject.SqlObject; -import org.jdbi.v3.sqlobject.SqlObjectPlugin; import org.jdbi.v3.sqlobject.config.Configurer; import org.jdbi.v3.sqlobject.config.ConfiguringAnnotation; import org.jdbi.v3.sqlobject.statement.SqlQuery; @@ -45,8 +43,7 @@ public class NonpublicSubclassTest { @Rule - public H2DatabaseRule dbRule = new H2DatabaseRule().withPlugin(new SqlObjectPlugin()).withSomething() - .withConfig(Extensions.class, c -> c.setAllowProxy(false)); + public H2DatabaseRule dbRule = GeneratorH2Rule.rule().withSomething(); private Handle handle; private AbstractClassDao dao; diff --git a/postgres/src/main/java/org/jdbi/v3/postgres/PostgresPlugin.java b/postgres/src/main/java/org/jdbi/v3/postgres/PostgresPlugin.java index 23033c4de5..5b2ed4243b 100644 --- a/postgres/src/main/java/org/jdbi/v3/postgres/PostgresPlugin.java +++ b/postgres/src/main/java/org/jdbi/v3/postgres/PostgresPlugin.java @@ -113,6 +113,8 @@ public void customizeJdbi(Jdbi jdbi) { jdbi.registerArgument(new BlobInputStreamArgumentFactory()); jdbi.registerArgument(new ClobReaderArgumentFactory()); + jdbi.registerArrayType(short.class, "smallint"); + jdbi.registerArrayType(Short.class, "smallint"); jdbi.registerArrayType(int.class, "integer"); jdbi.registerArrayType(Integer.class, "integer"); jdbi.registerArrayType(long.class, "bigint"); diff --git a/sqlobject/src/main/java/org/jdbi/v3/sqlobject/internal/SqlObjectInitData.java b/sqlobject/src/main/java/org/jdbi/v3/sqlobject/internal/SqlObjectInitData.java index 8f6fd7c29f..ade214eb46 100644 --- a/sqlobject/src/main/java/org/jdbi/v3/sqlobject/internal/SqlObjectInitData.java +++ b/sqlobject/src/main/java/org/jdbi/v3/sqlobject/internal/SqlObjectInitData.java @@ -29,6 +29,7 @@ import org.jdbi.v3.core.internal.exceptions.Sneaky; import org.jdbi.v3.sqlobject.GenerateSqlObject; import org.jdbi.v3.sqlobject.Handler; +import org.jdbi.v3.sqlobject.SqlObject; import org.jdbi.v3.sqlobject.UnableToCreateSqlObjectException; public final class SqlObjectInitData { @@ -77,6 +78,11 @@ private static Method lookupMethod(Class klass, String methodName, Class.. return klass.getDeclaredMethod(methodName, parameterTypes); } catch (Exception x) { e.addSuppressed(x); + try { + return SqlObject.class.getMethod(methodName, parameterTypes); + } catch (Exception x2) { + e.addSuppressed(x2); + } } throw new IllegalStateException( String.format("can't find %s#%s%s", klass.getName(), methodName, Arrays.asList(parameterTypes)), e);