Skip to content

Commit d9b5488

Browse files
committed
Polishing.
Extract Single Query Loading branching to SingleQueryFallbackDataAccessStrategy. Inline AggregateReaderFactory into SingleQueryDataAccessStrategy. Move CachingSqlGenerator to AggregateReader as caching root. Introduce DataAccessStrategyFactory to encapsulate configuration. Fix Javadoc tag ordering. Remove superfluous MappingContext parameters when Converter is available. Simplify code. Reformat code. Reorder Functions methods. Tweak Javadoc, move composite function into SingleQuerySqlGenerator. See #1446 See #1450 See #1445 Original pull request: #1572
1 parent 93821f5 commit d9b5488

25 files changed

+439
-333
lines changed

Diff for: spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/AggregateReader.java

+61-35
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
1716
package org.springframework.data.jdbc.core.convert;
1817

1918
import java.util.ArrayList;
@@ -24,71 +23,59 @@
2423
import org.springframework.dao.IncorrectResultSizeDataAccessException;
2524
import org.springframework.data.relational.core.dialect.Dialect;
2625
import org.springframework.data.relational.core.mapping.AggregatePath;
27-
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
2826
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
2927
import org.springframework.data.relational.core.sqlgeneration.AliasFactory;
30-
import org.springframework.data.relational.core.sqlgeneration.CachingSqlGenerator;
3128
import org.springframework.data.relational.core.sqlgeneration.SingleQuerySqlGenerator;
29+
import org.springframework.data.relational.core.sqlgeneration.SqlGenerator;
3230
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
31+
import org.springframework.lang.Nullable;
3332
import org.springframework.util.Assert;
3433

3534
/**
3635
* Reads complete Aggregates from the database, by generating appropriate SQL using a {@link SingleQuerySqlGenerator}
3736
* and a matching {@link AggregateResultSetExtractor} and invoking a
3837
* {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate}
39-
*
38+
*
4039
* @param <T> the type of aggregate produced by this reader.
41-
* @since 3.2
4240
* @author Jens Schauder
41+
* @since 3.2
4342
*/
4443
class AggregateReader<T> {
4544

46-
private final RelationalMappingContext mappingContext;
4745
private final RelationalPersistentEntity<T> aggregate;
48-
private final AliasFactory aliasFactory;
4946
private final org.springframework.data.relational.core.sqlgeneration.SqlGenerator sqlGenerator;
5047
private final JdbcConverter converter;
5148
private final NamedParameterJdbcOperations jdbcTemplate;
49+
private final AggregateResultSetExtractor<T> extractor;
5250

53-
AggregateReader(RelationalMappingContext mappingContext, Dialect dialect, JdbcConverter converter,
51+
AggregateReader(Dialect dialect, JdbcConverter converter, AliasFactory aliasFactory,
5452
NamedParameterJdbcOperations jdbcTemplate, RelationalPersistentEntity<T> aggregate) {
5553

56-
this.mappingContext = mappingContext;
57-
58-
this.aggregate = aggregate;
5954
this.converter = converter;
55+
this.aggregate = aggregate;
6056
this.jdbcTemplate = jdbcTemplate;
6157

62-
this.sqlGenerator = new CachingSqlGenerator(new SingleQuerySqlGenerator(mappingContext, dialect, aggregate));
63-
this.aliasFactory = sqlGenerator.getAliasFactory();
58+
this.sqlGenerator = new CachingSqlGenerator(
59+
new SingleQuerySqlGenerator(converter.getMappingContext(), aliasFactory, dialect, aggregate));
60+
61+
this.extractor = new AggregateResultSetExtractor<>(aggregate, converter, createPathToColumnMapping(aliasFactory));
6462
}
6563

6664
public List<T> findAll() {
6765

68-
String sql = sqlGenerator.findAll();
69-
70-
PathToColumnMapping pathToColumn = createPathToColumnMapping(aliasFactory);
71-
AggregateResultSetExtractor<T> extractor = new AggregateResultSetExtractor<>(mappingContext, aggregate, converter,
72-
pathToColumn);
73-
74-
Iterable<T> result = jdbcTemplate.query(sql, extractor);
66+
Iterable<T> result = jdbcTemplate.query(sqlGenerator.findAll(), extractor);
7567

7668
Assert.state(result != null, "result is null");
7769

7870
return (List<T>) result;
7971
}
8072

73+
@Nullable
8174
public T findById(Object id) {
8275

83-
PathToColumnMapping pathToColumn = createPathToColumnMapping(aliasFactory);
84-
AggregateResultSetExtractor<T> extractor = new AggregateResultSetExtractor<>(mappingContext, aggregate, converter,
85-
pathToColumn);
86-
87-
String sql = sqlGenerator.findById();
88-
8976
id = converter.writeValue(id, aggregate.getRequiredIdProperty().getTypeInformation());
9077

91-
Iterator<T> result = jdbcTemplate.query(sql, Map.of("id", id), extractor).iterator();
78+
Iterator<T> result = jdbcTemplate.query(sqlGenerator.findById(), Map.of("id", id), extractor).iterator();
9279

9380
T returnValue = result.hasNext() ? result.next() : null;
9481

@@ -101,18 +88,12 @@ public T findById(Object id) {
10188

10289
public Iterable<T> findAllById(Iterable<?> ids) {
10390

104-
PathToColumnMapping pathToColumn = createPathToColumnMapping(aliasFactory);
105-
AggregateResultSetExtractor<T> extractor = new AggregateResultSetExtractor<>(mappingContext, aggregate, converter,
106-
pathToColumn);
107-
108-
String sql = sqlGenerator.findAllById();
109-
11091
List<Object> convertedIds = new ArrayList<>();
11192
for (Object id : ids) {
11293
convertedIds.add(converter.writeValue(id, aggregate.getRequiredIdProperty().getTypeInformation()));
11394
}
11495

115-
return jdbcTemplate.query(sql, Map.of("ids", convertedIds), extractor);
96+
return jdbcTemplate.query(sqlGenerator.findAllById(), Map.of("ids", convertedIds), extractor);
11697
}
11798

11899
private PathToColumnMapping createPathToColumnMapping(AliasFactory aliasFactory) {
@@ -121,7 +102,7 @@ private PathToColumnMapping createPathToColumnMapping(AliasFactory aliasFactory)
121102
public String column(AggregatePath path) {
122103

123104
String alias = aliasFactory.getColumnAlias(path);
124-
Assert.notNull(alias, () -> "alias for >" + path + "<must not be null");
105+
Assert.notNull(alias, () -> "alias for >" + path + "< must not be null");
125106
return alias;
126107
}
127108

@@ -131,4 +112,49 @@ public String keyColumn(AggregatePath path) {
131112
}
132113
};
133114
}
115+
116+
/**
117+
* A wrapper for the {@link org.springframework.data.relational.core.sqlgeneration.SqlGenerator} that caches the
118+
* generated statements.
119+
*
120+
* @since 3.2
121+
* @author Jens Schauder
122+
*/
123+
static class CachingSqlGenerator implements org.springframework.data.relational.core.sqlgeneration.SqlGenerator {
124+
125+
private final org.springframework.data.relational.core.sqlgeneration.SqlGenerator delegate;
126+
127+
private final String findAll;
128+
private final String findById;
129+
private final String findAllById;
130+
131+
public CachingSqlGenerator(SqlGenerator delegate) {
132+
133+
this.delegate = delegate;
134+
135+
findAll = delegate.findAll();
136+
findById = delegate.findById();
137+
findAllById = delegate.findAllById();
138+
}
139+
140+
@Override
141+
public String findAll() {
142+
return findAll;
143+
}
144+
145+
@Override
146+
public String findById() {
147+
return findById;
148+
}
149+
150+
@Override
151+
public String findAllById() {
152+
return findAllById;
153+
}
154+
155+
@Override
156+
public AliasFactory getAliasFactory() {
157+
return delegate.getAliasFactory();
158+
}
159+
}
134160
}

Diff for: spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/AggregateReaderFactory.java

-49
This file was deleted.

Diff for: spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/AggregateResultSetExtractor.java

+14-16
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,10 @@
4848
* which looks somewhat how one would represent an aggregate in a single excel table. The first row contains data of the
4949
* aggregate root, any single valued reference and the first element of any collection. Following rows do NOT repeat the
5050
* aggregate root data but contain data of second elements of any collections. For details see accompanying unit tests.
51-
*
51+
*
5252
* @param <T> the type of aggregates to extract
53-
* @since 3.2
5453
* @author Jens Schauder
54+
* @since 3.2
5555
*/
5656
class AggregateResultSetExtractor<T> implements ResultSetExtractor<Iterable<T>> {
5757

@@ -61,26 +61,23 @@ class AggregateResultSetExtractor<T> implements ResultSetExtractor<Iterable<T>>
6161
private final PathToColumnMapping propertyToColumn;
6262

6363
/**
64-
* @param context the {@link org.springframework.data.mapping.context.MappingContext} providing the metadata for the
65-
* aggregate and its entity. Must not be {@literal null}.
6664
* @param rootEntity the aggregate root. Must not be {@literal null}.
6765
* @param converter Used for converting objects from the database to whatever is required by the aggregate. Must not
6866
* be {@literal null}.
6967
* @param pathToColumn a mapping from {@link org.springframework.data.relational.core.mapping.AggregatePath} to the
7068
* column of the {@link ResultSet} that holds the data for that
7169
* {@link org.springframework.data.relational.core.mapping.AggregatePath}.
7270
*/
73-
AggregateResultSetExtractor(RelationalMappingContext context, RelationalPersistentEntity<T> rootEntity,
71+
AggregateResultSetExtractor(RelationalPersistentEntity<T> rootEntity,
7472
JdbcConverter converter, PathToColumnMapping pathToColumn) {
7573

76-
Assert.notNull(context, "context must not be null");
7774
Assert.notNull(rootEntity, "rootEntity must not be null");
7875
Assert.notNull(converter, "converter must not be null");
7976
Assert.notNull(pathToColumn, "propertyToColumn must not be null");
8077

81-
this.context = context;
8278
this.rootEntity = rootEntity;
8379
this.converter = converter;
80+
this.context = converter.getMappingContext();
8481
this.propertyToColumn = pathToColumn;
8582
}
8683

@@ -131,7 +128,7 @@ private Object hydrateInstance(EntityInstantiator instantiator, ResultSetParamet
131128

132129
/**
133130
* A {@link Reader} is responsible for reading a single entity or collection of entities from a set of columns
134-
*
131+
*
135132
* @since 3.2
136133
* @author Jens Schauder
137134
*/
@@ -145,14 +142,14 @@ private interface Reader {
145142
/**
146143
* Checks if this {@literal Reader} has all the data needed for a complete result, or if it needs to read further
147144
* rows.
148-
*
145+
*
149146
* @return the result of the check.
150147
*/
151148
boolean hasResult();
152149

153150
/**
154151
* Constructs the result, returns it and resets the state of the reader to read the next instance.
155-
*
152+
*
156153
* @return an instance of whatever this {@literal Reader} is supposed to read.
157154
*/
158155
@Nullable
@@ -161,7 +158,7 @@ private interface Reader {
161158

162159
/**
163160
* Adapts a {@link Map} to the interface of a {@literal Collection<Map.Entry<Object, Object>>}.
164-
*
161+
*
165162
* @since 3.2
166163
* @author Jens Schauder
167164
*/
@@ -221,7 +218,7 @@ public boolean add(Map.Entry<Object, Object> entry) {
221218

222219
/**
223220
* A {@link Reader} for reading entities.
224-
*
221+
*
225222
* @since 3.2
226223
* @author Jens Schauder
227224
*/
@@ -315,7 +312,7 @@ public String toString() {
315312

316313
/**
317314
* A {@link Reader} for reading collections of entities.
318-
*
315+
*
319316
* @since 3.2
320317
* @author Jens Schauder
321318
*/
@@ -413,7 +410,7 @@ public String toString() {
413410
/**
414411
* A {@link Reader} for reading collection entries. Most of the work is done by an {@link EntityReader}, but a
415412
* additional key column might get read. The result is
416-
*
413+
*
417414
* @since 3.2
418415
* @author Jens Schauder
419416
*/
@@ -459,8 +456,9 @@ public Object getResultAndReset() {
459456
}
460457

461458
/**
462-
* A {@link ParameterValueProvider} that provided the values for an entity from a continues set of rows in a {@link ResultSet}. These might be referenced entities or collections of such entities. {@link ResultSet}.
463-
*
459+
* A {@link ParameterValueProvider} that provided the values for an entity from a continues set of rows in a
460+
* {@link ResultSet}. These might be referenced entities or collections of such entities. {@link ResultSet}.
461+
*
464462
* @since 3.2
465463
* @author Jens Schauder
466464
*/

Diff for: spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/CachingResultSet.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@
2626
* Despite its name not really a {@link ResultSet}, but it offers the part of the {@literal ResultSet} API that is used
2727
* by {@link AggregateReader}. It allows peeking in the next row of a ResultSet by caching one row of the ResultSet.
2828
*
29-
* @since 3.2
3029
* @author Jens Schauder
30+
* @since 3.2
3131
*/
3232
class CachingResultSet {
3333

0 commit comments

Comments
 (0)