Skip to content

Commit 4cf07be

Browse files
committed
Polishing.
Original pull request #1604 See #1586
1 parent f600442 commit 4cf07be

File tree

8 files changed

+81
-47
lines changed

8 files changed

+81
-47
lines changed

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

+46-24
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
/**
3838
* Reads complete Aggregates from the database, by generating appropriate SQL using a {@link SingleQuerySqlGenerator}
3939
* through {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate}. Results are converterd into an
40-
* intermediate {@link ResultSetRowDocumentExtractor RowDocument} and mapped via
40+
* intermediate {@link RowDocumentResultSetExtractor RowDocument} and mapped via
4141
* {@link org.springframework.data.relational.core.conversion.RelationalConverter#read(Class, RowDocument)}.
4242
*
4343
* @param <T> the type of aggregate produced by this reader.
@@ -47,23 +47,23 @@
4747
*/
4848
class AggregateReader<T> {
4949

50-
private final RelationalPersistentEntity<T> entity;
50+
private final RelationalPersistentEntity<T> aggregate;
5151
private final org.springframework.data.relational.core.sqlgeneration.SqlGenerator sqlGenerator;
5252
private final JdbcConverter converter;
5353
private final NamedParameterJdbcOperations jdbcTemplate;
54-
private final ResultSetRowDocumentExtractor extractor;
54+
private final RowDocumentResultSetExtractor extractor;
5555

5656
AggregateReader(Dialect dialect, JdbcConverter converter, AliasFactory aliasFactory,
57-
NamedParameterJdbcOperations jdbcTemplate, RelationalPersistentEntity<T> entity) {
57+
NamedParameterJdbcOperations jdbcTemplate, RelationalPersistentEntity<T> aggregate) {
5858

5959
this.converter = converter;
60-
this.entity = entity;
60+
this.aggregate = aggregate;
6161
this.jdbcTemplate = jdbcTemplate;
6262

6363
this.sqlGenerator = new CachingSqlGenerator(
64-
new SingleQuerySqlGenerator(converter.getMappingContext(), aliasFactory, dialect, entity));
64+
new SingleQuerySqlGenerator(converter.getMappingContext(), aliasFactory, dialect, aggregate));
6565

66-
this.extractor = new ResultSetRowDocumentExtractor(converter.getMappingContext(),
66+
this.extractor = new RowDocumentResultSetExtractor(converter.getMappingContext(),
6767
createPathToColumnMapping(aliasFactory));
6868
}
6969

@@ -74,44 +74,66 @@ public List<T> findAll() {
7474
@Nullable
7575
public T findById(Object id) {
7676

77-
id = converter.writeValue(id, entity.getRequiredIdProperty().getTypeInformation());
77+
id = converter.writeValue(id, aggregate.getRequiredIdProperty().getTypeInformation());
7878

79-
return jdbcTemplate.query(sqlGenerator.findById(), Map.of("id", id), rs -> {
80-
81-
Iterator<RowDocument> iterate = extractor.iterate(entity, rs);
82-
if (iterate.hasNext()) {
83-
84-
RowDocument object = iterate.next();
85-
if (iterate.hasNext()) {
86-
throw new IncorrectResultSizeDataAccessException(1);
87-
}
88-
return converter.read(entity.getType(), object);
89-
}
90-
return null;
91-
});
79+
return jdbcTemplate.query(sqlGenerator.findById(), Map.of("id", id), this::extractZeroOrOne);
9280
}
9381

9482
public Iterable<T> findAllById(Iterable<?> ids) {
9583

9684
List<Object> convertedIds = new ArrayList<>();
9785
for (Object id : ids) {
98-
convertedIds.add(converter.writeValue(id, entity.getRequiredIdProperty().getTypeInformation()));
86+
convertedIds.add(converter.writeValue(id, aggregate.getRequiredIdProperty().getTypeInformation()));
9987
}
10088

10189
return jdbcTemplate.query(sqlGenerator.findAllById(), Map.of("ids", convertedIds), this::extractAll);
10290
}
10391

92+
/**
93+
* Extracts a list of aggregates from the given {@link ResultSet} by utilizing the
94+
* {@link RowDocumentResultSetExtractor} and the {@link JdbcConverter}. When used as a method reference this conforms
95+
* to the {@link org.springframework.jdbc.core.ResultSetExtractor} contract.
96+
*
97+
* @param rs the {@link ResultSet} from which to extract the data. Must not be {(}@literal null}.
98+
* @return a {@code List} of aggregates, fully converted.
99+
* @throws SQLException
100+
*/
104101
private List<T> extractAll(ResultSet rs) throws SQLException {
105102

106-
Iterator<RowDocument> iterate = extractor.iterate(entity, rs);
103+
Iterator<RowDocument> iterate = extractor.iterate(aggregate, rs);
107104
List<T> resultList = new ArrayList<>();
108105
while (iterate.hasNext()) {
109-
resultList.add(converter.read(entity.getType(), iterate.next()));
106+
resultList.add(converter.read(aggregate.getType(), iterate.next()));
110107
}
111108

112109
return resultList;
113110
}
114111

112+
/**
113+
* Extracts a single aggregate or {@literal null} from the given {@link ResultSet} by utilizing the
114+
* {@link RowDocumentResultSetExtractor} and the {@link JdbcConverter}. When used as a method reference this conforms
115+
* to the {@link org.springframework.jdbc.core.ResultSetExtractor} contract.
116+
*
117+
* @param @param rs the {@link ResultSet} from which to extract the data. Must not be {(}@literal null}.
118+
* @return The single instance when the conversion results in exactly one instance. If the {@literal ResultSet} is empty, null is returned.
119+
* @throws SQLException
120+
* @throws IncorrectResultSizeDataAccessException when the conversion yields more than one instance.
121+
*/
122+
@Nullable
123+
private T extractZeroOrOne(ResultSet rs) throws SQLException {
124+
125+
Iterator<RowDocument> iterate = extractor.iterate(aggregate, rs);
126+
if (iterate.hasNext()) {
127+
128+
RowDocument object = iterate.next();
129+
if (iterate.hasNext()) {
130+
throw new IncorrectResultSizeDataAccessException(1);
131+
}
132+
return converter.read(aggregate.getType(), object);
133+
}
134+
return null;
135+
}
136+
115137
private PathToColumnMapping createPathToColumnMapping(AliasFactory aliasFactory) {
116138
return new PathToColumnMapping() {
117139
@Override

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

+8-5
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ protected static class AggregateContext<RS> {
7979

8080
protected AggregateContext(TabularResultAdapter<RS> adapter, RelationalMappingContext context,
8181
PathToColumnMapping propertyToColumn, Map<String, Integer> columnMap) {
82+
8283
this.adapter = adapter;
8384
this.context = context;
8485
this.propertyToColumn = propertyToColumn;
@@ -183,6 +184,7 @@ protected static class RowDocumentSink<RS> extends TabularSink<RS> {
183184

184185
public RowDocumentSink(AggregateContext<RS> aggregateContext, RelationalPersistentEntity<?> entity,
185186
AggregatePath basePath) {
187+
186188
this.aggregateContext = aggregateContext;
187189
this.entity = entity;
188190
this.basePath = basePath;
@@ -234,11 +236,13 @@ private void readEntity(RS row, RowDocument document, AggregatePath basePath,
234236
AggregatePath path = basePath.append(property);
235237

236238
if (property.isEntity() && !property.isEmbedded() && (property.isCollectionLike() || property.isQualified())) {
239+
237240
readerState.put(property, new ContainerSink<>(aggregateContext, property, path));
238241
continue;
239242
}
240243

241244
if (property.isEmbedded()) {
245+
242246
RelationalPersistentEntity<?> embeddedEntity = aggregateContext.getRequiredPersistentEntity(property);
243247
readEntity(row, document, path, embeddedEntity);
244248
continue;
@@ -286,11 +290,7 @@ boolean hasResult() {
286290
}
287291
}
288292

289-
if (result.isEmpty() && key == null) {
290-
return false;
291-
}
292-
293-
return true;
293+
return !(result.isEmpty() && key == null);
294294
}
295295

296296
@Override
@@ -308,6 +308,7 @@ RowDocument getResult() {
308308

309309
@Override
310310
void reset() {
311+
311312
result = null;
312313
readerState.clear();
313314
}
@@ -326,6 +327,7 @@ private static class SingleColumnSink<RS> extends TabularSink<RS> {
326327
private @Nullable Object value;
327328

328329
public SingleColumnSink(AggregateContext<RS> aggregateContext, AggregatePath path) {
330+
329331
this.aggregateContext = aggregateContext;
330332
this.columnName = path.getColumnInfo().name().getReference();
331333
}
@@ -431,6 +433,7 @@ public boolean hasResult() {
431433
public Object getResult() {
432434

433435
if (componentReader.hasResult()) {
436+
434437
container.add(this.key, componentReader.getResult());
435438
componentReader.reset();
436439
}
+7-3
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,13 @@
4040
* @author Mark Paluch
4141
* @since 3.2
4242
*/
43-
class ResultSetRowDocumentExtractor {
43+
class RowDocumentResultSetExtractor {
4444

4545
private final RelationalMappingContext context;
4646
private final PathToColumnMapping propertyToColumn;
4747

48-
ResultSetRowDocumentExtractor(RelationalMappingContext context, PathToColumnMapping propertyToColumn) {
48+
RowDocumentResultSetExtractor(RelationalMappingContext context, PathToColumnMapping propertyToColumn) {
49+
4950
this.context = context;
5051
this.propertyToColumn = propertyToColumn;
5152
}
@@ -54,11 +55,14 @@ class ResultSetRowDocumentExtractor {
5455
* Adapter to extract values and column metadata from a {@link ResultSet}.
5556
*/
5657
enum ResultSetAdapter implements TabularResultAdapter<ResultSet> {
58+
5759
INSTANCE;
5860

5961
@Override
6062
public Object getObject(ResultSet row, int index) {
63+
6164
try {
65+
6266
Object resultSetValue = JdbcUtils.getResultSetValue(row, index);
6367

6468
if (resultSetValue instanceof Array a) {
@@ -75,6 +79,7 @@ public Object getObject(ResultSet row, int index) {
7579
public Map<String, Integer> getColumnMap(ResultSet result) {
7680

7781
try {
82+
7883
ResultSetMetaData metaData = result.getMetaData();
7984
Map<String, Integer> columns = new LinkedCaseInsensitiveMap<>(metaData.getColumnCount());
8085

@@ -201,5 +206,4 @@ public RowDocument next() {
201206
return reader.getResult();
202207
}
203208
}
204-
205209
}
+14-12
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,19 @@
4141
import org.springframework.data.relational.domain.RowDocument;
4242

4343
/**
44-
* Unit tests for the {@link ResultSetRowDocumentExtractor}.
44+
* Unit tests for the {@link RowDocumentResultSetExtractor}.
4545
*
4646
* @author Jens Schauder
4747
* @author Mark Paluch
4848
*/
49-
public class ResultSetRowDocumentExtractorUnitTests {
49+
public class RowDocumentResultSetExtractorUnitTests {
5050

5151
RelationalMappingContext context = new JdbcMappingContext(new DefaultNamingStrategy());
5252

5353
private final PathToColumnMapping column = new PathToColumnMapping() {
5454
@Override
5555
public String column(AggregatePath path) {
56-
return ResultSetRowDocumentExtractorUnitTests.this.column(path);
56+
return RowDocumentResultSetExtractorUnitTests.this.column(path);
5757
}
5858

5959
@Override
@@ -62,7 +62,7 @@ public String keyColumn(AggregatePath path) {
6262
}
6363
};
6464

65-
ResultSetRowDocumentExtractor documentExtractor = new ResultSetRowDocumentExtractor(context, column);
65+
RowDocumentResultSetExtractor documentExtractor = new RowDocumentResultSetExtractor(context, column);
6666

6767
@Test // GH-1446
6868
void emptyResultSetYieldsEmptyResult() {
@@ -272,8 +272,7 @@ void extractSingleUnorderedListReference() {
272272
@Nested
273273
class Maps {
274274

275-
@Test
276-
// GH-1446
275+
@Test // GH-1446
277276
void extractSingleMapReference() {
278277

279278
testerFor(WithMaps.class).resultSet(rsc -> {
@@ -288,8 +287,7 @@ void extractSingleMapReference() {
288287
});
289288
}
290289

291-
@Test
292-
// GH-1446
290+
@Test // GH-1446
293291
void extractMultipleCollectionReference() {
294292

295293
testerFor(WithMapsAndList.class).resultSet(rsc -> {
@@ -307,8 +305,7 @@ void extractMultipleCollectionReference() {
307305
});
308306
}
309307

310-
@Test
311-
// GH-1446
308+
@Test // GH-1446
312309
void extractNestedMapsWithId() {
313310

314311
testerFor(WithMaps.class).resultSet(rsc -> {
@@ -529,16 +526,19 @@ public ResultSetConfigurer withRow(Object... rowValues) {
529526
private static class DocumentTester extends AbstractTester {
530527

531528
private final Class<?> entityType;
532-
private final ResultSetRowDocumentExtractor extractor;
529+
private final RowDocumentResultSetExtractor extractor;
530+
531+
DocumentTester(Class<?> entityType, RelationalMappingContext context, RowDocumentResultSetExtractor extractor) {
533532

534-
DocumentTester(Class<?> entityType, RelationalMappingContext context, ResultSetRowDocumentExtractor extractor) {
535533
super(entityType, context);
534+
536535
this.entityType = entityType;
537536
this.extractor = extractor;
538537
}
539538

540539
@Override
541540
DocumentTester resultSet(Consumer<ResultSetConfigurer> configuration) {
541+
542542
super.resultSet(configuration);
543543
return this;
544544
}
@@ -561,7 +561,9 @@ private static class ResultSetTester extends AbstractTester {
561561

562562
@Override
563563
ResultSetTester resultSet(Consumer<ResultSetConfigurer> configuration) {
564+
564565
super.resultSet(configuration);
566+
565567
return this;
566568
}
567569

spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/DocumentPropertyAccessor.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@
2727
* {@link org.springframework.expression.PropertyAccessor} to allow entity based field access to
2828
* {@link org.springframework.data.relational.domain.RowDocument}s.
2929
*
30-
* @author Oliver Gierke
31-
* @author Christoph Strobl
30+
* @author Mark Paluch
3231
*/
3332
class DocumentPropertyAccessor extends MapAccessor {
3433

spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/MappingRelationalConverter.java

+4
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,9 @@ public class MappingRelationalConverter extends BasicRelationalConverter {
6767
* @param context must not be {@literal null}.
6868
*/
6969
public MappingRelationalConverter(RelationalMappingContext context) {
70+
7071
super(context);
72+
7173
this.spELContext = new SpELContext(DocumentPropertyAccessor.INSTANCE);
7274
}
7375

@@ -79,7 +81,9 @@ public MappingRelationalConverter(RelationalMappingContext context) {
7981
* @param conversions must not be {@literal null}.
8082
*/
8183
public MappingRelationalConverter(RelationalMappingContext context, CustomConversions conversions) {
84+
8285
super(context, conversions);
86+
8387
this.spELContext = new SpELContext(DocumentPropertyAccessor.INSTANCE);
8488
}
8589

spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/RowDocumentAccessor.java

-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@ public Object get(RelationalPersistentProperty property) {
9494
* @param property must not be {@literal null}.
9595
* @return {@literal true} if no non {@literal null} value present.
9696
*/
97-
@SuppressWarnings("unchecked")
9897
public boolean hasValue(RelationalPersistentProperty property) {
9998

10099
Assert.notNull(property, "Property must not be null");

spring-data-relational/src/main/java/org/springframework/data/relational/domain/RowDocument.java

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public RowDocument() {
4242
}
4343

4444
public RowDocument(Map<String, ? extends Object> map) {
45+
4546
this.delegate = new LinkedCaseInsensitiveMap<>();
4647
this.delegate.putAll(delegate);
4748
}

0 commit comments

Comments
 (0)