Skip to content

Commit 7ef8ac0

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
1 parent b82813d commit 7ef8ac0

File tree

7 files changed

+241
-198
lines changed

7 files changed

+241
-198
lines changed

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

Lines changed: 38 additions & 35 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;
@@ -80,7 +78,7 @@ public class MappingJdbcConverter extends MappingRelationalConverter implements
8078
* {@link #MappingJdbcConverter(RelationalMappingContext, RelationResolver, CustomConversions, JdbcTypeFactory)}
8179
* (MappingContext, RelationResolver, JdbcTypeFactory)} to convert arrays and large objects into JDBC-specific types.
8280
*
83-
* @param context must not be {@literal null}.
81+
* @param context must not be {@literal null}.
8482
* @param relationResolver used to fetch additional relations from the database. Must not be {@literal null}.
8583
*/
8684
public MappingJdbcConverter(RelationalMappingContext context, RelationResolver relationResolver) {
@@ -91,19 +89,17 @@ public MappingJdbcConverter(RelationalMappingContext context, RelationResolver r
9189

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

9894
/**
9995
* Creates a new {@link MappingJdbcConverter} given {@link MappingContext}.
10096
*
101-
* @param context must not be {@literal null}.
97+
* @param context must not be {@literal null}.
10298
* @param relationResolver used to fetch additional relations from the database. Must not be {@literal null}.
103-
* @param typeFactory must not be {@literal null}
99+
* @param typeFactory must not be {@literal null}
104100
*/
105101
public MappingJdbcConverter(RelationalMappingContext context, RelationResolver relationResolver,
106-
CustomConversions conversions, JdbcTypeFactory typeFactory) {
102+
CustomConversions conversions, JdbcTypeFactory typeFactory) {
107103

108104
super(context, conversions);
109105

@@ -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;
188+
}
189+
190+
@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;
204198
}
205199

206200
@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) {
@@ -285,7 +288,7 @@ public <R> R readAndResolve(TypeInformation<R> type, RowDocument source, Identif
285288

286289
@Override
287290
protected RelationalPropertyValueProvider newValueProvider(RowDocumentAccessor documentAccessor,
288-
ValueExpressionEvaluator evaluator, ConversionContext context) {
291+
ValueExpressionEvaluator evaluator, ConversionContext context) {
289292

290293
if (context instanceof ResolvingConversionContext rcc) {
291294

@@ -314,7 +317,7 @@ class ResolvingRelationalPropertyValueProvider implements RelationalPropertyValu
314317
private final Identifier identifier;
315318

316319
private ResolvingRelationalPropertyValueProvider(AggregatePathValueProvider delegate, RowDocumentAccessor accessor,
317-
ResolvingConversionContext context, Identifier identifier) {
320+
ResolvingConversionContext context, Identifier identifier) {
318321

319322
AggregatePath path = context.aggregatePath();
320323

@@ -323,15 +326,15 @@ private ResolvingRelationalPropertyValueProvider(AggregatePathValueProvider dele
323326
this.context = context;
324327
this.identifier = path.isEntity()
325328
? potentiallyAppendIdentifier(identifier, path.getRequiredLeafEntity(),
326-
property -> delegate.getValue(path.append(property)))
329+
property -> delegate.getValue(path.append(property)))
327330
: identifier;
328331
}
329332

330333
/**
331334
* Conditionally append the identifier if the entity has an identifier property.
332335
*/
333336
static Identifier potentiallyAppendIdentifier(Identifier base, RelationalPersistentEntity<?> entity,
334-
Function<RelationalPersistentProperty, Object> getter) {
337+
Function<RelationalPersistentProperty, Object> getter) {
335338

336339
if (entity.hasIdProperty()) {
337340

@@ -460,7 +463,7 @@ public RelationalPropertyValueProvider withContext(ConversionContext context) {
460463

461464
return context == this.context ? this
462465
: new ResolvingRelationalPropertyValueProvider(delegate.withContext(context), accessor,
463-
(ResolvingConversionContext) context, identifier);
466+
(ResolvingConversionContext) context, identifier);
464467
}
465468
}
466469

@@ -472,7 +475,7 @@ public RelationalPropertyValueProvider withContext(ConversionContext context) {
472475
* @param identifier
473476
*/
474477
private record ResolvingConversionContext(ConversionContext delegate, AggregatePath aggregatePath,
475-
Identifier identifier) implements ConversionContext {
478+
Identifier identifier) implements ConversionContext {
476479

477480
@Override
478481
public <S> S convert(Object source, TypeInformation<? extends S> typeHint) {
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

0 commit comments

Comments
 (0)