From afbf75aee61dc1e7ea184aa213c8b847f7a6f8c9 Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Mon, 28 Apr 2014 10:46:39 +0200 Subject: [PATCH] [#3212] Add support for value types in DefaultRecordMapper, when mapping Record1 types --- .../org/jooq/test/_/testcases/FetchTests.java | 22 +++++++++++ .../src/org/jooq/test/jOOQAbstractTest.java | 5 +++ .../java/org/jooq/impl/DefaultDataType.java | 9 +++++ .../org/jooq/impl/DefaultRecordMapper.java | 38 +++++++++++++++++++ .../java/org/jooq/test/RecordMappingTest.java | 24 +++++++++++- 5 files changed, 97 insertions(+), 1 deletion(-) diff --git a/jOOQ-test/src/org/jooq/test/_/testcases/FetchTests.java b/jOOQ-test/src/org/jooq/test/_/testcases/FetchTests.java index bdd345d90e..13a0512e87 100644 --- a/jOOQ-test/src/org/jooq/test/_/testcases/FetchTests.java +++ b/jOOQ-test/src/org/jooq/test/_/testcases/FetchTests.java @@ -1834,6 +1834,28 @@ extends BaseTest> result = + create().select(TBook_ID()) + .from(TBook()) + .orderBy(TBook_ID()) + .fetch(); + + assertEquals(BOOK_IDS, result.into(int.class)); + assertEquals(BOOK_IDS, result.into(Integer.class)); + assertEquals(BOOK_IDS_SHORT, result.into(short.class)); + assertEquals(BOOK_IDS_SHORT, result.into(Short.class)); + assertEquals(BOOK_IDS_STRING, result.into(String.class)); + + try { + create().selectFrom(TBook()) + .fetchInto(int.class); + fail(); + } + catch (MappingException expected) {} + } + @Test public void testFetchIntoResultSet() throws Exception { Result result = create().selectFrom(TBook()).orderBy(TBook_ID()).fetch(); diff --git a/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java b/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java index 09cb917a17..064d2b369c 100644 --- a/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java +++ b/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java @@ -1592,6 +1592,11 @@ public abstract class jOOQAbstractTest< new FetchTests(this).testFetchIntoGeneratedPojos(); } + @Test + public void testFetchIntoValueType() throws Exception { + new FetchTests(this).testFetchIntoValueType(); + } + @Test public void testFetchIntoRecordHandler() throws Exception { new FetchTests(this).testFetchIntoRecordHandler(); diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultDataType.java b/jOOQ/src/main/java/org/jooq/impl/DefaultDataType.java index 4531721040..1ea9e19932 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultDataType.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultDataType.java @@ -40,6 +40,7 @@ */ package org.jooq.impl; +import static java.util.Collections.unmodifiableCollection; import static org.jooq.impl.SQLDataType.BLOB; import static org.jooq.impl.SQLDataType.CLOB; import static org.jooq.impl.SQLDataType.NCLOB; @@ -849,4 +850,12 @@ public class DefaultDataType implements DataType { return BigDecimal.class; } } + + static Collection> types() { + return unmodifiableCollection(SQL_DATATYPES_BY_TYPE.keySet()); + } + + static Collection> dataTypes() { + return unmodifiableCollection(SQL_DATATYPES_BY_TYPE.values()); + } } diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultRecordMapper.java b/jOOQ/src/main/java/org/jooq/impl/DefaultRecordMapper.java index 3da75d22d1..39b279d22c 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultRecordMapper.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultRecordMapper.java @@ -56,6 +56,7 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Proxy; +import java.sql.Timestamp; import java.util.Arrays; import java.util.HashMap; import java.util.List; @@ -67,6 +68,7 @@ import org.jooq.AttachableInternal; import org.jooq.Configuration; import org.jooq.Field; import org.jooq.Record; +import org.jooq.Record1; import org.jooq.RecordMapper; import org.jooq.RecordMapperProvider; import org.jooq.RecordType; @@ -87,6 +89,24 @@ import org.jooq.tools.reflect.Reflect; * specific arrays fails, a {@link MappingException} is thrown, wrapping * conversion exceptions. *

+ *

If <E> is a field "value type" and <R> + * has exactly one column:
+ *

+ * Any Java type available from {@link SQLDataType} qualifies as a well-known + * "value type" that can be converted from a single-field {@link Record1}. The + * following rules apply: + *

+ *

    + *
  • If <E> is a reference type like {@link String}, + * {@link Integer}, {@link Long}, {@link Timestamp}, etc., then converting from + * <R> to <E> is mere convenience for calling + * {@link Record#getValue(int, Class)} with fieldIndex = 0
  • + *
  • If <E> is a primitive type, the mapping result will be + * the corresponding wrapper type. null will map to the primitive + * type's initialisation value, e.g. 0 for int, + * 0.0 for double, false for + * boolean.
  • + *
*
If a default constructor is available and any JPA {@link Column} * annotations are found on the provided <E>, only those are * used:
@@ -245,6 +265,12 @@ public class DefaultRecordMapper implements RecordMapper implements RecordMapper { + + @Override + public final E map(R record) { + int size = record.size(); + if (size != 1) + throw new MappingException("Cannot map multi-column record of degree " + size + " to value type " + type); + + return record.getValue(0, type); + } + } + /** * Convert a record into an hash map proxy of a given type. *

diff --git a/jOOQ/src/test/java/org/jooq/test/RecordMappingTest.java b/jOOQ/src/test/java/org/jooq/test/RecordMappingTest.java index 270be1bbf0..fc027e406c 100644 --- a/jOOQ/src/test/java/org/jooq/test/RecordMappingTest.java +++ b/jOOQ/src/test/java/org/jooq/test/RecordMappingTest.java @@ -41,13 +41,16 @@ package org.jooq.test; -import static org.junit.Assert.assertTrue; import static org.jooq.impl.DSL.field; +import static org.junit.Assert.assertTrue; + +import java.util.Arrays; import javax.persistence.Column; import org.jooq.Field; import org.jooq.Record1; +import org.jooq.Result; import org.junit.Test; @@ -103,4 +106,23 @@ public class RecordMappingTest extends AbstractTest { return "Boolean [oneZero=" + oneZero + ", oneZero1=" + oneZero1 + ", oneZero2=" + oneZero2 + "]"; } } + + @Test + public void testIntoValueTypes() throws Exception { + Field field = field("B", Boolean.class); + Result> result = create.newResult(field); + result.add(create.newRecord(field)); + result.add(create.newRecord(field)); + result.add(create.newRecord(field)); + result.get(0).setValue(field, true); + result.get(1).setValue(field, false); + result.get(2).setValue(field, null); + + assertEquals(Arrays.asList(true, false, false), result.into(boolean.class)); + assertEquals(Arrays.asList(true, false, null), result.into(Boolean.class)); + assertEquals(Arrays.asList(1, 0, 0), result.into(int.class)); + assertEquals(Arrays.asList(1, 0, null), result.into(Integer.class)); + assertEquals(Arrays.asList("true", "false", null), result.into(String.class)); + } + }