[#3212] Add support for value types in DefaultRecordMapper, when mapping Record1 types
This commit is contained in:
parent
4d27ced7b3
commit
afbf75aee6
@ -1834,6 +1834,28 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFetchIntoValueType() throws Exception {
|
||||
Result<Record1<Integer>> 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<B> result = create().selectFrom(TBook()).orderBy(TBook_ID()).fetch();
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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<T> implements DataType<T> {
|
||||
return BigDecimal.class;
|
||||
}
|
||||
}
|
||||
|
||||
static Collection<Class<?>> types() {
|
||||
return unmodifiableCollection(SQL_DATATYPES_BY_TYPE.keySet());
|
||||
}
|
||||
|
||||
static Collection<DataType<?>> dataTypes() {
|
||||
return unmodifiableCollection(SQL_DATATYPES_BY_TYPE.values());
|
||||
}
|
||||
}
|
||||
|
||||
@ -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.
|
||||
* <p>
|
||||
* <h5>If <code><E></code> is a field "value type" and <code><R></code>
|
||||
* has exactly one column:</h5>
|
||||
* <p>
|
||||
* 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:
|
||||
* <p>
|
||||
* <ul>
|
||||
* <li>If <code><E></code> is a reference type like {@link String},
|
||||
* {@link Integer}, {@link Long}, {@link Timestamp}, etc., then converting from
|
||||
* <code><R></code> to <code><E></code> is mere convenience for calling
|
||||
* {@link Record#getValue(int, Class)} with <code>fieldIndex = 0</code></li>
|
||||
* <li>If <code><E></code> is a primitive type, the mapping result will be
|
||||
* the corresponding wrapper type. <code>null</code> will map to the primitive
|
||||
* type's initialisation value, e.g. <code>0</code> for <code>int</code>,
|
||||
* <code>0.0</code> for <code>double</code>, <code>false</code> for
|
||||
* <code>boolean</code>.</li>
|
||||
* </ul>
|
||||
* <h5>If a default constructor is available and any JPA {@link Column}
|
||||
* annotations are found on the provided <code><E></code>, only those are
|
||||
* used:</h5>
|
||||
@ -245,6 +265,12 @@ public class DefaultRecordMapper<R extends Record, E> implements RecordMapper<R,
|
||||
return;
|
||||
}
|
||||
|
||||
// [#3212] "Value types" can be mapped from single-field Record1 types for convenience
|
||||
if (type.isPrimitive() || DefaultDataType.types().contains(type)) {
|
||||
delegate = new ValueTypeMapper();
|
||||
return;
|
||||
}
|
||||
|
||||
// [#1470] Return a proxy if the supplied type is an interface
|
||||
if (Modifier.isAbstract(type.getModifiers())) {
|
||||
delegate = new ProxyMapper();
|
||||
@ -347,6 +373,18 @@ public class DefaultRecordMapper<R extends Record, E> implements RecordMapper<R,
|
||||
}
|
||||
}
|
||||
|
||||
private class ValueTypeMapper implements RecordMapper<R, E> {
|
||||
|
||||
@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.
|
||||
* <p>
|
||||
|
||||
@ -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<Boolean> field = field("B", Boolean.class);
|
||||
Result<Record1<Boolean>> 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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user