Skip to content

Commit 8e32af4

Browse files
committed
Polishing.
Consistently configure components using JdbcAggregateOperations. Reorder methods, refine dependency lookups. Refine JdbcAggregateTemplate dependency setup for easier object creation. Extend tests. Refine bean names to provide naming hints for easier bean lookup in case multiple beans are registered for the same type. See #687 Original pull request: #1704
1 parent d17bff8 commit 8e32af4

27 files changed

+641
-397
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,4 +341,5 @@ public interface JdbcAggregateOperations {
341341
* @return the {@link DataAccessStrategy}
342342
*/
343343
DataAccessStrategy getDataAccessStrategy();
344+
344345
}

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

Lines changed: 63 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@
2828
import java.util.stream.Stream;
2929
import java.util.stream.StreamSupport;
3030

31+
import org.springframework.beans.BeansException;
3132
import org.springframework.context.ApplicationContext;
33+
import org.springframework.context.ApplicationContextAware;
3234
import org.springframework.context.ApplicationEventPublisher;
3335
import org.springframework.data.domain.Page;
3436
import org.springframework.data.domain.Pageable;
@@ -70,132 +72,95 @@
7072
* @author Diego Krupitza
7173
* @author Sergey Korotaev
7274
* @author Mikhail Polivakha
73-
* @author Tomohiko Ozawa
7475
*/
75-
public class JdbcAggregateTemplate implements JdbcAggregateOperations {
76+
public class JdbcAggregateTemplate implements JdbcAggregateOperations, ApplicationContextAware {
7677

7778
private final EntityLifecycleEventDelegate eventDelegate = new EntityLifecycleEventDelegate();
7879
private final RelationalMappingContext context;
79-
8080
private final RelationalEntityDeleteWriter jdbcEntityDeleteWriter;
81-
8281
private final DataAccessStrategy accessStrategy;
8382
private final AggregateChangeExecutor executor;
8483
private final JdbcConverter converter;
8584

86-
private EntityCallbacks entityCallbacks = EntityCallbacks.create();
85+
private @Nullable EntityCallbacks entityCallbacks;
8786

8887
/**
89-
* Creates a new {@link JdbcAggregateTemplate} given {@link ApplicationContext}, {@link RelationalMappingContext} and
90-
* {@link DataAccessStrategy}.
88+
* Creates a new {@link JdbcAggregateTemplate} given {@link RelationalMappingContext} and {@link DataAccessStrategy}.
9189
*
92-
* @param publisher must not be {@literal null}.
90+
* @param converter must not be {@literal null}.
9391
* @param dataAccessStrategy must not be {@literal null}.
94-
* @since 3.3
95-
*/
96-
public JdbcAggregateTemplate(ApplicationContext publisher, JdbcConverter converter,
97-
DataAccessStrategy dataAccessStrategy) {
98-
99-
Assert.notNull(publisher, "ApplicationContext must not be null");
100-
Assert.notNull(converter, "RelationalConverter must not be null");
101-
Assert.notNull(dataAccessStrategy, "DataAccessStrategy must not be null");
102-
103-
this.eventDelegate.setPublisher(publisher);
104-
this.converter = converter;
105-
this.accessStrategy = dataAccessStrategy;
106-
this.context = converter.getMappingContext();
107-
108-
this.jdbcEntityDeleteWriter = new RelationalEntityDeleteWriter(context);
109-
110-
this.executor = new AggregateChangeExecutor(converter, accessStrategy);
111-
112-
setEntityCallbacks(EntityCallbacks.create(publisher));
113-
}
114-
115-
/**
116-
* Creates a new {@link JdbcAggregateTemplate} given {@link ApplicationEventPublisher},
117-
* {@link RelationalMappingContext} and {@link DataAccessStrategy}.
118-
*
119-
* @param publisher must not be {@literal null}.
120-
* @param dataAccessStrategy must not be {@literal null}.
121-
* @since 3.3
92+
* @since 1.1
12293
*/
123-
public JdbcAggregateTemplate(ApplicationEventPublisher publisher, JdbcConverter converter,
124-
DataAccessStrategy dataAccessStrategy) {
125-
126-
Assert.notNull(publisher, "ApplicationEventPublisher must not be null");
127-
Assert.notNull(converter, "RelationalConverter must not be null");
128-
Assert.notNull(dataAccessStrategy, "DataAccessStrategy must not be null");
129-
130-
this.eventDelegate.setPublisher(publisher);
131-
this.converter = converter;
132-
this.accessStrategy = dataAccessStrategy;
133-
this.context = converter.getMappingContext();
134-
135-
this.jdbcEntityDeleteWriter = new RelationalEntityDeleteWriter(context);
136-
this.executor = new AggregateChangeExecutor(converter, accessStrategy);
94+
public JdbcAggregateTemplate(JdbcConverter converter, DataAccessStrategy dataAccessStrategy) {
95+
this(converter, converter.getMappingContext(), dataAccessStrategy);
13796
}
13897

13998
/**
14099
* Creates a new {@link JdbcAggregateTemplate} given {@link ApplicationContext}, {@link RelationalMappingContext} and
141100
* {@link DataAccessStrategy}.
142101
*
143-
* @param publisher must not be {@literal null}.
102+
* @param applicationContext must not be {@literal null}.
144103
* @param context must not be {@literal null}.
104+
* @param converter must not be {@literal null}.
145105
* @param dataAccessStrategy must not be {@literal null}.
146106
* @since 1.1
147-
* @deprecated since 3.3, use {@link JdbcAggregateTemplate(ApplicationContext, JdbcConverter, DataAccessStrategy)}
148-
* instead.
149107
*/
150-
@Deprecated(since = "3.3")
151-
public JdbcAggregateTemplate(ApplicationContext publisher, RelationalMappingContext context, JdbcConverter converter,
152-
DataAccessStrategy dataAccessStrategy) {
153-
154-
Assert.notNull(publisher, "ApplicationContext must not be null");
155-
Assert.notNull(context, "RelationalMappingContext must not be null");
156-
Assert.notNull(converter, "RelationalConverter must not be null");
157-
Assert.notNull(dataAccessStrategy, "DataAccessStrategy must not be null");
158-
159-
this.eventDelegate.setPublisher(publisher);
160-
this.context = context;
161-
this.accessStrategy = dataAccessStrategy;
162-
this.converter = converter;
163-
164-
this.jdbcEntityDeleteWriter = new RelationalEntityDeleteWriter(context);
165-
166-
this.executor = new AggregateChangeExecutor(converter, accessStrategy);
167-
168-
setEntityCallbacks(EntityCallbacks.create(publisher));
108+
public JdbcAggregateTemplate(ApplicationContext applicationContext, RelationalMappingContext context,
109+
JdbcConverter converter, DataAccessStrategy dataAccessStrategy) {
110+
this(converter, context, dataAccessStrategy);
111+
setApplicationContext(applicationContext);
169112
}
170113

171114
/**
172115
* Creates a new {@link JdbcAggregateTemplate} given {@link ApplicationEventPublisher},
173-
* {@link RelationalMappingContext} and {@link DataAccessStrategy}.
116+
* {@link RelationalMappingContext}, {@link JdbcConverter} and {@link DataAccessStrategy}.
174117
*
175118
* @param publisher must not be {@literal null}.
176119
* @param context must not be {@literal null}.
120+
* @param converter must not be {@literal null}.
177121
* @param dataAccessStrategy must not be {@literal null}.
178-
* @deprecated since 3.3, use {@link JdbcAggregateTemplate(ApplicationEventPublisher, JdbcConverter,
179-
* DataAccessStrategy)} instead.
180122
*/
181-
@Deprecated(since = "3.3")
182123
public JdbcAggregateTemplate(ApplicationEventPublisher publisher, RelationalMappingContext context,
183124
JdbcConverter converter, DataAccessStrategy dataAccessStrategy) {
184125

126+
this(converter, context, dataAccessStrategy);
127+
185128
Assert.notNull(publisher, "ApplicationEventPublisher must not be null");
186-
Assert.notNull(context, "RelationalMappingContext must not be null");
129+
130+
if (publisher instanceof ApplicationContext applicationContext) {
131+
setApplicationContext(applicationContext);
132+
} else {
133+
this.eventDelegate.setPublisher(publisher);
134+
}
135+
}
136+
137+
private JdbcAggregateTemplate(JdbcConverter converter, RelationalMappingContext context,
138+
DataAccessStrategy dataAccessStrategy) {
139+
187140
Assert.notNull(converter, "RelationalConverter must not be null");
141+
Assert.notNull(context, "RelationalMappingContext must not be null");
188142
Assert.notNull(dataAccessStrategy, "DataAccessStrategy must not be null");
189143

190-
this.eventDelegate.setPublisher(publisher);
191-
this.context = context;
192144
this.accessStrategy = dataAccessStrategy;
193145
this.converter = converter;
146+
this.context = context;
194147

195148
this.jdbcEntityDeleteWriter = new RelationalEntityDeleteWriter(context);
196149
this.executor = new AggregateChangeExecutor(converter, accessStrategy);
197150
}
198151

152+
@Override
153+
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
154+
155+
Assert.notNull(applicationContext, "ApplicationContext must not be null");
156+
157+
if (entityCallbacks == null) {
158+
setEntityCallbacks(EntityCallbacks.create(applicationContext));
159+
}
160+
161+
this.eventDelegate.setPublisher(applicationContext);
162+
}
163+
199164
/**
200165
* Sets the callbacks to be invoked on life cycle events.
201166
*
@@ -519,6 +484,16 @@ public <T> void deleteAll(Iterable<? extends T> instances) {
519484
}
520485
}
521486

487+
@Override
488+
public DataAccessStrategy getDataAccessStrategy() {
489+
return accessStrategy;
490+
}
491+
492+
@Override
493+
public JdbcConverter getConverter() {
494+
return converter;
495+
}
496+
522497
private <T> void verifyIdProperty(T instance) {
523498
// accessing the id property just to raise an exception in the case it does not exist.
524499
context.getRequiredPersistentEntity(instance.getClass()).getRequiredIdProperty();
@@ -711,33 +686,35 @@ private <T> List<T> triggerAfterConvert(Iterable<T> all) {
711686
private <T> T triggerAfterConvert(T entity) {
712687

713688
eventDelegate.publishEvent(() -> new AfterConvertEvent<>(entity));
714-
return entityCallbacks.callback(AfterConvertCallback.class, entity);
689+
return entityCallbacks != null ? entityCallbacks.callback(AfterConvertCallback.class, entity) : entity;
715690
}
716691

717692
private <T> T triggerBeforeConvert(T aggregateRoot) {
718693

719694
eventDelegate.publishEvent(() -> new BeforeConvertEvent<>(aggregateRoot));
720-
return entityCallbacks.callback(BeforeConvertCallback.class, aggregateRoot);
695+
return entityCallbacks != null ? entityCallbacks.callback(BeforeConvertCallback.class, aggregateRoot)
696+
: aggregateRoot;
721697
}
722698

723699
private <T> T triggerBeforeSave(T aggregateRoot, AggregateChange<T> change) {
724700

725701
eventDelegate.publishEvent(() -> new BeforeSaveEvent<>(aggregateRoot, change));
726702

727-
return entityCallbacks.callback(BeforeSaveCallback.class, aggregateRoot, change);
703+
return entityCallbacks != null ? entityCallbacks.callback(BeforeSaveCallback.class, aggregateRoot, change)
704+
: aggregateRoot;
728705
}
729706

730707
private <T> T triggerAfterSave(T aggregateRoot, AggregateChange<T> change) {
731708

732709
eventDelegate.publishEvent(() -> new AfterSaveEvent<>(aggregateRoot, change));
733-
return entityCallbacks.callback(AfterSaveCallback.class, aggregateRoot);
710+
return entityCallbacks != null ? entityCallbacks.callback(AfterSaveCallback.class, aggregateRoot) : aggregateRoot;
734711
}
735712

736713
private <T> void triggerAfterDelete(@Nullable T aggregateRoot, Object id, AggregateChange<T> change) {
737714

738715
eventDelegate.publishEvent(() -> new AfterDeleteEvent<>(Identifier.of(id), aggregateRoot, change));
739716

740-
if (aggregateRoot != null) {
717+
if (aggregateRoot != null && entityCallbacks != null) {
741718
entityCallbacks.callback(AfterDeleteCallback.class, aggregateRoot);
742719
}
743720
}
@@ -747,11 +724,11 @@ private <T> T triggerBeforeDelete(@Nullable T aggregateRoot, Object id, MutableA
747724

748725
eventDelegate.publishEvent(() -> new BeforeDeleteEvent<>(Identifier.of(id), aggregateRoot, change));
749726

750-
if (aggregateRoot != null) {
727+
if (aggregateRoot != null && entityCallbacks != null) {
751728
return entityCallbacks.callback(BeforeDeleteCallback.class, aggregateRoot, change);
752729
}
753730

754-
return null;
731+
return aggregateRoot;
755732
}
756733

757734
private record EntityAndPreviousVersion<T>(T entity, @Nullable Number version) {
@@ -764,13 +741,4 @@ private interface AggregateChangeCreator<T> {
764741
RootAggregateChange<T> createAggregateChange(T instance);
765742
}
766743

767-
@Override
768-
public DataAccessStrategy getDataAccessStrategy() {
769-
return accessStrategy;
770-
}
771-
772-
@Override
773-
public JdbcConverter getConverter() {
774-
return converter;
775-
}
776744
}

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +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.dialect.Dialect;
3132
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
3233
import org.springframework.data.relational.core.query.Query;
3334
import org.springframework.data.relational.core.sql.LockMode;
35+
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
36+
import org.springframework.util.Assert;
3437

3538
/**
3639
* Delegates each method to the {@link DataAccessStrategy}s passed to the constructor in turn until the first that does
@@ -54,6 +57,22 @@ public CascadingDataAccessStrategy(List<DataAccessStrategy> strategies) {
5457
this.strategies = new ArrayList<>(strategies);
5558
}
5659

60+
@Override
61+
public Dialect getDialect() {
62+
63+
Assert.notEmpty(strategies, "DataAccessStrategy must have at least one strategy");
64+
65+
return strategies.get(0).getDialect();
66+
}
67+
68+
@Override
69+
public NamedParameterJdbcOperations getJdbcOperations() {
70+
71+
Assert.notEmpty(strategies, "DataAccessStrategy must have at least one strategy");
72+
73+
return strategies.get(0).getJdbcOperations();
74+
}
75+
5776
@Override
5877
public <T> Object insert(T instance, Class<T> domainType, Identifier identifier, IdValueSource idValueSource) {
5978
return collect(das -> das.insert(instance, domainType, identifier, idValueSource));

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@
2626
import org.springframework.data.jdbc.core.JdbcAggregateOperations;
2727
import org.springframework.data.mapping.PersistentPropertyPath;
2828
import org.springframework.data.relational.core.conversion.IdValueSource;
29+
import org.springframework.data.relational.core.dialect.Dialect;
2930
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
3031
import org.springframework.data.relational.core.query.Query;
3132
import org.springframework.data.relational.core.sql.LockMode;
33+
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
3234
import org.springframework.lang.Nullable;
3335

3436
/**
@@ -46,6 +48,18 @@
4648
*/
4749
public interface DataAccessStrategy extends ReadingDataAccessStrategy, RelationResolver {
4850

51+
/**
52+
* @return the dialect used by this strategy.
53+
* @since 4.0
54+
*/
55+
Dialect getDialect();
56+
57+
/**
58+
* @return the {@link NamedParameterJdbcOperations} used by this strategy.
59+
* @since 4.0
60+
*/
61+
NamedParameterJdbcOperations getJdbcOperations();
62+
4963
/**
5064
* Inserts the data of a single entity. Referenced entities don't get handled.
5165
*

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.springframework.data.domain.Sort;
3131
import org.springframework.data.mapping.PersistentPropertyPath;
3232
import org.springframework.data.relational.core.conversion.IdValueSource;
33+
import org.springframework.data.relational.core.dialect.Dialect;
3334
import org.springframework.data.relational.core.mapping.AggregatePath;
3435
import org.springframework.data.relational.core.mapping.AggregatePath.TableInfo;
3536
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
@@ -105,6 +106,16 @@ public DefaultDataAccessStrategy(SqlGeneratorSource sqlGeneratorSource, Relation
105106
this.queryMappingConfiguration = queryMappingConfiguration;
106107
}
107108

109+
@Override
110+
public Dialect getDialect() {
111+
return sqlGeneratorSource.getDialect();
112+
}
113+
114+
@Override
115+
public NamedParameterJdbcOperations getJdbcOperations() {
116+
return operations;
117+
}
118+
108119
@Override
109120
public <T> Object insert(T instance, Class<T> domainType, Identifier identifier, IdValueSource idValueSource) {
110121

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@
2323
import org.springframework.data.domain.Sort;
2424
import org.springframework.data.mapping.PersistentPropertyPath;
2525
import org.springframework.data.relational.core.conversion.IdValueSource;
26+
import org.springframework.data.relational.core.dialect.Dialect;
2627
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
2728
import org.springframework.data.relational.core.query.Query;
2829
import org.springframework.data.relational.core.sql.LockMode;
30+
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
2931
import org.springframework.util.Assert;
3032

3133
/**
@@ -53,6 +55,16 @@ public DelegatingDataAccessStrategy(DataAccessStrategy delegate) {
5355
this.delegate = delegate;
5456
}
5557

58+
@Override
59+
public Dialect getDialect() {
60+
return delegate.getDialect();
61+
}
62+
63+
@Override
64+
public NamedParameterJdbcOperations getJdbcOperations() {
65+
return delegate.getJdbcOperations();
66+
}
67+
5668
@Override
5769
public <T> Object insert(T instance, Class<T> domainType, Identifier identifier, IdValueSource idValueSource) {
5870
return delegate.insert(instance, domainType, identifier, idValueSource);

0 commit comments

Comments
 (0)