Skip to content

Commit 002acbc

Browse files
schaudermp911de
authored andcommitted
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 6103593 commit 002acbc

File tree

9 files changed

+248
-449
lines changed

9 files changed

+248
-449
lines changed

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

Lines changed: 0 additions & 136 deletions
This file was deleted.

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

Lines changed: 83 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,8 @@
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;
31+
import org.springframework.dao.NonTransientDataAccessException;
3332
import org.springframework.data.convert.CustomConversions;
3433
import org.springframework.data.jdbc.core.mapping.AggregateReference;
3534
import org.springframework.data.jdbc.core.mapping.JdbcValue;
@@ -91,8 +90,6 @@ public MappingJdbcConverter(RelationalMappingContext context, RelationResolver r
9190

9291
this.typeFactory = JdbcTypeFactory.unsupported();
9392
this.relationResolver = relationResolver;
94-
95-
registerAggregateReferenceConverters();
9693
}
9794

9895
/**
@@ -112,14 +109,6 @@ public MappingJdbcConverter(RelationalMappingContext context, RelationResolver r
112109

113110
this.typeFactory = typeFactory;
114111
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);
123112
}
124113

125114
@Nullable
@@ -184,34 +173,78 @@ private Class<?> doGetColumnType(RelationalPersistentProperty property) {
184173
return componentColumnType;
185174
}
186175

176+
/**
177+
* Read and convert a single value that is coming from a database to the {@literal targetType} expected by the domain
178+
* model.
179+
*
180+
* @param value a value as it is returned by the driver accessing the persistence store. May be {@code null}.
181+
* @param targetType {@link TypeInformation} into which the value is to be converted. Must not be {@code null}.
182+
* @return
183+
*/
187184
@Override
188185
@Nullable
189-
public Object readValue(@Nullable Object value, TypeInformation<?> type) {
186+
public Object readValue(@Nullable Object value, TypeInformation<?> targetType) {
190187

191-
if (value == null) {
192-
return value;
188+
if (null == value) {
189+
return null;
193190
}
194191

192+
TypeInformation<?> originalTargetType = targetType;
193+
value = readJdbcArray(value);
194+
targetType = determineNestedTargetType(targetType);
195+
196+
return possiblyReadToAggregateReference(getPotentiallyConvertedSimpleRead(value, targetType), originalTargetType);
197+
}
198+
199+
/**
200+
* Unwrap a Jdbc array, if such a value is provided
201+
*/
202+
private Object readJdbcArray(Object value) {
203+
195204
if (value instanceof Array array) {
196205
try {
197-
return super.readValue(array.getArray(), type);
198-
} catch (SQLException | ConverterNotFoundException e) {
199-
LOG.info("Failed to extract a value of type %s from an Array; Attempting to use standard conversions", e);
206+
return array.getArray();
207+
} catch (SQLException e) {
208+
throw new FailedToAccessJdbcArrayException(e);
200209
}
201210
}
202211

203-
return super.readValue(value, type);
212+
return value;
213+
}
214+
215+
/**
216+
* Determine the id type of an {@link AggregateReference} that the rest of the conversion infrastructure needs to use
217+
* as a conversion target.
218+
*/
219+
private TypeInformation<?> determineNestedTargetType(TypeInformation<?> ultimateTargetType) {
220+
221+
if (AggregateReference.class.isAssignableFrom(ultimateTargetType.getType())) {
222+
// the id type of a AggregateReference
223+
return ultimateTargetType.getTypeArguments().get(1);
224+
}
225+
return ultimateTargetType;
226+
}
227+
228+
/**
229+
* Convert value to an {@link AggregateReference} if that is specified by the parameter targetType.
230+
*/
231+
private Object possiblyReadToAggregateReference(Object value, TypeInformation<?> targetType) {
232+
233+
if (AggregateReference.class.isAssignableFrom(targetType.getType())) {
234+
return AggregateReference.to(value);
235+
}
236+
return value;
204237
}
205238

206-
@Override
207239
@Nullable
208-
public Object writeValue(@Nullable Object value, TypeInformation<?> type) {
240+
@Override
241+
protected Object getPotentiallyConvertedSimpleWrite(Object value, TypeInformation<?> type) {
209242

210-
if (value == null) {
211-
return null;
243+
if (value instanceof AggregateReference<?, ?> aggregateReference) {
244+
return writeValue(aggregateReference.getId(), type);
212245
}
213246

214-
return super.writeValue(value, type);
247+
return super.getPotentiallyConvertedSimpleWrite(value, type);
215248
}
216249

217250
private boolean canWriteAsJdbcValue(@Nullable Object value) {
@@ -244,28 +277,37 @@ private boolean canWriteAsJdbcValue(@Nullable Object value) {
244277
public JdbcValue writeJdbcValue(@Nullable Object value, TypeInformation<?> columnType, SQLType sqlType) {
245278

246279
TypeInformation<?> targetType = canWriteAsJdbcValue(value) ? TypeInformation.of(JdbcValue.class) : columnType;
280+
281+
if (value instanceof AggregateReference<?, ?> aggregateReference) {
282+
return writeJdbcValue(aggregateReference.getId(), columnType, sqlType);
283+
}
284+
247285
Object convertedValue = writeValue(value, targetType);
248286

249287
if (convertedValue instanceof JdbcValue result) {
250288
return result;
251289
}
252290

253-
if (convertedValue == null || !convertedValue.getClass().isArray()) {
254-
return JdbcValue.of(convertedValue, sqlType);
291+
if (convertedValue == null) {
292+
return JdbcValue.of(null, sqlType);
255293
}
256294

257-
Class<?> componentType = convertedValue.getClass().getComponentType();
258-
if (componentType != byte.class && componentType != Byte.class) {
295+
if (convertedValue.getClass().isArray()) {// array conversion
296+
Class<?> componentType = convertedValue.getClass().getComponentType();
297+
if (componentType != byte.class && componentType != Byte.class) {
259298

260-
Object[] objectArray = requireObjectArray(convertedValue);
261-
return JdbcValue.of(typeFactory.createArray(objectArray), JDBCType.ARRAY);
262-
}
299+
Object[] objectArray = requireObjectArray(convertedValue);
300+
return JdbcValue.of(typeFactory.createArray(objectArray), JDBCType.ARRAY);
301+
}
263302

264-
if (componentType == Byte.class) {
265-
convertedValue = ArrayUtils.toPrimitive((Byte[]) convertedValue);
266-
}
303+
if (componentType == Byte.class) {
304+
convertedValue = ArrayUtils.toPrimitive((Byte[]) convertedValue);
305+
}
267306

268-
return JdbcValue.of(convertedValue, JDBCType.BINARY);
307+
return JdbcValue.of(convertedValue, JDBCType.BINARY);
308+
}
309+
310+
return JdbcValue.of(convertedValue, sqlType);
269311
}
270312

271313
@SuppressWarnings("unchecked")
@@ -298,6 +340,12 @@ protected RelationalPropertyValueProvider newValueProvider(RowDocumentAccessor d
298340
return super.newValueProvider(documentAccessor, evaluator, context);
299341
}
300342

343+
private static class FailedToAccessJdbcArrayException extends NonTransientDataAccessException {
344+
public FailedToAccessJdbcArrayException(SQLException e) {
345+
super("Failed to read array", e);
346+
}
347+
}
348+
301349
/**
302350
* {@link RelationalPropertyValueProvider} using a resolving context to lookup relations. This is highly
303351
* context-sensitive. Note that the identifier is held here because of a chicken and egg problem, while

0 commit comments

Comments
 (0)