Properly convert primitive array arguments.

Closes #945
Original pull request: #949.
This commit is contained in:
Jens Schauder
2021-03-23 13:59:34 +01:00
committed by Mark Paluch
parent 80da756a42
commit a55bdb46cc
3 changed files with 134 additions and 8 deletions

View File

@@ -41,4 +41,97 @@ class ArrayUtil {
}
return bytes;
}
static Byte[] toObjectArray(byte[] primitiveArray) {
Byte[] objects = new Byte[primitiveArray.length];
for (int i = 0; i < primitiveArray.length; i++) {
objects[i] = primitiveArray[i];
}
return objects;
}
static Short[] toObjectArray(short[] primitiveArray) {
Short[] objects = new Short[primitiveArray.length];
for (int i = 0; i < primitiveArray.length; i++) {
objects[i] = primitiveArray[i];
}
return objects;
}
static Character[] toObjectArray(char[] primitiveArray) {
Character[] objects = new Character[primitiveArray.length];
for (int i = 0; i < primitiveArray.length; i++) {
objects[i] = primitiveArray[i];
}
return objects;
}
static Integer[] toObjectArray(int[] primitiveArray) {
Integer[] objects = new Integer[primitiveArray.length];
for (int i = 0; i < primitiveArray.length; i++) {
objects[i] = primitiveArray[i];
}
return objects;
}
static Long[] toObjectArray(long[] primitiveArray) {
Long[] objects = new Long[primitiveArray.length];
for (int i = 0; i < primitiveArray.length; i++) {
objects[i] = primitiveArray[i];
}
return objects;
}
static Float[] toObjectArray(float[] primitiveArray) {
Float[] objects = new Float[primitiveArray.length];
for (int i = 0; i < primitiveArray.length; i++) {
objects[i] = primitiveArray[i];
}
return objects;
}
static Double[] toObjectArray(double[] primitiveArray) {
Double[] objects = new Double[primitiveArray.length];
for (int i = 0; i < primitiveArray.length; i++) {
objects[i] = primitiveArray[i];
}
return objects;
}
static Object[] convertToObjectArray(Object unknownArray) {
Class<?> componentType = unknownArray.getClass().getComponentType();
if (componentType.isPrimitive()) {
if (componentType == byte.class) {
return toObjectArray((byte[]) unknownArray);
}
if (componentType == short.class) {
return toObjectArray((short[]) unknownArray);
}
if (componentType == char.class) {
return toObjectArray((char[]) unknownArray);
}
if (componentType == int.class) {
return toObjectArray((int[]) unknownArray);
}
if (componentType == long.class) {
return toObjectArray((long[]) unknownArray);
}
if (componentType == float.class) {
return toObjectArray((float[]) unknownArray);
}
if (componentType == double.class) {
return toObjectArray((double[]) unknownArray);
}
}
return (Object[]) unknownArray;
}
}

View File

@@ -297,7 +297,9 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
Class<?> componentType = convertedValue.getClass().getComponentType();
if (componentType != byte.class && componentType != Byte.class) {
return JdbcValue.of(typeFactory.createArray((Object[]) convertedValue), JDBCType.ARRAY);
Object[] objectArray = ArrayUtil.convertToObjectArray(convertedValue);
return JdbcValue.of(typeFactory.createArray(objectArray), JDBCType.ARRAY);
}
if (componentType == Byte.class) {

View File

@@ -16,9 +16,11 @@
package org.springframework.data.jdbc.core.convert;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import lombok.Data;
import java.sql.Array;
import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDate;
@@ -35,8 +37,10 @@ import org.junit.Test;
import org.springframework.data.annotation.Id;
import org.springframework.data.jdbc.core.mapping.AggregateReference;
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
import org.springframework.data.jdbc.support.JdbcUtil;
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
import org.springframework.data.relational.core.sql.IdentifierProcessing;
import org.springframework.data.util.ClassTypeInformation;
/**
@@ -47,9 +51,15 @@ import org.springframework.data.util.ClassTypeInformation;
public class BasicJdbcConverterUnitTests {
JdbcMappingContext context = new JdbcMappingContext();
BasicJdbcConverter converter = new BasicJdbcConverter(context, (identifier, path) -> {
throw new UnsupportedOperationException();
});
StubbedJdbcTypeFactory typeFactory = new StubbedJdbcTypeFactory();
BasicJdbcConverter converter = new BasicJdbcConverter( //
context, //
(identifier, path) -> {
throw new UnsupportedOperationException();
}, //
new JdbcCustomConversions(), //
typeFactory, IdentifierProcessing.ANSI //
);
@Test // DATAJDBC-104, DATAJDBC-1384
public void testTargetTypesForPropertyType() {
@@ -110,14 +120,25 @@ public class BasicJdbcConverterUnitTests {
LocalDateTime testLocalDateTime = LocalDateTime.of(2001, 2, 3, 4, 5, 6, 123456789);
checkConversionToTimestampAndBack(softly, persistentEntity, "localDateTime", testLocalDateTime);
checkConversionToTimestampAndBack(softly, persistentEntity, "localDate", LocalDate.of(2001, 2, 3));
checkConversionToTimestampAndBack(softly, persistentEntity, "localTime", LocalTime.of(1, 2, 3,123456789));
checkConversionToTimestampAndBack(softly, persistentEntity, "instant", testLocalDateTime.toInstant(ZoneOffset.UTC));
checkConversionToTimestampAndBack(softly, persistentEntity, "localTime", LocalTime.of(1, 2, 3, 123456789));
checkConversionToTimestampAndBack(softly, persistentEntity, "instant",
testLocalDateTime.toInstant(ZoneOffset.UTC));
});
}
private void checkConversionToTimestampAndBack(SoftAssertions softly, RelationalPersistentEntity<?> persistentEntity, String propertyName,
Object value) {
@Test // #945
public void conversionOfPrimitiveArrays() {
int[] ints = { 1, 2, 3, 4, 5 };
JdbcValue converted = converter.writeJdbcValue(ints, ints.getClass(), JdbcUtil.sqlTypeFor(ints.getClass()));
assertThat(converted.getValue()).isInstanceOf(Array.class);
assertThat(typeFactory.arraySource).containsExactly(1, 2, 3, 4, 5);
}
private void checkConversionToTimestampAndBack(SoftAssertions softly, RelationalPersistentEntity<?> persistentEntity,
String propertyName, Object value) {
RelationalPersistentProperty property = persistentEntity.getRequiredPersistentProperty(propertyName);
@@ -165,4 +186,14 @@ public class BasicJdbcConverterUnitTests {
@SuppressWarnings("unused")
private static class OtherEntity {}
private static class StubbedJdbcTypeFactory implements JdbcTypeFactory {
public Object[] arraySource;
@Override
public Array createArray(Object[] value) {
arraySource = value;
return mock(Array.class);
}
}
}