Skip to content

Commit 876c005

Browse files
committed
Introduce AggregatePath.
AggregatePath replaces PersistentPropertyPathExtension. It gets created and cached by the RelationalMappingContext, which should be more efficient and certainly looks nicer. Closes #1525
1 parent adc8d9c commit 876c005

File tree

39 files changed

+1327
-188
lines changed

39 files changed

+1327
-188
lines changed

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

+9-22
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,7 @@
1515
*/
1616
package org.springframework.data.jdbc.core;
1717

18-
import java.util.ArrayList;
19-
import java.util.Arrays;
20-
import java.util.Collections;
21-
import java.util.HashMap;
22-
import java.util.HashSet;
23-
import java.util.LinkedHashMap;
24-
import java.util.List;
25-
import java.util.Map;
26-
import java.util.Optional;
27-
import java.util.Set;
18+
import java.util.*;
2819
import java.util.function.BiConsumer;
2920
import java.util.stream.Collectors;
3021

@@ -38,11 +29,12 @@
3829
import org.springframework.data.mapping.PersistentProperty;
3930
import org.springframework.data.mapping.PersistentPropertyPath;
4031
import org.springframework.data.mapping.PersistentPropertyPathAccessor;
41-
import org.springframework.data.mapping.context.MappingContext;
4232
import org.springframework.data.relational.core.conversion.DbAction;
4333
import org.springframework.data.relational.core.conversion.DbActionExecutionResult;
4434
import org.springframework.data.relational.core.conversion.IdValueSource;
35+
import org.springframework.data.relational.core.mapping.AggregatePath;
4536
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
37+
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
4638
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
4739
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
4840
import org.springframework.data.relational.core.sql.LockMode;
@@ -65,7 +57,7 @@ class JdbcAggregateChangeExecutionContext {
6557
private static final String UPDATE_FAILED = "Failed to update entity [%s]; Id [%s] not found in database";
6658
private static final String UPDATE_FAILED_OPTIMISTIC_LOCKING = "Failed to update entity [%s]; The entity was updated since it was rea or it isn't in the database at all";
6759

68-
private final MappingContext<? extends RelationalPersistentEntity<?>, ? extends RelationalPersistentProperty> context;
60+
private final RelationalMappingContext context;
6961
private final JdbcConverter converter;
7062
private final DataAccessStrategy accessStrategy;
7163

@@ -184,33 +176,28 @@ private Identifier getParentKeys(DbAction.WithDependingOn<?> action, JdbcConvert
184176
Object id = getParentId(action);
185177

186178
JdbcIdentifierBuilder identifier = JdbcIdentifierBuilder //
187-
.forBackReferences(converter, new PersistentPropertyPathExtension(context, action.getPropertyPath()), id);
179+
.forBackReferences(converter, context.getAggregatePath(action.getPropertyPath()), id);
188180

189181
for (Map.Entry<PersistentPropertyPath<RelationalPersistentProperty>, Object> qualifier : action.getQualifiers()
190182
.entrySet()) {
191-
identifier = identifier.withQualifier(new PersistentPropertyPathExtension(context, qualifier.getKey()),
192-
qualifier.getValue());
183+
identifier = identifier.withQualifier(context.getAggregatePath(qualifier.getKey()), qualifier.getValue());
193184
}
194185

195186
return identifier.build();
196187
}
197188

198189
private Object getParentId(DbAction.WithDependingOn<?> action) {
199190

200-
PersistentPropertyPathExtension path = new PersistentPropertyPathExtension(context, action.getPropertyPath());
201-
PersistentPropertyPathExtension idPath = path.getIdDefiningParentPath();
202-
203-
DbAction.WithEntity<?> idOwningAction = getIdOwningAction(action, idPath);
191+
DbAction.WithEntity<?> idOwningAction = getIdOwningAction(action, context.getAggregatePath(action.getPropertyPath()).getIdDefiningParentPath());
204192

205193
return getPotentialGeneratedIdFrom(idOwningAction);
206194
}
207195

208-
private DbAction.WithEntity<?> getIdOwningAction(DbAction.WithEntity<?> action,
209-
PersistentPropertyPathExtension idPath) {
196+
private DbAction.WithEntity<?> getIdOwningAction(DbAction.WithEntity<?> action, AggregatePath idPath) {
210197

211198
if (!(action instanceof DbAction.WithDependingOn<?> withDependingOn)) {
212199

213-
Assert.state(idPath.getLength() == 0,
200+
Assert.state(idPath.isRoot(),
214201
"When the id path is not empty the id providing action should be of type WithDependingOn");
215202

216203
return action;

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

+15-12
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@
4747
import org.springframework.data.mapping.model.SpELExpressionParameterValueProvider;
4848
import org.springframework.data.relational.core.conversion.BasicRelationalConverter;
4949
import org.springframework.data.relational.core.conversion.RelationalConverter;
50-
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
50+
import org.springframework.data.relational.core.mapping.AggregatePath;
51+
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
5152
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
5253
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
5354
import org.springframework.data.relational.core.sql.IdentifierProcessing;
@@ -86,14 +87,14 @@ public class BasicJdbcConverter extends BasicRelationalConverter implements Jdbc
8687
* Creates a new {@link BasicRelationalConverter} given {@link MappingContext} and a
8788
* {@link JdbcTypeFactory#unsupported() no-op type factory} throwing {@link UnsupportedOperationException} on type
8889
* creation. Use
89-
* {@link #BasicJdbcConverter(MappingContext, RelationResolver, CustomConversions, JdbcTypeFactory, IdentifierProcessing)}
90+
* {@link #BasicJdbcConverter(RelationalMappingContext, RelationResolver, CustomConversions, JdbcTypeFactory, IdentifierProcessing)}
9091
* (MappingContext, RelationResolver, JdbcTypeFactory)} to convert arrays and large objects into JDBC-specific types.
9192
*
9293
* @param context must not be {@literal null}.
9394
* @param relationResolver used to fetch additional relations from the database. Must not be {@literal null}.
9495
*/
9596
public BasicJdbcConverter(
96-
MappingContext<? extends RelationalPersistentEntity<?>, ? extends RelationalPersistentProperty> context,
97+
RelationalMappingContext context,
9798
RelationResolver relationResolver) {
9899

99100
super(context, new JdbcCustomConversions());
@@ -116,7 +117,7 @@ public BasicJdbcConverter(
116117
* @since 2.0
117118
*/
118119
public BasicJdbcConverter(
119-
MappingContext<? extends RelationalPersistentEntity<?>, ? extends RelationalPersistentProperty> context,
120+
RelationalMappingContext context,
120121
RelationResolver relationResolver, CustomConversions conversions, JdbcTypeFactory typeFactory,
121122
IdentifierProcessing identifierProcessing) {
122123

@@ -300,12 +301,13 @@ private JdbcValue tryToConvertToJdbcValue(@Nullable Object value) {
300301

301302
@Override
302303
public <T> T mapRow(RelationalPersistentEntity<T> entity, ResultSet resultSet, Object key) {
303-
return new ReadingContext<T>(new PersistentPropertyPathExtension(getMappingContext(), entity),
304+
return new ReadingContext<T>(getMappingContext().getAggregatePath( entity),
304305
new ResultSetAccessor(resultSet), Identifier.empty(), key).mapRow();
305306
}
306307

308+
307309
@Override
308-
public <T> T mapRow(PersistentPropertyPathExtension path, ResultSet resultSet, Identifier identifier, Object key) {
310+
public <T> T mapRow(AggregatePath path, ResultSet resultSet, Identifier identifier, Object key) {
309311
return new ReadingContext<T>(path, new ResultSetAccessor(resultSet), identifier, key).mapRow();
310312
}
311313

@@ -350,8 +352,8 @@ private class ReadingContext<T> {
350352

351353
private final RelationalPersistentEntity<T> entity;
352354

353-
private final PersistentPropertyPathExtension rootPath;
354-
private final PersistentPropertyPathExtension path;
355+
private final AggregatePath rootPath;
356+
private final AggregatePath path;
355357
private final Identifier identifier;
356358
private final Object key;
357359

@@ -360,26 +362,27 @@ private class ReadingContext<T> {
360362
private final ResultSetAccessor accessor;
361363

362364
@SuppressWarnings("unchecked")
363-
private ReadingContext(PersistentPropertyPathExtension rootPath, ResultSetAccessor accessor, Identifier identifier,
365+
private ReadingContext(AggregatePath rootPath, ResultSetAccessor accessor, Identifier identifier,
364366
Object key) {
365367
RelationalPersistentEntity<T> entity = (RelationalPersistentEntity<T>) rootPath.getLeafEntity();
366368

367369
Assert.notNull(entity, "The rootPath must point to an entity");
368370

369371
this.entity = entity;
370372
this.rootPath = rootPath;
371-
this.path = new PersistentPropertyPathExtension(getMappingContext(), this.entity);
373+
this.path = getMappingContext().getAggregatePath( this.entity);
372374
this.identifier = identifier;
373375
this.key = key;
374376
this.propertyValueProvider = new JdbcPropertyValueProvider(path, accessor);
375377
this.backReferencePropertyValueProvider = new JdbcBackReferencePropertyValueProvider(path, accessor);
376378
this.accessor = accessor;
377379
}
378380

379-
private ReadingContext(RelationalPersistentEntity<T> entity, PersistentPropertyPathExtension rootPath,
380-
PersistentPropertyPathExtension path, Identifier identifier, Object key,
381+
private ReadingContext(RelationalPersistentEntity<T> entity, AggregatePath rootPath,
382+
AggregatePath path, Identifier identifier, Object key,
381383
JdbcPropertyValueProvider propertyValueProvider,
382384
JdbcBackReferencePropertyValueProvider backReferencePropertyValueProvider, ResultSetAccessor accessor) {
385+
383386
this.entity = entity;
384387
this.rootPath = rootPath;
385388
this.path = path;

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

+6-7
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@
2828
import org.springframework.data.domain.Sort;
2929
import org.springframework.data.mapping.PersistentPropertyPath;
3030
import org.springframework.data.relational.core.conversion.IdValueSource;
31+
import org.springframework.data.relational.core.mapping.AggregatePath;
3132
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
3233
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
3334
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
3435
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
3536
import org.springframework.data.relational.core.query.Query;
36-
import org.springframework.data.relational.core.sql.IdentifierProcessing;
3737
import org.springframework.data.relational.core.sql.LockMode;
3838
import org.springframework.data.relational.core.sql.SqlIdentifier;
3939
import org.springframework.jdbc.core.RowMapper;
@@ -297,8 +297,8 @@ public Iterable<Object> findAllByPath(Identifier identifier,
297297
Assert.notNull(identifier, "identifier must not be null");
298298
Assert.notNull(propertyPath, "propertyPath must not be null");
299299

300-
PersistentPropertyPathExtension path = new PersistentPropertyPathExtension(context, propertyPath);
301-
Class<?> actualType = path.getActualType();
300+
AggregatePath path = context.getAggregatePath(propertyPath);
301+
Class<?> actualType = path.getLeafEntity().getType();
302302

303303
String findAllByProperty = sql(actualType) //
304304
.getFindAllByProperty(identifier, propertyPath);
@@ -339,8 +339,7 @@ public <T> Optional<T> findOne(Query query, Class<T> domainType) {
339339
String sqlQuery = sql(domainType).selectByQuery(query, parameterSource);
340340

341341
try {
342-
return Optional.ofNullable(
343-
operations.queryForObject(sqlQuery, parameterSource, getEntityRowMapper(domainType)));
342+
return Optional.ofNullable(operations.queryForObject(sqlQuery, parameterSource, getEntityRowMapper(domainType)));
344343
} catch (EmptyResultDataAccessException e) {
345344
return Optional.empty();
346345
}
@@ -394,11 +393,11 @@ private <T> EntityRowMapper<T> getEntityRowMapper(Class<T> domainType) {
394393
return new EntityRowMapper<>(getRequiredPersistentEntity(domainType), converter);
395394
}
396395

397-
private EntityRowMapper<?> getEntityRowMapper(PersistentPropertyPathExtension path, Identifier identifier) {
396+
private EntityRowMapper<?> getEntityRowMapper(AggregatePath path, Identifier identifier) {
398397
return new EntityRowMapper<>(path, converter, identifier);
399398
}
400399

401-
private RowMapper<?> getMapEntityRowMapper(PersistentPropertyPathExtension path, Identifier identifier) {
400+
private RowMapper<?> getMapEntityRowMapper(AggregatePath path, Identifier identifier) {
402401

403402
SqlIdentifier keyColumn = path.getQualifierColumn();
404403
Assert.notNull(keyColumn, () -> "KeyColumn must not be null for " + path);

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

+17-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import java.sql.ResultSet;
1919

20+
import org.springframework.data.relational.core.mapping.AggregatePath;
2021
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
2122
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
2223
import org.springframework.jdbc.core.RowMapper;
@@ -35,13 +36,28 @@
3536
public class EntityRowMapper<T> implements RowMapper<T> {
3637

3738
private final RelationalPersistentEntity<T> entity;
38-
private final PersistentPropertyPathExtension path;
39+
private final AggregatePath path;
3940
private final JdbcConverter converter;
4041
private final Identifier identifier;
4142

43+
/**
44+
*
45+
*
46+
* @deprecated use {@link EntityRowMapper#EntityRowMapper(AggregatePath, JdbcConverter, Identifier)} instead
47+
*/
48+
@Deprecated(since = "3.2", forRemoval = true)
4249
@SuppressWarnings("unchecked")
4350
public EntityRowMapper(PersistentPropertyPathExtension path, JdbcConverter converter, Identifier identifier) {
4451

52+
this.entity = (RelationalPersistentEntity<T>) path.getLeafEntity();
53+
this.path = path.getAggregatePath();
54+
this.converter = converter;
55+
this.identifier = identifier;
56+
}
57+
58+
@SuppressWarnings("unchecked")
59+
public EntityRowMapper(AggregatePath path, JdbcConverter converter, Identifier identifier) {
60+
4561
this.entity = (RelationalPersistentEntity<T>) path.getLeafEntity();
4662
this.path = path;
4763
this.converter = converter;

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

+3-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package org.springframework.data.jdbc.core.convert;
1717

1818
import org.springframework.data.mapping.model.PropertyValueProvider;
19+
import org.springframework.data.relational.core.mapping.AggregatePath;
1920
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
2021
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
2122
import org.springframework.data.relational.core.sql.IdentifierProcessing;
@@ -31,14 +32,14 @@
3132
*/
3233
class JdbcBackReferencePropertyValueProvider implements PropertyValueProvider<RelationalPersistentProperty> {
3334

34-
private final PersistentPropertyPathExtension basePath;
35+
private final AggregatePath basePath;
3536
private final ResultSetAccessor resultSet;
3637

3738
/**
3839
* @param basePath path from the aggregate root relative to which all properties get resolved.
3940
* @param resultSet the {@link ResultSetAccessor} from which to obtain the actual values.
4041
*/
41-
JdbcBackReferencePropertyValueProvider(PersistentPropertyPathExtension basePath, ResultSetAccessor resultSet) {
42+
JdbcBackReferencePropertyValueProvider(AggregatePath basePath, ResultSetAccessor resultSet) {
4243

4344
this.resultSet = resultSet;
4445
this.basePath = basePath;

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

+23-1
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,11 @@
1919
import java.sql.SQLType;
2020

2121
import org.springframework.data.jdbc.core.mapping.JdbcValue;
22+
import org.springframework.data.mapping.context.MappingContext;
2223
import org.springframework.data.relational.core.conversion.RelationalConverter;
24+
import org.springframework.data.relational.core.mapping.AggregatePath;
2325
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
26+
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
2427
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
2528
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
2629
import org.springframework.data.util.TypeInformation;
@@ -67,8 +70,24 @@ public interface JdbcConverter extends RelationalConverter {
6770
* @param key primary key.
6871
* @param <T>
6972
* @return
73+
* @deprecated use {@link #mapRow(AggregatePath, ResultSet, Identifier, Object)} instead.
7074
*/
71-
<T> T mapRow(PersistentPropertyPathExtension path, ResultSet resultSet, Identifier identifier, Object key);
75+
@Deprecated(since = "3.2", forRemoval = true)
76+
default <T> T mapRow(PersistentPropertyPathExtension path, ResultSet resultSet, Identifier identifier, Object key){
77+
return mapRow(path.getAggregatePath(), resultSet, identifier, key);
78+
};
79+
80+
/**
81+
* Read the current row from {@link ResultSet} to an {@link AggregatePath#getLeafEntity()} entity}.
82+
*
83+
* @param path path to the owning property.
84+
* @param resultSet the {@link ResultSet} to read from.
85+
* @param identifier entity identifier.
86+
* @param key primary key.
87+
* @param <T>
88+
* @return
89+
*/
90+
<T> T mapRow(AggregatePath path, ResultSet resultSet, Identifier identifier, Object key);
7291

7392
/**
7493
* The type to be used to store this property in the database. Multidimensional arrays are unwrapped to reflect a
@@ -88,4 +107,7 @@ public interface JdbcConverter extends RelationalConverter {
88107
* @since 2.0
89108
*/
90109
SQLType getTargetSqlType(RelationalPersistentProperty property);
110+
111+
@Override
112+
RelationalMappingContext getMappingContext();
91113
}

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

+26
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package org.springframework.data.jdbc.core.convert;
1717

18+
import org.springframework.data.relational.core.mapping.AggregatePath;
1819
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
1920
import org.springframework.lang.Nullable;
2021
import org.springframework.util.Assert;
@@ -39,9 +40,20 @@ public static JdbcIdentifierBuilder empty() {
3940

4041
/**
4142
* Creates ParentKeys with backreference for the given path and value of the parents id.
43+
*
44+
* @deprecated Use {@link #forBackReferences(JdbcConverter, AggregatePath, Object)} instead.
4245
*/
46+
@Deprecated(since = "3.2", forRemoval = true)
4347
public static JdbcIdentifierBuilder forBackReferences(JdbcConverter converter, PersistentPropertyPathExtension path,
4448
@Nullable Object value) {
49+
return forBackReferences(converter, path.getAggregatePath(), value);
50+
}
51+
52+
/**
53+
* Creates ParentKeys with backreference for the given path and value of the parents id.
54+
*/
55+
public static JdbcIdentifierBuilder forBackReferences(JdbcConverter converter, AggregatePath path,
56+
@Nullable Object value) {
4557

4658
Identifier identifier = Identifier.of( //
4759
path.getReverseColumnName(), //
@@ -59,8 +71,22 @@ public static JdbcIdentifierBuilder forBackReferences(JdbcConverter converter, P
5971
* @param value map key or list index qualifying the map identified by {@code path}. Must not be {@literal null}.
6072
* @return this builder. Guaranteed to be not {@literal null}.
6173
*/
74+
@Deprecated
6275
public JdbcIdentifierBuilder withQualifier(PersistentPropertyPathExtension path, Object value) {
6376

77+
return withQualifier(path.getAggregatePath(), value);
78+
}
79+
80+
81+
/**
82+
* Adds a qualifier to the identifier to build. A qualifier is a map key or a list index.
83+
*
84+
* @param path path to the map that gets qualified by {@code value}. Must not be {@literal null}.
85+
* @param value map key or list index qualifying the map identified by {@code path}. Must not be {@literal null}.
86+
* @return this builder. Guaranteed to be not {@literal null}.
87+
*/
88+
public JdbcIdentifierBuilder withQualifier(AggregatePath path, Object value) {
89+
6490
Assert.notNull(path, "Path must not be null");
6591
Assert.notNull(value, "Value must not be null");
6692

0 commit comments

Comments
 (0)