|
|
|
@ -16,6 +16,9 @@ |
|
|
|
package org.springframework.data.jdbc.repository.support; |
|
|
|
package org.springframework.data.jdbc.repository.support; |
|
|
|
|
|
|
|
|
|
|
|
import java.io.Serializable; |
|
|
|
import java.io.Serializable; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import org.jspecify.annotations.Nullable; |
|
|
|
|
|
|
|
|
|
|
|
import org.springframework.beans.factory.BeanFactory; |
|
|
|
import org.springframework.beans.factory.BeanFactory; |
|
|
|
import org.springframework.context.ApplicationEventPublisher; |
|
|
|
import org.springframework.context.ApplicationEventPublisher; |
|
|
|
import org.springframework.context.ApplicationEventPublisherAware; |
|
|
|
import org.springframework.context.ApplicationEventPublisherAware; |
|
|
|
@ -38,6 +41,19 @@ import org.springframework.util.Assert; |
|
|
|
/** |
|
|
|
/** |
|
|
|
* Special adapter for Springs {@link org.springframework.beans.factory.FactoryBean} interface to allow easy setup of |
|
|
|
* Special adapter for Springs {@link org.springframework.beans.factory.FactoryBean} interface to allow easy setup of |
|
|
|
* repository factories via Spring configuration. |
|
|
|
* repository factories via Spring configuration. |
|
|
|
|
|
|
|
* <p> |
|
|
|
|
|
|
|
* A partially populated factory bean can use {@link BeanFactory} to resolve missing dependencies, specifically: |
|
|
|
|
|
|
|
* <ul> |
|
|
|
|
|
|
|
* <li>The {@link org.springframework.data.mapping.context.MappingContext} is being derived from |
|
|
|
|
|
|
|
* {@link RelationalMappingContext} if the {@code mappingContext} was not set.</li> |
|
|
|
|
|
|
|
* <li>The {@link NamedParameterJdbcOperations} is looked up from a {@link BeanFactory} if {@code jdbcOperations} was |
|
|
|
|
|
|
|
* not set.</li> |
|
|
|
|
|
|
|
* <li>The {@link QueryMappingConfiguration} is looked up from a {@link BeanFactory} if |
|
|
|
|
|
|
|
* {@code queryMappingConfiguration} was not set. If the {@link BeanFactory} was not set, defaults to |
|
|
|
|
|
|
|
* {@link QueryMappingConfiguration#EMPTY}.</li> |
|
|
|
|
|
|
|
* <li>The {@link DataAccessStrategy} is looked up from a {@link BeanFactory} if {@code dataAccessStrategy} was not set. |
|
|
|
|
|
|
|
* If the {@link BeanFactory} was not set, then it is created using {@link Dialect}.</li> |
|
|
|
|
|
|
|
* </ul> |
|
|
|
* |
|
|
|
* |
|
|
|
* @author Jens Schauder |
|
|
|
* @author Jens Schauder |
|
|
|
* @author Greg Turnquist |
|
|
|
* @author Greg Turnquist |
|
|
|
@ -52,15 +68,15 @@ import org.springframework.util.Assert; |
|
|
|
public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable> |
|
|
|
public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable> |
|
|
|
extends TransactionalRepositoryFactoryBeanSupport<T, S, ID> implements ApplicationEventPublisherAware { |
|
|
|
extends TransactionalRepositoryFactoryBeanSupport<T, S, ID> implements ApplicationEventPublisherAware { |
|
|
|
|
|
|
|
|
|
|
|
private ApplicationEventPublisher publisher; |
|
|
|
private @Nullable ApplicationEventPublisher publisher; |
|
|
|
private BeanFactory beanFactory; |
|
|
|
private @Nullable BeanFactory beanFactory; |
|
|
|
private RelationalMappingContext mappingContext; |
|
|
|
private @Nullable RelationalMappingContext mappingContext; |
|
|
|
private JdbcConverter converter; |
|
|
|
private @Nullable JdbcConverter converter; |
|
|
|
private DataAccessStrategy dataAccessStrategy; |
|
|
|
private @Nullable DataAccessStrategy dataAccessStrategy; |
|
|
|
private QueryMappingConfiguration queryMappingConfiguration; |
|
|
|
private @Nullable QueryMappingConfiguration queryMappingConfiguration; |
|
|
|
private NamedParameterJdbcOperations operations; |
|
|
|
private @Nullable NamedParameterJdbcOperations operations; |
|
|
|
private EntityCallbacks entityCallbacks; |
|
|
|
private EntityCallbacks entityCallbacks = EntityCallbacks.create(); |
|
|
|
private Dialect dialect; |
|
|
|
private @Nullable Dialect dialect; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Creates a new {@link JdbcRepositoryFactoryBean} for the given repository interface. |
|
|
|
* Creates a new {@link JdbcRepositoryFactoryBean} for the given repository interface. |
|
|
|
@ -85,6 +101,14 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
protected RepositoryFactorySupport doCreateRepositoryFactory() { |
|
|
|
protected RepositoryFactorySupport doCreateRepositoryFactory() { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Assert.state(this.dataAccessStrategy != null, "DataAccessStrategy is required and must not be null"); |
|
|
|
|
|
|
|
Assert.state(this.mappingContext != null, "MappingContext is required and must not be null"); |
|
|
|
|
|
|
|
Assert.state(this.converter != null, "RelationalConverter is required and must not be null"); |
|
|
|
|
|
|
|
Assert.state(this.dialect != null, "Dialect is required and must not be null"); |
|
|
|
|
|
|
|
Assert.state(this.publisher != null, "ApplicationEventPublisher is required and must not be null"); |
|
|
|
|
|
|
|
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, |
|
|
|
JdbcRepositoryFactory jdbcRepositoryFactory = new JdbcRepositoryFactory(dataAccessStrategy, mappingContext, |
|
|
|
converter, dialect, publisher, operations); |
|
|
|
converter, dialect, publisher, operations); |
|
|
|
jdbcRepositoryFactory.setQueryMappingConfiguration(queryMappingConfiguration); |
|
|
|
jdbcRepositoryFactory.setQueryMappingConfiguration(queryMappingConfiguration); |
|
|
|
@ -149,6 +173,7 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend |
|
|
|
|
|
|
|
|
|
|
|
super.setBeanFactory(beanFactory); |
|
|
|
super.setBeanFactory(beanFactory); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.entityCallbacks = EntityCallbacks.create(beanFactory); |
|
|
|
this.beanFactory = beanFactory; |
|
|
|
this.beanFactory = beanFactory; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -157,51 +182,53 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend |
|
|
|
|
|
|
|
|
|
|
|
Assert.state(this.converter != null, "RelationalConverter is required and must not be null"); |
|
|
|
Assert.state(this.converter != null, "RelationalConverter is required and must not be null"); |
|
|
|
|
|
|
|
|
|
|
|
if (mappingContext == null) { |
|
|
|
if (this.mappingContext == null) { |
|
|
|
Assert.state(beanFactory != null, "If no MappingContext are set a BeanFactory must be available"); |
|
|
|
this.mappingContext = this.converter.getMappingContext(); |
|
|
|
|
|
|
|
|
|
|
|
this.mappingContext = beanFactory.getBean(RelationalMappingContext.class); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (this.operations == null) { |
|
|
|
if (this.operations == null) { |
|
|
|
|
|
|
|
|
|
|
|
Assert.state(beanFactory != null, "If no JdbcOperations are set a BeanFactory must be available"); |
|
|
|
Assert.state(this.beanFactory != null, "If no JdbcOperations are set a BeanFactory must be available"); |
|
|
|
|
|
|
|
this.operations = this.beanFactory.getBean(NamedParameterJdbcOperations.class); |
|
|
|
this.operations = beanFactory.getBean(NamedParameterJdbcOperations.class); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (this.queryMappingConfiguration == null) { |
|
|
|
if (this.queryMappingConfiguration == null) { |
|
|
|
Assert.state(beanFactory != null, "If no QueryMappingConfiguration are set a BeanFactory must be available"); |
|
|
|
|
|
|
|
|
|
|
|
if (this.beanFactory == null) { |
|
|
|
|
|
|
|
this.queryMappingConfiguration = QueryMappingConfiguration.EMPTY; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
|
|
|
|
this.queryMappingConfiguration = beanFactory.getBeanProvider(QueryMappingConfiguration.class) |
|
|
|
this.queryMappingConfiguration = beanFactory.getBeanProvider(QueryMappingConfiguration.class) |
|
|
|
.getIfAvailable(() -> QueryMappingConfiguration.EMPTY); |
|
|
|
.getIfAvailable(() -> QueryMappingConfiguration.EMPTY); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (this.dataAccessStrategy == null) { |
|
|
|
if (this.dataAccessStrategy == null && this.beanFactory != null) { |
|
|
|
|
|
|
|
this.dataAccessStrategy = this.beanFactory.getBeanProvider(DataAccessStrategy.class).getIfAvailable(); |
|
|
|
Assert.state(beanFactory != null, "If no DataAccessStrategy is set a BeanFactory must be available"); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
this.dataAccessStrategy = this.beanFactory.getBeanProvider(DataAccessStrategy.class) //
|
|
|
|
if (this.dataAccessStrategy == null) { |
|
|
|
.getIfAvailable(() -> { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Assert.state(this.dialect != null, "Dialect is required and must not be null"); |
|
|
|
Assert.state(this.dialect != null, "Dialect is required and must not be null"); |
|
|
|
|
|
|
|
|
|
|
|
SqlGeneratorSource sqlGeneratorSource = new SqlGeneratorSource(this.mappingContext, this.converter, |
|
|
|
DataAccessStrategyFactory factory = getDataAccessStrategyFactory(this.mappingContext, this.converter, |
|
|
|
this.dialect); |
|
|
|
this.dialect, this.operations, this.queryMappingConfiguration); |
|
|
|
SqlParametersFactory sqlParametersFactory = new SqlParametersFactory(this.mappingContext, this.converter); |
|
|
|
|
|
|
|
InsertStrategyFactory insertStrategyFactory = new InsertStrategyFactory(this.operations, this.dialect); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DataAccessStrategyFactory factory = new DataAccessStrategyFactory(sqlGeneratorSource, this.converter, |
|
|
|
this.dataAccessStrategy = factory.create(); |
|
|
|
this.operations, sqlParametersFactory, insertStrategyFactory, queryMappingConfiguration); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return factory.create(); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (beanFactory != null) { |
|
|
|
super.afterPropertiesSet(); |
|
|
|
entityCallbacks = EntityCallbacks.create(beanFactory); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
super.afterPropertiesSet(); |
|
|
|
private static DataAccessStrategyFactory getDataAccessStrategyFactory(RelationalMappingContext mappingContext, |
|
|
|
|
|
|
|
JdbcConverter converter, Dialect dialect, NamedParameterJdbcOperations operations, |
|
|
|
|
|
|
|
QueryMappingConfiguration queryMapping) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SqlGeneratorSource source = new SqlGeneratorSource(mappingContext, converter, dialect); |
|
|
|
|
|
|
|
SqlParametersFactory spf = new SqlParametersFactory(mappingContext, converter); |
|
|
|
|
|
|
|
InsertStrategyFactory isf = new InsertStrategyFactory(operations, dialect); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return new DataAccessStrategyFactory(source, converter, operations, spf, isf, queryMapping); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|