Skip to content

Commit fad6568

Browse files
committed
Support AggregateReferences with custom id type.
Restructured reading conversion process into: - converting technology base types (JDBC Arrays). - standard and custom conversions. - module specific conversions (AggregateReference). Closes #1828 Original pull request #2062
1 parent fc4e20f commit fad6568

File tree

7 files changed

+231
-188
lines changed

7 files changed

+231
-188
lines changed

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

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,7 @@
2727
import org.apache.commons.logging.Log;
2828
import org.apache.commons.logging.LogFactory;
2929
import org.springframework.context.ApplicationContextAware;
30-
import org.springframework.core.convert.ConverterNotFoundException;
3130
import org.springframework.core.convert.converter.Converter;
32-
import org.springframework.core.convert.converter.ConverterRegistry;
3331
import org.springframework.data.convert.CustomConversions;
3432
import org.springframework.data.jdbc.core.mapping.AggregateReference;
3533
import org.springframework.data.jdbc.core.mapping.JdbcValue;
@@ -91,8 +89,6 @@ public MappingJdbcConverter(RelationalMappingContext context, RelationResolver r
9189

9290
this.typeFactory = JdbcTypeFactory.unsupported();
9391
this.relationResolver = relationResolver;
94-
95-
registerAggregateReferenceConverters();
9692
}
9793

9894
/**
@@ -112,14 +108,6 @@ public MappingJdbcConverter(RelationalMappingContext context, RelationResolver r
112108

113109
this.typeFactory = typeFactory;
114110
this.relationResolver = relationResolver;
115-
116-
registerAggregateReferenceConverters();
117-
}
118-
119-
private void registerAggregateReferenceConverters() {
120-
121-
ConverterRegistry registry = (ConverterRegistry) getConversionService();
122-
AggregateReferenceConverters.getConvertersToRegister(getConversionService()).forEach(registry::addConverter);
123111
}
124112

125113
@Nullable
@@ -185,33 +173,48 @@ private Class<?> doGetColumnType(RelationalPersistentProperty property) {
185173
}
186174

187175
@Override
188-
@Nullable
189-
public Object readValue(@Nullable Object value, TypeInformation<?> type) {
190-
191-
if (value == null) {
192-
return value;
193-
}
176+
protected Object readTechnologyType(Object value) {
194177

195178
if (value instanceof Array array) {
196179
try {
197-
return super.readValue(array.getArray(), type);
198-
} catch (SQLException | ConverterNotFoundException e) {
180+
return array.getArray();
181+
} catch (SQLException e) {
199182
LOG.info("Failed to extract a value of type %s from an Array; Attempting to use standard conversions", e);
183+
200184
}
201185
}
202186

203-
return super.readValue(value, type);
187+
return value;
204188
}
205189

206190
@Override
191+
protected TypeInformation<?> determineModuleReadTarget(TypeInformation<?> ultimateTargetType) {
192+
193+
if (AggregateReference.class.isAssignableFrom(ultimateTargetType.getType())) {
194+
// the id type of a AggregateReference
195+
return ultimateTargetType.getTypeArguments().get(1);
196+
}
197+
return ultimateTargetType;
198+
}
199+
200+
@Override
201+
protected Object readModuleType(Object value, TypeInformation<?> targetType) {
202+
203+
if (AggregateReference.class.isAssignableFrom(targetType.getType())) {
204+
return AggregateReference.to(value);
205+
}
206+
return value;
207+
}
208+
207209
@Nullable
208-
public Object writeValue(@Nullable Object value, TypeInformation<?> type) {
210+
@Override
211+
protected Object getPotentiallyConvertedSimpleWrite(Object value, TypeInformation<?> type) {
209212

210-
if (value == null) {
211-
return null;
213+
if (value instanceof AggregateReference<?, ?> aggregateReference) {
214+
return writeValue(aggregateReference.getId(), type);
212215
}
213216

214-
return super.writeValue(value, type);
217+
return super.getPotentiallyConvertedSimpleWrite(value, type);
215218
}
216219

217220
private boolean canWriteAsJdbcValue(@Nullable Object value) {
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,15 @@
3232
*
3333
* @author Jens Schauder
3434
*/
35-
public class BasicRelationalConverterAggregateReferenceUnitTests {
35+
class MappingJdbcConverterAggregateReferenceUnitTests {
3636

3737
JdbcMappingContext context = new JdbcMappingContext();
3838
JdbcConverter converter = new MappingJdbcConverter(context, mock(RelationResolver.class));
3939

4040
RelationalPersistentEntity<?> entity = context.getRequiredPersistentEntity(DummyEntity.class);
4141

4242
@Test // DATAJDBC-221
43-
public void convertsToAggregateReference() {
43+
void convertsToAggregateReference() {
4444

4545
final RelationalPersistentProperty property = entity.getRequiredPersistentProperty("reference");
4646

@@ -51,7 +51,7 @@ public void convertsToAggregateReference() {
5151
}
5252

5353
@Test // DATAJDBC-221
54-
public void convertsFromAggregateReference() {
54+
void convertsFromAggregateReference() {
5555

5656
final RelationalPersistentProperty property = entity.getRequiredPersistentProperty("reference");
5757

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

Lines changed: 46 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import org.junit.jupiter.api.Test;
4141
import org.springframework.core.convert.converter.Converter;
4242
import org.springframework.data.annotation.Id;
43+
import org.springframework.data.convert.WritingConverter;
4344
import org.springframework.data.jdbc.core.mapping.AggregateReference;
4445
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
4546
import org.springframework.data.jdbc.core.mapping.JdbcValue;
@@ -60,8 +61,7 @@ class MappingJdbcConverterUnitTests {
6061

6162
private static final UUID UUID = java.util.UUID.fromString("87a48aa8-a071-705e-54a9-e52fe3a012f1");
6263
private static final byte[] BYTES_REPRESENTING_UUID = { -121, -92, -118, -88, -96, 113, 112, 94, 84, -87, -27, 47,
63-
-29,
64-
-96, 18, -15 };
64+
-29, -96, 18, -15 };
6565

6666
private JdbcMappingContext context = new JdbcMappingContext();
6767
private StubbedJdbcTypeFactory typeFactory = new StubbedJdbcTypeFactory();
@@ -70,7 +70,7 @@ class MappingJdbcConverterUnitTests {
7070
(identifier, path) -> {
7171
throw new UnsupportedOperationException();
7272
}, //
73-
new JdbcCustomConversions(), //
73+
new JdbcCustomConversions(List.of(CustomIdToLong.INSTANCE)), //
7474
typeFactory //
7575
);
7676

@@ -91,6 +91,7 @@ void testTargetTypesForPropertyType() {
9191
checkTargetType(softly, entity, "date", Date.class);
9292
checkTargetType(softly, entity, "timestamp", Timestamp.class);
9393
checkTargetType(softly, entity, "uuid", UUID.class);
94+
checkTargetType(softly, entity, "reference", Long.class);
9495

9596
softly.assertAll();
9697
}
@@ -216,117 +217,26 @@ private void checkTargetType(SoftAssertions softly, RelationalPersistentEntity<?
216217
}
217218

218219
@SuppressWarnings("unused")
219-
private static class DummyEntity {
220-
221-
@Id private final Long id;
222-
private final SomeEnum someEnum;
223-
private final LocalDateTime localDateTime;
224-
private final LocalDate localDate;
225-
private final LocalTime localTime;
226-
private final ZonedDateTime zonedDateTime;
227-
private final OffsetDateTime offsetDateTime;
228-
private final Instant instant;
229-
private final Date date;
230-
private final Timestamp timestamp;
231-
private final AggregateReference<DummyEntity, Long> reference;
232-
private final UUID uuid;
233-
private final AggregateReference<ReferencedByUuid, UUID> uuidRef;
234-
private final Optional<UUID> optionalUuid;
235-
236-
// DATAJDBC-259
237-
private final List<String> listOfString;
238-
private final String[] arrayOfString;
239-
private final List<OtherEntity> listOfEntity;
240-
private final OtherEntity[] arrayOfEntity;
241-
242-
private DummyEntity(Long id, SomeEnum someEnum, LocalDateTime localDateTime, LocalDate localDate,
243-
LocalTime localTime, ZonedDateTime zonedDateTime, OffsetDateTime offsetDateTime, Instant instant, Date date,
244-
Timestamp timestamp, AggregateReference<DummyEntity, Long> reference, UUID uuid,
245-
AggregateReference<ReferencedByUuid, UUID> uuidRef, Optional<java.util.UUID> optionalUUID, List<String> listOfString, String[] arrayOfString,
246-
List<OtherEntity> listOfEntity, OtherEntity[] arrayOfEntity) {
247-
this.id = id;
248-
this.someEnum = someEnum;
249-
this.localDateTime = localDateTime;
250-
this.localDate = localDate;
251-
this.localTime = localTime;
252-
this.zonedDateTime = zonedDateTime;
253-
this.offsetDateTime = offsetDateTime;
254-
this.instant = instant;
255-
this.date = date;
256-
this.timestamp = timestamp;
257-
this.reference = reference;
258-
this.uuid = uuid;
259-
this.uuidRef = uuidRef;
260-
this.optionalUuid = optionalUUID;
261-
this.listOfString = listOfString;
262-
this.arrayOfString = arrayOfString;
263-
this.listOfEntity = listOfEntity;
264-
this.arrayOfEntity = arrayOfEntity;
265-
}
266-
267-
public Long getId() {
268-
return this.id;
269-
}
270-
271-
public SomeEnum getSomeEnum() {
272-
return this.someEnum;
273-
}
274-
275-
public LocalDateTime getLocalDateTime() {
276-
return this.localDateTime;
277-
}
278-
279-
public LocalDate getLocalDate() {
280-
return this.localDate;
281-
}
282-
283-
public LocalTime getLocalTime() {
284-
return this.localTime;
285-
}
286-
287-
public ZonedDateTime getZonedDateTime() {
288-
return this.zonedDateTime;
289-
}
290-
291-
public OffsetDateTime getOffsetDateTime() {
292-
return this.offsetDateTime;
293-
}
294-
295-
public Instant getInstant() {
296-
return this.instant;
297-
}
298-
299-
public Date getDate() {
300-
return this.date;
301-
}
302-
303-
public Timestamp getTimestamp() {
304-
return this.timestamp;
305-
}
306-
307-
public AggregateReference<DummyEntity, Long> getReference() {
308-
return this.reference;
309-
}
310-
311-
public UUID getUuid() {
312-
return this.uuid;
313-
}
314-
315-
public List<String> getListOfString() {
316-
return this.listOfString;
317-
}
318-
319-
public String[] getArrayOfString() {
320-
return this.arrayOfString;
321-
}
322-
323-
public List<OtherEntity> getListOfEntity() {
324-
return this.listOfEntity;
325-
}
326-
327-
public OtherEntity[] getArrayOfEntity() {
328-
return this.arrayOfEntity;
329-
}
220+
private record DummyEntity( //
221+
@Id Long id, //
222+
SomeEnum someEnum, //
223+
LocalDateTime localDateTime, //
224+
LocalDate localDate, //
225+
LocalTime localTime, //
226+
ZonedDateTime zonedDateTime, //
227+
OffsetDateTime offsetDateTime, //
228+
Instant instant, //
229+
Date date, //
230+
Timestamp timestamp, //
231+
AggregateReference<DummyEntity, Long> reference, //
232+
UUID uuid, //
233+
AggregateReference<ReferencedByUuid, UUID> uuidRef, //
234+
Optional<UUID> optionalUuid, //
235+
List<String> listOfString, //
236+
String[] arrayOfString, //
237+
List<OtherEntity> listOfEntity, //
238+
OtherEntity[] arrayOfEntity //
239+
) {
330240
}
331241

332242
@SuppressWarnings("unused")
@@ -337,6 +247,18 @@ private enum SomeEnum {
337247
@SuppressWarnings("unused")
338248
private static class OtherEntity {}
339249

250+
private static class EnumIdEntity {
251+
@Id SomeEnum id;
252+
}
253+
254+
private static class CustomIdEntity {
255+
@Id CustomId id;
256+
}
257+
258+
private record CustomId(Long id) {
259+
260+
}
261+
340262
private static class StubbedJdbcTypeFactory implements JdbcTypeFactory {
341263
Object[] arraySource;
342264

@@ -366,4 +288,14 @@ public UUID convert(byte[] source) {
366288
return new UUID(high, low);
367289
}
368290
}
291+
292+
@WritingConverter
293+
enum CustomIdToLong implements Converter<CustomId, Long> {
294+
INSTANCE;
295+
296+
@Override
297+
public Long convert(CustomId source) {
298+
return source.id;
299+
}
300+
}
369301
}

0 commit comments

Comments
 (0)