Browse Source

Add `jdbcAggregateOperationsRef` to `@EnableJdbcRepositories`.

Closes #687
Original pull request: #1704
pull/2114/head
Tomohiko Ozawa 2 years ago committed by Mark Paluch
parent
commit
d17bff807d
No known key found for this signature in database
GPG Key ID: 55BC6374BAA9D973
  1. 17
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/JdbcAggregateOperations.java
  2. 68
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/JdbcAggregateTemplate.java
  3. 105
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/dialect/DialectResolver.java
  4. 7
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/AbstractJdbcConfiguration.java
  5. 8
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/EnableJdbcRepositories.java
  6. 13
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/JdbcRepositoryConfigExtension.java
  7. 19
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactory.java
  8. 14
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBean.java
  9. 5
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/AbstractJdbcAggregateTemplateIntegrationTests.java
  10. 10
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/ImmutableAggregateTemplateHsqlIntegrationTests.java
  11. 12
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateSchemaIntegrationTests.java
  12. 2
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateUnitTests.java
  13. 33
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/EnableJdbcRepositoriesIntegrationTests.java
  14. 14
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBeanUnitTests.java
  15. 11
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/TestConfiguration.java

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

@ -24,6 +24,8 @@ import org.springframework.data.domain.Example; @@ -24,6 +24,8 @@ import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jdbc.core.convert.DataAccessStrategy;
import org.springframework.data.jdbc.core.convert.JdbcConverter;
import org.springframework.data.relational.core.query.Query;
import org.springframework.lang.Nullable;
@ -37,6 +39,7 @@ import org.springframework.lang.Nullable; @@ -37,6 +39,7 @@ import org.springframework.lang.Nullable;
* @author Diego Krupitza
* @author Myeonghyeon Lee
* @author Sergey Korotaev
* @author Tomohiko Ozawa
*/
public interface JdbcAggregateOperations {
@ -324,4 +327,18 @@ public interface JdbcAggregateOperations { @@ -324,4 +327,18 @@ public interface JdbcAggregateOperations {
* @param <T> the type of the aggregate roots.
*/
<T> void deleteAll(Iterable<? extends T> aggregateRoots);
/**
* Returns the {@link JdbcConverter}.
*
* @return the {@link JdbcConverter}.
*/
JdbcConverter getConverter();
/**
* Return the {@link DataAccessStrategy}
*
* @return the {@link DataAccessStrategy}
*/
DataAccessStrategy getDataAccessStrategy();
}

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

@ -70,6 +70,7 @@ import org.springframework.util.ClassUtils; @@ -70,6 +70,7 @@ import org.springframework.util.ClassUtils;
* @author Diego Krupitza
* @author Sergey Korotaev
* @author Mikhail Polivakha
* @author Tomohiko Ozawa
*/
public class JdbcAggregateTemplate implements JdbcAggregateOperations {
@ -84,6 +85,57 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations { @@ -84,6 +85,57 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
private EntityCallbacks entityCallbacks = EntityCallbacks.create();
/**
* Creates a new {@link JdbcAggregateTemplate} given {@link ApplicationContext}, {@link RelationalMappingContext} and
* {@link DataAccessStrategy}.
*
* @param publisher must not be {@literal null}.
* @param dataAccessStrategy must not be {@literal null}.
* @since 3.3
*/
public JdbcAggregateTemplate(ApplicationContext publisher, JdbcConverter converter,
DataAccessStrategy dataAccessStrategy) {
Assert.notNull(publisher, "ApplicationContext must not be null");
Assert.notNull(converter, "RelationalConverter must not be null");
Assert.notNull(dataAccessStrategy, "DataAccessStrategy must not be null");
this.eventDelegate.setPublisher(publisher);
this.converter = converter;
this.accessStrategy = dataAccessStrategy;
this.context = converter.getMappingContext();
this.jdbcEntityDeleteWriter = new RelationalEntityDeleteWriter(context);
this.executor = new AggregateChangeExecutor(converter, accessStrategy);
setEntityCallbacks(EntityCallbacks.create(publisher));
}
/**
* Creates a new {@link JdbcAggregateTemplate} given {@link ApplicationEventPublisher},
* {@link RelationalMappingContext} and {@link DataAccessStrategy}.
*
* @param publisher must not be {@literal null}.
* @param dataAccessStrategy must not be {@literal null}.
* @since 3.3
*/
public JdbcAggregateTemplate(ApplicationEventPublisher publisher, JdbcConverter converter,
DataAccessStrategy dataAccessStrategy) {
Assert.notNull(publisher, "ApplicationEventPublisher must not be null");
Assert.notNull(converter, "RelationalConverter must not be null");
Assert.notNull(dataAccessStrategy, "DataAccessStrategy must not be null");
this.eventDelegate.setPublisher(publisher);
this.converter = converter;
this.accessStrategy = dataAccessStrategy;
this.context = converter.getMappingContext();
this.jdbcEntityDeleteWriter = new RelationalEntityDeleteWriter(context);
this.executor = new AggregateChangeExecutor(converter, accessStrategy);
}
/**
* Creates a new {@link JdbcAggregateTemplate} given {@link ApplicationContext}, {@link RelationalMappingContext} and
* {@link DataAccessStrategy}.
@ -92,7 +144,10 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations { @@ -92,7 +144,10 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
* @param context must not be {@literal null}.
* @param dataAccessStrategy must not be {@literal null}.
* @since 1.1
* @deprecated since 3.3, use {@link JdbcAggregateTemplate(ApplicationContext, JdbcConverter, DataAccessStrategy)}
* instead.
*/
@Deprecated(since = "3.3")
public JdbcAggregateTemplate(ApplicationContext publisher, RelationalMappingContext context, JdbcConverter converter,
DataAccessStrategy dataAccessStrategy) {
@ -120,7 +175,10 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations { @@ -120,7 +175,10 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
* @param publisher must not be {@literal null}.
* @param context must not be {@literal null}.
* @param dataAccessStrategy must not be {@literal null}.
* @deprecated since 3.3, use {@link JdbcAggregateTemplate(ApplicationEventPublisher, JdbcConverter,
* DataAccessStrategy)} instead.
*/
@Deprecated(since = "3.3")
public JdbcAggregateTemplate(ApplicationEventPublisher publisher, RelationalMappingContext context,
JdbcConverter converter, DataAccessStrategy dataAccessStrategy) {
@ -705,4 +763,14 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations { @@ -705,4 +763,14 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
private interface AggregateChangeCreator<T> {
RootAggregateChange<T> createAggregateChange(T instance);
}
@Override
public DataAccessStrategy getDataAccessStrategy() {
return accessStrategy;
}
@Override
public JdbcConverter getConverter() {
return converter;
}
}

105
spring-data-jdbc/src/main/java/org/springframework/data/jdbc/dialect/DialectResolver.java

@ -0,0 +1,105 @@ @@ -0,0 +1,105 @@
/*
* Copyright 2020-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.jdbc.dialect;
import java.sql.Connection;
import java.util.Optional;
import javax.sql.DataSource;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.data.jdbc.core.dialect.JdbcDialect;
import org.springframework.data.relational.core.dialect.Dialect;
import org.springframework.jdbc.core.JdbcOperations;
/**
* Resolves a {@link Dialect}. Resolution typically uses {@link JdbcOperations} to obtain and inspect a
* {@link Connection}. Dialect resolution uses Spring's {@link SpringFactoriesLoader spring.factories} to determine
* available {@link JdbcDialectProvider extensions}.
*
* @author Jens Schauder
* @author Mikhail Polivakha
* @since 2.0
* @see Dialect
* @see SpringFactoriesLoader
* @deprecated since 3.5, replacement {@link org.springframework.data.jdbc.core.dialect.DialectResolver} was moved to
* the {@link org.springframework.data.jdbc.core.dialect} package.
*/
@Deprecated(since = "3.5", forRemoval = true)
public class DialectResolver {
// utility constructor.
private DialectResolver() {}
/**
* Retrieve a {@link Dialect} by inspecting a {@link Connection}.
*
* @param operations must not be {@literal null}.
* @return the resolved {@link Dialect} {@link NoDialectException} if the database type cannot be determined from
* {@link DataSource}.
* @throws NoDialectException if no {@link Dialect} can be found.
*/
public static JdbcDialect getDialect(JdbcOperations operations) {
return org.springframework.data.jdbc.core.dialect.DialectResolver.getDialect(operations);
}
/**
* SPI to extend Spring's default JDBC Dialect discovery mechanism. Implementations of this interface are discovered
* through Spring's {@link SpringFactoriesLoader} mechanism.
*
* @author Jens Schauder
* @see org.springframework.core.io.support.SpringFactoriesLoader
* @deprecated since 3.5, replacement {@link org.springframework.data.jdbc.core.dialect.DialectResolver} was moved to
* the {@link org.springframework.data.jdbc.core.dialect} package.
*/
@Deprecated(since = "3.5", forRemoval = true)
public interface JdbcDialectProvider
extends org.springframework.data.jdbc.core.dialect.DialectResolver.JdbcDialectProvider {
/**
* Returns a {@link Dialect} for a {@link DataSource}.
*
* @param operations the {@link JdbcOperations} to be used with the {@link Dialect}.
* @return {@link Optional} containing the {@link Dialect} if the {@link JdbcDialectProvider} can provide a dialect
* object, otherwise {@link Optional#empty()}.
*/
Optional<Dialect> getDialect(JdbcOperations operations);
}
@Deprecated(since = "3.5", forRemoval = true)
static public class DefaultDialectProvider extends
org.springframework.data.jdbc.core.dialect.DialectResolver.DefaultDialectProvider implements JdbcDialectProvider {
}
/**
* Exception thrown when {@link DialectResolver} cannot resolve a {@link Dialect}.
*/
@Deprecated(since = "3.5", forRemoval = true)
public static class NoDialectException
extends org.springframework.data.jdbc.core.dialect.DialectResolver.NoDialectException {
/**
* Constructor for NoDialectFoundException.
*
* @param msg the detail message
*/
NoDialectException(String msg) {
super(msg);
}
}
}

7
spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/AbstractJdbcConfiguration.java

@ -41,6 +41,7 @@ import org.springframework.data.jdbc.core.dialect.JdbcArrayColumns; @@ -41,6 +41,7 @@ import org.springframework.data.jdbc.core.dialect.JdbcArrayColumns;
import org.springframework.data.jdbc.core.dialect.JdbcDialect;
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
import org.springframework.data.jdbc.core.mapping.JdbcSimpleTypes;
import org.springframework.data.jdbc.dialect.DialectResolver;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.relational.RelationalManagedTypes;
import org.springframework.data.relational.core.conversion.RelationalConverter;
@ -65,6 +66,7 @@ import org.springframework.util.StringUtils; @@ -65,6 +66,7 @@ import org.springframework.util.StringUtils;
* @author Myeonghyeon Lee
* @author Chirag Tailor
* @author Mikhail Polivakha
* @author Tomohiko Ozawa
* @since 1.1
*/
@Configuration(proxyBeanMethods = false)
@ -221,7 +223,7 @@ public class AbstractJdbcConfiguration implements ApplicationContextAware { @@ -221,7 +223,7 @@ public class AbstractJdbcConfiguration implements ApplicationContextAware {
public JdbcAggregateTemplate jdbcAggregateTemplate(ApplicationContext applicationContext,
JdbcMappingContext mappingContext, JdbcConverter converter, DataAccessStrategy dataAccessStrategy) {
return new JdbcAggregateTemplate(applicationContext, mappingContext, converter, dataAccessStrategy);
return new JdbcAggregateTemplate(applicationContext, converter, dataAccessStrategy);
}
/**
@ -249,8 +251,7 @@ public class AbstractJdbcConfiguration implements ApplicationContextAware { @@ -249,8 +251,7 @@ public class AbstractJdbcConfiguration implements ApplicationContextAware {
* @param operations the {@link NamedParameterJdbcOperations} allowing access to a {@link java.sql.Connection}.
* @return the {@link Dialect} to be used.
* @since 2.0
* @throws org.springframework.data.jdbc.repository.config.DialectResolver.NoDialectException if the {@link Dialect}
* cannot be determined.
* @throws DialectResolver.NoDialectException if the {@link Dialect} cannot be determined.
*/
@Bean
public Dialect jdbcDialect(NamedParameterJdbcOperations operations) {

8
spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/EnableJdbcRepositories.java

@ -131,7 +131,9 @@ public @interface EnableJdbcRepositories { @@ -131,7 +131,9 @@ public @interface EnableJdbcRepositories {
/**
* Configures the name of the {@link org.springframework.data.jdbc.core.convert.DataAccessStrategy} bean definition to
* be used to create repositories discovered through this annotation. Defaults to {@code defaultDataAccessStrategy}.
* @deprecated since 3.3 use {@link #jdbcAggregateOperationsRef()} instead
*/
@Deprecated(since = "3.3")
String dataAccessStrategyRef() default "";
/**
@ -142,6 +144,12 @@ public @interface EnableJdbcRepositories { @@ -142,6 +144,12 @@ public @interface EnableJdbcRepositories {
*/
String transactionManagerRef() default "transactionManager";
/**
* Configure the name of the {@link org.springframework.data.jdbc.core.JdbcAggregateOperations} bean definition to be
* used to create repositories discovered through this annotation.
*/
String jdbcAggregateOperationsRef() default "";
/**
* Returns the key of the {@link QueryLookupStrategy} to be used for lookup queries for query methods. Defaults to
* {@link QueryLookupStrategy.Key#CREATE_IF_NOT_FOUND}.

13
spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/JdbcRepositoryConfigExtension.java

@ -40,6 +40,7 @@ import org.springframework.util.StringUtils; @@ -40,6 +40,7 @@ import org.springframework.util.StringUtils;
* @author Fei Dong
* @author Mark Paluch
* @author Antoine Sauray
* @author Tomohiko Ozawa
*/
public class JdbcRepositoryConfigExtension extends RepositoryConfigurationExtensionSupport {
@ -79,9 +80,15 @@ public class JdbcRepositoryConfigExtension extends RepositoryConfigurationExtens @@ -79,9 +80,15 @@ public class JdbcRepositoryConfigExtension extends RepositoryConfigurationExtens
Optional<String> transactionManagerRef = source.getAttribute("transactionManagerRef");
builder.addPropertyValue("transactionManager", transactionManagerRef.orElse(DEFAULT_TRANSACTION_MANAGER_BEAN_NAME));
builder.addPropertyValue("mappingContext", new RuntimeBeanReference(JdbcMappingContext.class));
builder.addPropertyValue("dialect", new RuntimeBeanReference(Dialect.class));
builder.addPropertyValue("converter", new RuntimeBeanReference(JdbcConverter.class));
Optional<String> jdbcAggregateOperationsRef = source.getAttribute("jdbcAggregateOperationsRef");
if (jdbcAggregateOperationsRef.isPresent()) {
builder.addPropertyReference("jdbcAggregateOperations", jdbcAggregateOperationsRef.get());
} else {
builder.addPropertyValue("mappingContext", new RuntimeBeanReference(JdbcMappingContext.class));
builder.addPropertyValue("dialect", new RuntimeBeanReference(Dialect.class));
builder.addPropertyValue("converter", new RuntimeBeanReference(JdbcConverter.class));
}
}
/**

19
spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactory.java

@ -19,9 +19,11 @@ import java.util.Optional; @@ -19,9 +19,11 @@ import java.util.Optional;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.jdbc.core.JdbcAggregateOperations;
import org.springframework.data.jdbc.core.JdbcAggregateTemplate;
import org.springframework.data.jdbc.core.convert.DataAccessStrategy;
import org.springframework.data.jdbc.core.convert.JdbcConverter;
import org.springframework.data.jdbc.dialect.DialectResolver;
import org.springframework.data.jdbc.core.convert.QueryMappingConfiguration;
import org.springframework.data.mapping.callback.EntityCallbacks;
import org.springframework.data.relational.core.dialect.Dialect;
@ -50,6 +52,7 @@ import org.springframework.util.Assert; @@ -50,6 +52,7 @@ import org.springframework.util.Assert;
* @author Diego Krupitza
* @author Christopher Klein
* @author Marcin Grzejszczak
* @author Tomohiko Ozawa
*/
public class JdbcRepositoryFactory extends RepositoryFactorySupport {
@ -64,6 +67,20 @@ public class JdbcRepositoryFactory extends RepositoryFactorySupport { @@ -64,6 +67,20 @@ public class JdbcRepositoryFactory extends RepositoryFactorySupport {
private QueryMappingConfiguration queryMappingConfiguration = QueryMappingConfiguration.EMPTY;
private EntityCallbacks entityCallbacks;
public JdbcRepositoryFactory(ApplicationEventPublisher publisher, JdbcAggregateOperations jdbcAggregateOperations,
NamedParameterJdbcOperations operations) {
Assert.notNull(publisher, "ApplicationEventPublisher must not be null");
Assert.notNull(jdbcAggregateOperations, "JdbcAggregateOperations must not be null");
Assert.notNull(operations, "NamedParameterJdbcOperations must not be null");
this.converter = jdbcAggregateOperations.getConverter();
this.accessStrategy = jdbcAggregateOperations.getDataAccessStrategy();
this.context = jdbcAggregateOperations.getConverter().getMappingContext();
this.dialect = DialectResolver.getDialect(operations.getJdbcOperations());
this.operations = operations;
this.publisher = publisher;
}
/**
* Creates a new {@link JdbcRepositoryFactory} for the given {@link DataAccessStrategy},
* {@link RelationalMappingContext} and {@link ApplicationEventPublisher}.
@ -115,7 +132,7 @@ public class JdbcRepositoryFactory extends RepositoryFactorySupport { @@ -115,7 +132,7 @@ public class JdbcRepositoryFactory extends RepositoryFactorySupport {
@Override
protected Object getTargetRepository(RepositoryInformation repositoryInformation) {
JdbcAggregateTemplate template = new JdbcAggregateTemplate(publisher, context, converter, accessStrategy);
JdbcAggregateTemplate template = new JdbcAggregateTemplate(publisher, converter, accessStrategy);
if (entityCallbacks != null) {
template.setEntityCallbacks(entityCallbacks);

14
spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBean.java

@ -22,6 +22,8 @@ import org.jspecify.annotations.Nullable; @@ -22,6 +22,8 @@ import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.data.jdbc.core.JdbcAggregateOperations;
import org.springframework.data.jdbc.core.JdbcAggregateTemplate;
import org.springframework.data.jdbc.core.convert.DataAccessStrategy;
import org.springframework.data.jdbc.core.convert.DataAccessStrategyFactory;
import org.springframework.data.jdbc.core.convert.InsertStrategyFactory;
@ -64,6 +66,7 @@ import org.springframework.util.Assert; @@ -64,6 +66,7 @@ import org.springframework.util.Assert;
* @author Chirag Tailor
* @author Mikhail Polivakha
* @author Sergey Korotaev
* @author Tomohiko Ozawa
*/
public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable>
extends TransactionalRepositoryFactoryBeanSupport<T, S, ID> implements ApplicationEventPublisherAware {
@ -75,6 +78,7 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend @@ -75,6 +78,7 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend
private @Nullable DataAccessStrategy dataAccessStrategy;
private @Nullable QueryMappingConfiguration queryMappingConfiguration;
private @Nullable NamedParameterJdbcOperations operations;
private JdbcAggregateOperations aggregateOperations;
private EntityCallbacks entityCallbacks = EntityCallbacks.create();
private @Nullable Dialect dialect;
@ -109,8 +113,7 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend @@ -109,8 +113,7 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend
Assert.state(this.operations != null, "NamedParameterJdbcOperations is required and must not be null");
Assert.state(this.queryMappingConfiguration != null, "RelationalConverter is required and must not be null");
JdbcRepositoryFactory jdbcRepositoryFactory = new JdbcRepositoryFactory(dataAccessStrategy, mappingContext,
converter, dialect, publisher, operations);
JdbcRepositoryFactory jdbcRepositoryFactory = new JdbcRepositoryFactory(publisher, aggregateOperations, operations);
jdbcRepositoryFactory.setQueryMappingConfiguration(queryMappingConfiguration);
jdbcRepositoryFactory.setEntityCallbacks(entityCallbacks);
jdbcRepositoryFactory.setBeanFactory(beanFactory);
@ -161,6 +164,10 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend @@ -161,6 +164,10 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend
this.operations = operations;
}
public void setJdbcAggregateOperations(JdbcAggregateOperations jdbcAggregateOperations) {
this.aggregateOperations = jdbcAggregateOperations;
}
public void setConverter(JdbcConverter converter) {
Assert.notNull(converter, "JdbcConverter must not be null");
@ -192,6 +199,9 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend @@ -192,6 +199,9 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend
this.operations = this.beanFactory.getBean(NamedParameterJdbcOperations.class);
}
aggregateOperations = new JdbcAggregateTemplate(publisher, converter, dataAccessStrategy);
}
if (this.queryMappingConfiguration == null) {
if (this.beanFactory == null) {

5
spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/AbstractJdbcAggregateTemplateIntegrationTests.java

@ -46,8 +46,6 @@ import org.springframework.data.annotation.Version; @@ -46,8 +46,6 @@ import org.springframework.data.annotation.Version;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Persistable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jdbc.core.convert.DataAccessStrategy;
import org.springframework.data.jdbc.core.convert.JdbcConverter;
import org.springframework.data.jdbc.testing.EnabledOnFeature;
import org.springframework.data.jdbc.testing.IntegrationTest;
import org.springframework.data.jdbc.testing.TestClass;
@ -1384,7 +1382,8 @@ abstract class AbstractJdbcAggregateTemplateIntegrationTests { @@ -1384,7 +1382,8 @@ abstract class AbstractJdbcAggregateTemplateIntegrationTests {
void mapWithEnumKey() {
EnumMapOwner enumMapOwner = template
.save(new EnumMapOwner(null, "OwnerName", Map.of(Color.BLUE, new MapElement("Element"))));
.save(
new EnumMapOwner(null, "OwnerName", Map.of(Color.BLUE, new MapElement("Element"))));
Iterable<EnumMapOwner> enumMapOwners = template.findAll(EnumMapOwner.class);

10
spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/ImmutableAggregateTemplateHsqlIntegrationTests.java

@ -23,18 +23,14 @@ import java.util.Objects; @@ -23,18 +23,14 @@ import java.util.Objects;
import org.assertj.core.api.SoftAssertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.annotation.Id;
import org.springframework.data.jdbc.core.convert.DataAccessStrategy;
import org.springframework.data.jdbc.core.convert.JdbcConverter;
import org.springframework.data.jdbc.testing.DatabaseType;
import org.springframework.data.jdbc.testing.EnabledOnDatabase;
import org.springframework.data.jdbc.testing.IntegrationTest;
import org.springframework.data.jdbc.testing.TestConfiguration;
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
/**
* Integration tests for {@link JdbcAggregateTemplate} and it's handling of immutable entities.
@ -602,11 +598,5 @@ public class ImmutableAggregateTemplateHsqlIntegrationTests { @@ -602,11 +598,5 @@ public class ImmutableAggregateTemplateHsqlIntegrationTests {
Class<?> testClass() {
return ImmutableAggregateTemplateHsqlIntegrationTests.class;
}
@Bean
JdbcAggregateOperations operations(ApplicationEventPublisher publisher, RelationalMappingContext context,
DataAccessStrategy dataAccessStrategy, JdbcConverter converter) {
return new JdbcAggregateTemplate(publisher, context, converter, dataAccessStrategy);
}
}
}

12
spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateSchemaIntegrationTests.java

@ -16,22 +16,16 @@ @@ -16,22 +16,16 @@
package org.springframework.data.jdbc.core;
import static org.assertj.core.api.Assertions.*;
import static org.springframework.data.jdbc.testing.TestDatabaseFeatures.Feature.*;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.annotation.Id;
import org.springframework.data.jdbc.core.convert.DataAccessStrategy;
import org.springframework.data.jdbc.core.convert.JdbcConverter;
import org.springframework.data.jdbc.testing.EnabledOnFeature;
import org.springframework.data.jdbc.testing.IntegrationTest;
import org.springframework.data.jdbc.testing.TestConfiguration;
import org.springframework.data.relational.core.mapping.NamingStrategy;
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
/**
@ -86,12 +80,6 @@ public class JdbcAggregateTemplateSchemaIntegrationTests { @@ -86,12 +80,6 @@ public class JdbcAggregateTemplateSchemaIntegrationTests {
return JdbcAggregateTemplateSchemaIntegrationTests.class;
}
@Bean
JdbcAggregateOperations operations(ApplicationEventPublisher publisher, RelationalMappingContext context,
DataAccessStrategy dataAccessStrategy, JdbcConverter converter) {
return new JdbcAggregateTemplate(publisher, context, converter, dataAccessStrategy);
}
@Bean
NamingStrategy namingStrategy() {
return new NamingStrategy() {

2
spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateUnitTests.java

@ -77,7 +77,7 @@ public class JdbcAggregateTemplateUnitTests { @@ -77,7 +77,7 @@ public class JdbcAggregateTemplateUnitTests {
RelationalMappingContext mappingContext = new RelationalMappingContext();
JdbcConverter converter = new MappingJdbcConverter(mappingContext, relationResolver);
template = new JdbcAggregateTemplate(eventPublisher, mappingContext, converter, dataAccessStrategy);
template = new JdbcAggregateTemplate(eventPublisher, converter, dataAccessStrategy);
template.setEntityCallbacks(callbacks);
}

33
spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/EnableJdbcRepositoriesIntegrationTests.java

@ -27,12 +27,14 @@ import org.junit.jupiter.api.BeforeAll; @@ -27,12 +27,14 @@ import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.Import;
import org.springframework.data.annotation.Id;
import org.springframework.data.jdbc.core.JdbcAggregateOperations;
import org.springframework.data.jdbc.core.JdbcAggregateTemplate;
import org.springframework.data.jdbc.core.convert.DataAccessStrategy;
import org.springframework.data.jdbc.core.convert.DataAccessStrategyFactory;
@ -41,6 +43,8 @@ import org.springframework.data.jdbc.core.convert.JdbcConverter; @@ -41,6 +43,8 @@ import org.springframework.data.jdbc.core.convert.JdbcConverter;
import org.springframework.data.jdbc.core.convert.QueryMappingConfiguration;
import org.springframework.data.jdbc.core.convert.SqlGeneratorSource;
import org.springframework.data.jdbc.core.convert.SqlParametersFactory;
import org.springframework.data.jdbc.dialect.DialectResolver;
import org.springframework.data.jdbc.repository.QueryMappingConfiguration;
import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactoryBean;
import org.springframework.data.jdbc.testing.IntegrationTest;
import org.springframework.data.jdbc.testing.TestConfiguration;
@ -72,6 +76,8 @@ public class EnableJdbcRepositoriesIntegrationTests { @@ -72,6 +76,8 @@ public class EnableJdbcRepositoriesIntegrationTests {
static final Field OPERATIONS = ReflectionUtils.findField(JdbcRepositoryFactoryBean.class, "operations");
static final Field DATA_ACCESS_STRATEGY = ReflectionUtils.findField(JdbcRepositoryFactoryBean.class,
"dataAccessStrategy");
static final Field AGGREGATE_OPERATIONS = ReflectionUtils.findField(JdbcRepositoryFactoryBean.class,
"aggregateOperations");
public static final RowMapper DUMMY_ENTITY_ROW_MAPPER = mock(RowMapper.class);
public static final RowMapper STRING_ROW_MAPPER = mock(RowMapper.class);
@ -82,9 +88,15 @@ public class EnableJdbcRepositoriesIntegrationTests { @@ -82,9 +88,15 @@ public class EnableJdbcRepositoriesIntegrationTests {
@Autowired
@Qualifier("defaultDataAccessStrategy") DataAccessStrategy defaultDataAccessStrategy;
@Autowired
@Qualifier("jdbcAggregateOperations")
JdbcAggregateOperations defaultJdbcAggregateOperations;
@Autowired
@Qualifier("qualifierJdbcOperations") NamedParameterJdbcOperations qualifierJdbcOperations;
@Autowired
@Qualifier("qualifierDataAccessStrategy") DataAccessStrategy qualifierDataAccessStrategy;
@Autowired
@Qualifier("qualifierJdbcAggregateOperations")
JdbcAggregateOperations qualifierJdbcAggregateOperations;
@BeforeAll
public static void setup() {
@ -92,6 +104,7 @@ public class EnableJdbcRepositoriesIntegrationTests { @@ -92,6 +104,7 @@ public class EnableJdbcRepositoriesIntegrationTests {
MAPPER_MAP.setAccessible(true);
OPERATIONS.setAccessible(true);
DATA_ACCESS_STRATEGY.setAccessible(true);
AGGREGATE_OPERATIONS.setAccessible(true);
}
@Test // DATAJDBC-100
@ -126,6 +139,19 @@ public class EnableJdbcRepositoriesIntegrationTests { @@ -126,6 +139,19 @@ public class EnableJdbcRepositoriesIntegrationTests {
assertThat(dataAccessStrategy).isNotSameAs(defaultDataAccessStrategy).isSameAs(qualifierDataAccessStrategy);
}
@Test // GH-1704
public void jdbcAggregateOperationsRef() {
JdbcAggregateOperations aggregateOperations = (JdbcAggregateOperations) ReflectionUtils.getField(
AGGREGATE_OPERATIONS, factoryBean);
assertThat(aggregateOperations).isNotSameAs(defaultJdbcAggregateOperations)
.isSameAs(qualifierJdbcAggregateOperations);
DataAccessStrategy dataAccessStrategy = (DataAccessStrategy) ReflectionUtils.getField(DATA_ACCESS_STRATEGY,
factoryBean);
assertThat(dataAccessStrategy).isNotSameAs(defaultDataAccessStrategy).isSameAs(qualifierDataAccessStrategy);
}
interface DummyRepository extends CrudRepository<DummyEntity, Long> {
}
@ -146,6 +172,7 @@ public class EnableJdbcRepositoriesIntegrationTests { @@ -146,6 +172,7 @@ public class EnableJdbcRepositoriesIntegrationTests {
@EnableJdbcRepositories(considerNestedRepositories = true,
includeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = DummyRepository.class),
jdbcOperationsRef = "qualifierJdbcOperations", dataAccessStrategyRef = "qualifierDataAccessStrategy",
jdbcAggregateOperationsRef = "qualifierJdbcAggregateOperations",
repositoryBaseClass = DummyRepositoryBaseClass.class)
@Import(TestConfiguration.class)
static class Config {
@ -176,6 +203,12 @@ public class EnableJdbcRepositoriesIntegrationTests { @@ -176,6 +203,12 @@ public class EnableJdbcRepositoriesIntegrationTests {
Dialect jdbcDialect(@Qualifier("qualifierJdbcOperations") NamedParameterJdbcOperations operations) {
return DialectResolver.getDialect(operations.getJdbcOperations());
}
@Bean("qualifierJdbcAggregateOperations")
JdbcAggregateOperations jdbcAggregateOperations(ApplicationContext publisher, JdbcConverter converter,
@Qualifier("qualifierDataAccessStrategy") DataAccessStrategy dataAccessStrategy) {
return new JdbcAggregateTemplate(publisher, converter, dataAccessStrategy);
}
}
private static class DummyRepositoryBaseClass<T, ID> implements CrudRepository<T, ID> {

14
spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBeanUnitTests.java

@ -40,8 +40,11 @@ import org.springframework.data.jdbc.core.convert.MappingJdbcConverter; @@ -40,8 +40,11 @@ import org.springframework.data.jdbc.core.convert.MappingJdbcConverter;
import org.springframework.data.jdbc.core.convert.QueryMappingConfiguration;
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
import org.springframework.data.relational.core.dialect.Dialect;
import org.springframework.data.relational.core.dialect.H2Dialect;
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
import org.springframework.data.repository.CrudRepository;
import org.springframework.jdbc.core.ConnectionCallback;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.test.util.ReflectionTestUtils;
@ -66,7 +69,12 @@ class JdbcRepositoryFactoryBeanUnitTests { @@ -66,7 +69,12 @@ class JdbcRepositoryFactoryBeanUnitTests {
@Mock(answer = Answers.RETURNS_DEEP_STUBS) ListableBeanFactory beanFactory;
@Mock Dialect dialect;
private RelationalMappingContext mappingContext;
@Mock
JdbcOperations operations;
@Mock
NamedParameterJdbcOperations namedParameterJdbcOperations;
RelationalMappingContext mappingContext;
@BeforeEach
void setUp() {
@ -76,7 +84,9 @@ class JdbcRepositoryFactoryBeanUnitTests { @@ -76,7 +84,9 @@ class JdbcRepositoryFactoryBeanUnitTests {
// Setup standard configuration
factoryBean = new JdbcRepositoryFactoryBean<>(DummyEntityRepository.class);
when(beanFactory.getBean(NamedParameterJdbcOperations.class)).thenReturn(mock(NamedParameterJdbcOperations.class));
when(operations.execute(any(ConnectionCallback.class))).thenReturn(H2Dialect.INSTANCE);
when(namedParameterJdbcOperations.getJdbcOperations()).thenReturn(operations);
when(beanFactory.getBean(NamedParameterJdbcOperations.class)).thenReturn(namedParameterJdbcOperations);
ObjectProvider<DataAccessStrategy> dataAccessStrategyObjectProvider = mock(ObjectProvider.class);
ObjectProvider<QueryMappingConfiguration> queryMappingConfigurationObjectProvider = mock(ObjectProvider.class);

11
spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/TestConfiguration.java

@ -27,6 +27,7 @@ import org.mockito.Mockito; @@ -27,6 +27,7 @@ import org.mockito.Mockito;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
@ -35,12 +36,14 @@ import org.springframework.context.annotation.Lazy; @@ -35,12 +36,14 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Profile;
import org.springframework.data.convert.CustomConversions;
import org.springframework.data.jdbc.core.JdbcAggregateOperations;
import org.springframework.data.jdbc.core.JdbcAggregateTemplate;
import org.springframework.data.jdbc.core.convert.*;
import org.springframework.data.jdbc.core.dialect.JdbcArrayColumns;
import org.springframework.data.jdbc.core.dialect.JdbcDialect;
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
import org.springframework.data.jdbc.core.mapping.JdbcSimpleTypes;
import org.springframework.data.jdbc.repository.config.DialectResolver;
import org.springframework.data.jdbc.dialect.DialectResolver;
import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory;
import org.springframework.data.mapping.callback.EntityCallback;
import org.springframework.data.mapping.callback.EntityCallbacks;
@ -194,6 +197,12 @@ public class TestConfiguration { @@ -194,6 +197,12 @@ public class TestConfiguration {
return DialectResolver.getDialect(operations.getJdbcOperations());
}
@Bean
JdbcAggregateOperations jdbcAggregateOperations(ApplicationContext publisher, JdbcConverter converter,
@Qualifier("defaultDataAccessStrategy") DataAccessStrategy dataAccessStrategy) {
return new JdbcAggregateTemplate(publisher, converter, dataAccessStrategy);
}
@Lazy
@Bean
TestDatabaseFeatures features(NamedParameterJdbcOperations operations) {

Loading…
Cancel
Save