Skip to content

Commit a55bdb4

Browse files
schaudermp911de
authored andcommitted
Properly convert primitive array arguments.
Closes #945 Original pull request: #949.
1 parent 80da756 commit a55bdb4

File tree

3 files changed

+134
-8
lines changed

3 files changed

+134
-8
lines changed

spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/ArrayUtil.java

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,97 @@ static byte[] toPrimitiveByteArray(Byte[] byteArray) {
4141
}
4242
return bytes;
4343
}
44+
45+
static Byte[] toObjectArray(byte[] primitiveArray) {
46+
47+
Byte[] objects = new Byte[primitiveArray.length];
48+
for (int i = 0; i < primitiveArray.length; i++) {
49+
objects[i] = primitiveArray[i];
50+
}
51+
return objects;
52+
}
53+
54+
static Short[] toObjectArray(short[] primitiveArray) {
55+
56+
Short[] objects = new Short[primitiveArray.length];
57+
for (int i = 0; i < primitiveArray.length; i++) {
58+
objects[i] = primitiveArray[i];
59+
}
60+
return objects;
61+
}
62+
63+
static Character[] toObjectArray(char[] primitiveArray) {
64+
65+
Character[] objects = new Character[primitiveArray.length];
66+
for (int i = 0; i < primitiveArray.length; i++) {
67+
objects[i] = primitiveArray[i];
68+
}
69+
return objects;
70+
}
71+
72+
static Integer[] toObjectArray(int[] primitiveArray) {
73+
74+
Integer[] objects = new Integer[primitiveArray.length];
75+
for (int i = 0; i < primitiveArray.length; i++) {
76+
objects[i] = primitiveArray[i];
77+
}
78+
return objects;
79+
}
80+
81+
static Long[] toObjectArray(long[] primitiveArray) {
82+
83+
Long[] objects = new Long[primitiveArray.length];
84+
for (int i = 0; i < primitiveArray.length; i++) {
85+
objects[i] = primitiveArray[i];
86+
}
87+
return objects;
88+
}
89+
90+
static Float[] toObjectArray(float[] primitiveArray) {
91+
92+
Float[] objects = new Float[primitiveArray.length];
93+
for (int i = 0; i < primitiveArray.length; i++) {
94+
objects[i] = primitiveArray[i];
95+
}
96+
return objects;
97+
}
98+
99+
static Double[] toObjectArray(double[] primitiveArray) {
100+
101+
Double[] objects = new Double[primitiveArray.length];
102+
for (int i = 0; i < primitiveArray.length; i++) {
103+
objects[i] = primitiveArray[i];
104+
}
105+
return objects;
106+
}
107+
108+
static Object[] convertToObjectArray(Object unknownArray) {
109+
110+
Class<?> componentType = unknownArray.getClass().getComponentType();
111+
112+
if (componentType.isPrimitive()) {
113+
if (componentType == byte.class) {
114+
return toObjectArray((byte[]) unknownArray);
115+
}
116+
if (componentType == short.class) {
117+
return toObjectArray((short[]) unknownArray);
118+
}
119+
if (componentType == char.class) {
120+
return toObjectArray((char[]) unknownArray);
121+
}
122+
if (componentType == int.class) {
123+
return toObjectArray((int[]) unknownArray);
124+
}
125+
if (componentType == long.class) {
126+
return toObjectArray((long[]) unknownArray);
127+
}
128+
if (componentType == float.class) {
129+
return toObjectArray((float[]) unknownArray);
130+
}
131+
if (componentType == double.class) {
132+
return toObjectArray((double[]) unknownArray);
133+
}
134+
}
135+
return (Object[]) unknownArray;
136+
}
44137
}

spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/BasicJdbcConverter.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,9 @@ public JdbcValue writeJdbcValue(@Nullable Object value, Class<?> columnType, int
297297

298298
Class<?> componentType = convertedValue.getClass().getComponentType();
299299
if (componentType != byte.class && componentType != Byte.class) {
300-
return JdbcValue.of(typeFactory.createArray((Object[]) convertedValue), JDBCType.ARRAY);
300+
301+
Object[] objectArray = ArrayUtil.convertToObjectArray(convertedValue);
302+
return JdbcValue.of(typeFactory.createArray(objectArray), JDBCType.ARRAY);
301303
}
302304

303305
if (componentType == Byte.class) {

spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/BasicJdbcConverterUnitTests.java

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@
1616
package org.springframework.data.jdbc.core.convert;
1717

1818
import static org.assertj.core.api.Assertions.*;
19+
import static org.mockito.Mockito.*;
1920

2021
import lombok.Data;
2122

23+
import java.sql.Array;
2224
import java.sql.Timestamp;
2325
import java.time.Instant;
2426
import java.time.LocalDate;
@@ -35,8 +37,10 @@
3537
import org.springframework.data.annotation.Id;
3638
import org.springframework.data.jdbc.core.mapping.AggregateReference;
3739
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
40+
import org.springframework.data.jdbc.support.JdbcUtil;
3841
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
3942
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
43+
import org.springframework.data.relational.core.sql.IdentifierProcessing;
4044
import org.springframework.data.util.ClassTypeInformation;
4145

4246
/**
@@ -47,9 +51,15 @@
4751
public class BasicJdbcConverterUnitTests {
4852

4953
JdbcMappingContext context = new JdbcMappingContext();
50-
BasicJdbcConverter converter = new BasicJdbcConverter(context, (identifier, path) -> {
51-
throw new UnsupportedOperationException();
52-
});
54+
StubbedJdbcTypeFactory typeFactory = new StubbedJdbcTypeFactory();
55+
BasicJdbcConverter converter = new BasicJdbcConverter( //
56+
context, //
57+
(identifier, path) -> {
58+
throw new UnsupportedOperationException();
59+
}, //
60+
new JdbcCustomConversions(), //
61+
typeFactory, IdentifierProcessing.ANSI //
62+
);
5363

5464
@Test // DATAJDBC-104, DATAJDBC-1384
5565
public void testTargetTypesForPropertyType() {
@@ -110,14 +120,25 @@ public void conversionOfDateLikeValueAndBackYieldsOriginalValue() {
110120
LocalDateTime testLocalDateTime = LocalDateTime.of(2001, 2, 3, 4, 5, 6, 123456789);
111121
checkConversionToTimestampAndBack(softly, persistentEntity, "localDateTime", testLocalDateTime);
112122
checkConversionToTimestampAndBack(softly, persistentEntity, "localDate", LocalDate.of(2001, 2, 3));
113-
checkConversionToTimestampAndBack(softly, persistentEntity, "localTime", LocalTime.of(1, 2, 3,123456789));
114-
checkConversionToTimestampAndBack(softly, persistentEntity, "instant", testLocalDateTime.toInstant(ZoneOffset.UTC));
123+
checkConversionToTimestampAndBack(softly, persistentEntity, "localTime", LocalTime.of(1, 2, 3, 123456789));
124+
checkConversionToTimestampAndBack(softly, persistentEntity, "instant",
125+
testLocalDateTime.toInstant(ZoneOffset.UTC));
115126
});
116127

117128
}
118129

119-
private void checkConversionToTimestampAndBack(SoftAssertions softly, RelationalPersistentEntity<?> persistentEntity, String propertyName,
120-
Object value) {
130+
@Test // #945
131+
public void conversionOfPrimitiveArrays() {
132+
133+
int[] ints = { 1, 2, 3, 4, 5 };
134+
JdbcValue converted = converter.writeJdbcValue(ints, ints.getClass(), JdbcUtil.sqlTypeFor(ints.getClass()));
135+
136+
assertThat(converted.getValue()).isInstanceOf(Array.class);
137+
assertThat(typeFactory.arraySource).containsExactly(1, 2, 3, 4, 5);
138+
}
139+
140+
private void checkConversionToTimestampAndBack(SoftAssertions softly, RelationalPersistentEntity<?> persistentEntity,
141+
String propertyName, Object value) {
121142

122143
RelationalPersistentProperty property = persistentEntity.getRequiredPersistentProperty(propertyName);
123144

@@ -165,4 +186,14 @@ private enum SomeEnum {
165186

166187
@SuppressWarnings("unused")
167188
private static class OtherEntity {}
189+
190+
private static class StubbedJdbcTypeFactory implements JdbcTypeFactory {
191+
public Object[] arraySource;
192+
193+
@Override
194+
public Array createArray(Object[] value) {
195+
arraySource = value;
196+
return mock(Array.class);
197+
}
198+
}
168199
}

0 commit comments

Comments
 (0)