Skip to content

Commit 1a3f63a

Browse files
committed
Fix problems with reading converters.
Let the AggregateReference converters now receive also custom converters as delegates. Remove the ArrayToObjectConverter which just uses the first element of the array from the DefaultConversion service. Closes #1750
1 parent d56a99a commit 1a3f63a

File tree

3 files changed

+89
-8
lines changed

3 files changed

+89
-8
lines changed

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

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import java.util.Collections;
2121
import java.util.List;
2222

23-
import org.springframework.core.convert.ConversionService;
23+
import org.springframework.core.convert.converter.Converter;
2424
import org.springframework.core.convert.converter.GenericConverter.ConvertiblePair;
2525
import org.springframework.core.convert.support.DefaultConversionService;
2626
import org.springframework.data.convert.CustomConversions;
@@ -70,11 +70,33 @@ public JdbcCustomConversions() {
7070
*/
7171
public JdbcCustomConversions(List<?> converters) {
7272

73-
super(new ConverterConfiguration( //
74-
STORE_CONVERSIONS, //
73+
super(constructConverterConfiguration(converters));
74+
}
75+
76+
private static ConverterConfiguration constructConverterConfiguration(List<?> converters) {
77+
78+
StoreConversions storeConversions = storeConversions(converters);
79+
80+
return new ConverterConfiguration( //
81+
storeConversions, //
7582
converters, //
7683
JdbcCustomConversions::excludeConversionsBetweenDateAndJsr310Types //
77-
));
84+
);
85+
}
86+
87+
private static StoreConversions storeConversions(List<?> userConverters) {
88+
89+
List<Object> converters = new ArrayList<>(Jsr310TimestampBasedConverters.getConvertersToRegister());
90+
91+
DefaultConversionService defaultConversionService = new DefaultConversionService();
92+
for (Object userConverter : userConverters) {
93+
if (userConverter instanceof Converter<?, ?> converter)
94+
defaultConversionService.addConverter(converter);
95+
}
96+
97+
converters.addAll(AggregateReferenceConverters.getConvertersToRegister(defaultConversionService));
98+
99+
return StoreConversions.of(JdbcSimpleTypes.HOLDER, Collections.unmodifiableCollection(converters));
78100
}
79101

80102
/**

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

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import static org.assertj.core.api.SoftAssertions.*;
2020
import static org.mockito.Mockito.*;
2121

22+
import java.nio.ByteBuffer;
2223
import java.sql.Array;
2324
import java.sql.Timestamp;
2425
import java.time.Instant;
@@ -28,13 +29,15 @@
2829
import java.time.OffsetDateTime;
2930
import java.time.ZoneOffset;
3031
import java.time.ZonedDateTime;
32+
import java.util.Collections;
3133
import java.util.Date;
3234
import java.util.List;
3335
import java.util.Map;
3436
import java.util.UUID;
3537

3638
import org.assertj.core.api.SoftAssertions;
3739
import org.junit.jupiter.api.Test;
40+
import org.springframework.core.convert.converter.Converter;
3841
import org.springframework.data.annotation.Id;
3942
import org.springframework.data.jdbc.core.mapping.AggregateReference;
4043
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
@@ -50,9 +53,14 @@
5053
* Unit tests for {@link MappingJdbcConverter}.
5154
*
5255
* @author Mark Paluch
56+
* @author Jens Schauder
5357
*/
5458
public class MappingJdbcConverterUnitTests {
5559

60+
public static final UUID UUID = java.util.UUID.fromString("87a48aa8-a071-705e-54a9-e52fe3a012f1");
61+
public static final byte[] BYTES_REPRESENTING_UUID = { -121, -92, -118, -88, -96, 113, 112, 94, 84, -87, -27, 47, -29,
62+
-96, 18, -15 };
63+
5664
JdbcMappingContext context = new JdbcMappingContext();
5765
StubbedJdbcTypeFactory typeFactory = new StubbedJdbcTypeFactory();
5866
MappingJdbcConverter converter = new MappingJdbcConverter( //
@@ -61,7 +69,7 @@ public class MappingJdbcConverterUnitTests {
6169
throw new UnsupportedOperationException();
6270
}, //
6371
new JdbcCustomConversions(), //
64-
typeFactory //
72+
typeFactory //
6573
);
6674

6775
@Test // DATAJDBC-104, DATAJDBC-1384
@@ -152,6 +160,38 @@ void accessesCorrectValuesForOneToOneRelationshipWithIdenticallyNamedIdPropertie
152160
assertThat(result).isEqualTo(new WithOneToOne("one", new Referenced(23L)));
153161
}
154162

163+
@Test // GH-1750
164+
void readByteArrayToAggregateReferenceWithCustomConverter() {
165+
166+
JdbcMappingContext context = new JdbcMappingContext();
167+
StubbedJdbcTypeFactory typeFactory = new StubbedJdbcTypeFactory();
168+
Converter<byte[], UUID> customConverter = new ByteArrayToUuid();
169+
MappingJdbcConverter converter = new MappingJdbcConverter( //
170+
context, //
171+
(identifier, path) -> {
172+
throw new UnsupportedOperationException();
173+
}, //
174+
new JdbcCustomConversions(Collections.singletonList(customConverter)), //
175+
typeFactory //
176+
);
177+
178+
SoftAssertions.assertSoftly(softly -> {
179+
checkReadConversion(softly, converter, "uuidRef", AggregateReference.to(UUID));
180+
checkReadConversion(softly, converter, "uuid", UUID);
181+
});
182+
183+
}
184+
185+
private static void checkReadConversion(SoftAssertions softly, MappingJdbcConverter converter, String propertyName,
186+
Object expected) {
187+
188+
RelationalPersistentProperty property = converter.getMappingContext().getRequiredPersistentEntity(DummyEntity.class)
189+
.getRequiredPersistentProperty(propertyName);
190+
Object value = converter.readValue(BYTES_REPRESENTING_UUID, property.getTypeInformation() //
191+
);
192+
193+
softly.assertThat(value).isEqualTo(expected);
194+
}
155195

156196
private void checkConversionToTimestampAndBack(SoftAssertions softly, RelationalPersistentEntity<?> persistentEntity,
157197
String propertyName, Object value) {
@@ -187,6 +227,7 @@ private static class DummyEntity {
187227
private final Timestamp timestamp;
188228
private final AggregateReference<DummyEntity, Long> reference;
189229
private final UUID uuid;
230+
private final AggregateReference<ReferencedByUuid, UUID> uuidRef;
190231

191232
// DATAJDBC-259
192233
private final List<String> listOfString;
@@ -196,8 +237,9 @@ private static class DummyEntity {
196237

197238
private DummyEntity(Long id, SomeEnum someEnum, LocalDateTime localDateTime, LocalDate localDate,
198239
LocalTime localTime, ZonedDateTime zonedDateTime, OffsetDateTime offsetDateTime, Instant instant, Date date,
199-
Timestamp timestamp, AggregateReference<DummyEntity, Long> reference, UUID uuid, List<String> listOfString,
200-
String[] arrayOfString, List<OtherEntity> listOfEntity, OtherEntity[] arrayOfEntity) {
240+
Timestamp timestamp, AggregateReference<DummyEntity, Long> reference, UUID uuid,
241+
AggregateReference<ReferencedByUuid, UUID> uuidRef, List<String> listOfString, String[] arrayOfString,
242+
List<OtherEntity> listOfEntity, OtherEntity[] arrayOfEntity) {
201243
this.id = id;
202244
this.someEnum = someEnum;
203245
this.localDateTime = localDateTime;
@@ -210,6 +252,7 @@ private DummyEntity(Long id, SomeEnum someEnum, LocalDateTime localDateTime, Loc
210252
this.timestamp = timestamp;
211253
this.reference = reference;
212254
this.uuid = uuid;
255+
this.uuidRef = uuidRef;
213256
this.listOfString = listOfString;
214257
this.arrayOfString = arrayOfString;
215258
this.listOfEntity = listOfEntity;
@@ -299,9 +342,23 @@ public Array createArray(Object[] value) {
299342
}
300343
}
301344

302-
record WithOneToOne(@Id String id,@MappedCollection(idColumn = "renamed") Referenced referenced){}
345+
record WithOneToOne(@Id String id, @MappedCollection(idColumn = "renamed") Referenced referenced) {
346+
}
303347

304348
record Referenced(@Id Long id) {
305349
}
306350

351+
record ReferencedByUuid(@Id UUID id) {
352+
}
353+
354+
class ByteArrayToUuid implements Converter<byte[], UUID> {
355+
@Override
356+
public UUID convert(byte[] source) {
357+
358+
ByteBuffer byteBuffer = ByteBuffer.wrap(source);
359+
long high = byteBuffer.getLong();
360+
long low = byteBuffer.getLong();
361+
return new UUID(high, low);
362+
}
363+
}
307364
}

spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/AbstractRelationalConverter.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ private AbstractRelationalConverter(RelationalMappingContext context, CustomConv
7272
this.entityInstantiators = entityInstantiators;
7373
this.conversions = conversions;
7474

75+
this.conversionService.removeConvertible(Object[].class, Object.class);
76+
7577
conversions.registerConvertersIn(this.conversionService);
7678
}
7779

0 commit comments

Comments
 (0)