From 7ee5ae446b2b2647567b3a1034b8ce90a87185ae Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Thu, 20 Jul 2017 10:14:57 +0200 Subject: [PATCH] DATACMNS-1117 - Fixed creation of RepositoryInformation in RepositoryFactoryBeanSupport. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RepositoryFactoryBeanSupport.getRepositoryInformation() previously didn't consider any store-specific compositions (incl. store-specific fragments like the Querydsl support) as it just handed a fragment with the custom implementation to RepositoryFactorySupport. This is now fixed by improving the API in RepositoryFactorySupport which now exposes a getRepositoryInformation(RepositoryMetadata, RepositoryFragments) which creates a fresh RepositoryComposition from the given RepositoryMetadata. Intermediate setup methods are still kept around but private as RepositoryFactorySupport.getRepository(…) still needs to forward the base RepositoryComposition to method interceptors for query result mapping. --- .../support/RepositoryFactoryBeanSupport.java | 10 ++-- .../support/RepositoryFactorySupport.java | 48 +++++++++++++++---- .../core/support/DummyRepositoryFactory.java | 18 +++++++ ...RepositoryFactoryBeanSupportUnitTests.java | 17 ++++++- 4 files changed, 79 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/springframework/data/repository/core/support/RepositoryFactoryBeanSupport.java b/src/main/java/org/springframework/data/repository/core/support/RepositoryFactoryBeanSupport.java index 8a967127b..1af2746a4 100644 --- a/src/main/java/org/springframework/data/repository/core/support/RepositoryFactoryBeanSupport.java +++ b/src/main/java/org/springframework/data/repository/core/support/RepositoryFactoryBeanSupport.java @@ -202,8 +202,11 @@ public abstract class RepositoryFactoryBeanSupport, * @see org.springframework.data.repository.core.support.RepositoryFactoryInformation#getRepositoryInformation() */ public RepositoryInformation getRepositoryInformation() { - return this.factory.getRepositoryInformation(repositoryMetadata, - customImplementation.map(RepositoryComposition::just).orElse(RepositoryComposition.empty())); + + RepositoryFragments fragments = customImplementation.map(RepositoryFragments::just)// + .orElse(RepositoryFragments.empty()); + + return factory.getRepositoryInformation(repositoryMetadata, fragments); } /* @@ -216,7 +219,8 @@ public abstract class RepositoryFactoryBeanSupport, .getRequiredPersistentEntity(repositoryMetadata.getDomainType()); } - /* (non-Javadoc) + /* + * (non-Javadoc) * @see org.springframework.data.repository.core.support.RepositoryFactoryInformation#getQueryMethods() */ public List getQueryMethods() { diff --git a/src/main/java/org/springframework/data/repository/core/support/RepositoryFactorySupport.java b/src/main/java/org/springframework/data/repository/core/support/RepositoryFactorySupport.java index 3a177ba0b..1f1eaa4c4 100644 --- a/src/main/java/org/springframework/data/repository/core/support/RepositoryFactorySupport.java +++ b/src/main/java/org/springframework/data/repository/core/support/RepositoryFactorySupport.java @@ -235,7 +235,7 @@ public abstract class RepositoryFactorySupport implements BeanClassLoaderAware, * @param metadata * @return */ - protected RepositoryComposition getRepositoryComposition(RepositoryMetadata metadata) { + private RepositoryComposition getRepositoryComposition(RepositoryMetadata metadata) { RepositoryComposition composition = RepositoryComposition.empty(); @@ -288,13 +288,10 @@ public abstract class RepositoryFactorySupport implements BeanClassLoaderAware, Assert.notNull(fragments, "RepositoryFragments must not be null!"); RepositoryMetadata metadata = getRepositoryMetadata(repositoryInterface); - RepositoryComposition composition = getRepositoryComposition(metadata); - RepositoryFragments repositoryAspects = getRepositoryFragments(metadata); + RepositoryComposition composition = getRepositoryComposition(metadata, fragments); + RepositoryInformation information = getRepositoryInformation(metadata, composition); - RepositoryComposition compositionToUse = composition.append(fragments).append(repositoryAspects); - RepositoryInformation information = getRepositoryInformation(metadata, compositionToUse); - - validate(information, compositionToUse); + validate(information, composition); Object target = getTargetRepository(information); @@ -311,8 +308,8 @@ public abstract class RepositoryFactorySupport implements BeanClassLoaderAware, result.addAdvice(new DefaultMethodInvokingMethodInterceptor()); result.addAdvice(new QueryExecutorMethodInterceptor(information)); - compositionToUse = compositionToUse.append(RepositoryFragment.implemented(target)); - result.addAdvice(new ImplementationMethodExecutionInterceptor(compositionToUse)); + composition = composition.append(RepositoryFragment.implemented(target)); + result.addAdvice(new ImplementationMethodExecutionInterceptor(composition)); return (T) result.getProxy(classLoader); } @@ -327,6 +324,37 @@ public abstract class RepositoryFactorySupport implements BeanClassLoaderAware, return AbstractRepositoryMetadata.getMetadata(repositoryInterface); } + /** + * Returns the {@link RepositoryInformation} for the given {@link RepositoryMetadata} and custom + * {@link RepositoryFragments}. + * + * @param metadata must not be {@literal null}. + * @param fragments must not be {@literal null}. + * @return will never be {@literal null}. + */ + protected RepositoryInformation getRepositoryInformation(RepositoryMetadata metadata, RepositoryFragments fragments) { + return getRepositoryInformation(metadata, getRepositoryComposition(metadata, fragments)); + } + + /** + * Returns the {@link RepositoryComposition} for the given {@link RepositoryMetadata} and extra + * {@link RepositoryFragments}. + * + * @param metadata must not be {@literal null}. + * @param fragments must not be {@literal null}. + * @return will never be {@literal null}. + */ + private RepositoryComposition getRepositoryComposition(RepositoryMetadata metadata, RepositoryFragments fragments) { + + Assert.notNull(metadata, "RepositoryMetadata must not be null!"); + Assert.notNull(fragments, "RepositoryFragments must not be null!"); + + RepositoryComposition composition = getRepositoryComposition(metadata); + RepositoryFragments repositoryAspects = getRepositoryFragments(metadata); + + return composition.append(fragments).append(repositoryAspects); + } + /** * Returns the {@link RepositoryInformation} for the given repository interface. * @@ -334,7 +362,7 @@ public abstract class RepositoryFactorySupport implements BeanClassLoaderAware, * @param composition * @return */ - protected RepositoryInformation getRepositoryInformation(RepositoryMetadata metadata, + private RepositoryInformation getRepositoryInformation(RepositoryMetadata metadata, RepositoryComposition composition) { RepositoryInformationCacheKey cacheKey = new RepositoryInformationCacheKey(metadata, composition); diff --git a/src/test/java/org/springframework/data/repository/core/support/DummyRepositoryFactory.java b/src/test/java/org/springframework/data/repository/core/support/DummyRepositoryFactory.java index f6b0b90f6..3e2bd725b 100644 --- a/src/test/java/org/springframework/data/repository/core/support/DummyRepositoryFactory.java +++ b/src/test/java/org/springframework/data/repository/core/support/DummyRepositoryFactory.java @@ -22,10 +22,12 @@ import java.util.Optional; import org.mockito.Mockito; import org.springframework.data.projection.ProjectionFactory; +import org.springframework.data.querydsl.QuerydslPredicateExecutor; import org.springframework.data.repository.core.EntityInformation; import org.springframework.data.repository.core.NamedQueries; import org.springframework.data.repository.core.RepositoryInformation; import org.springframework.data.repository.core.RepositoryMetadata; +import org.springframework.data.repository.core.support.RepositoryComposition.RepositoryFragments; import org.springframework.data.repository.core.support.RepositoryFactorySupportUnitTests.MyRepositoryQuery; import org.springframework.data.repository.query.EvaluationContextProvider; import org.springframework.data.repository.query.QueryLookupStrategy; @@ -44,6 +46,8 @@ public class DummyRepositoryFactory extends RepositoryFactorySupport { public final RepositoryQuery queryTwo = mock(RepositoryQuery.class); public final QueryLookupStrategy strategy = mock(QueryLookupStrategy.class); + @SuppressWarnings("unchecked") private final QuerydslPredicateExecutor querydsl = mock( + QuerydslPredicateExecutor.class); private final Object repository; public DummyRepositoryFactory(Object repository) { @@ -91,4 +95,18 @@ public class DummyRepositoryFactory extends RepositoryFactorySupport { EvaluationContextProvider evaluationContextProvider) { return Optional.of(strategy); } + + /* + * (non-Javadoc) + * @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getRepositoryFragments(org.springframework.data.repository.core.RepositoryMetadata) + */ + @Override + protected RepositoryFragments getRepositoryFragments(RepositoryMetadata metadata) { + + RepositoryFragments fragments = super.getRepositoryFragments(metadata); + + return QuerydslPredicateExecutor.class.isAssignableFrom(metadata.getRepositoryInterface()) // + ? fragments.append(RepositoryFragments.just(querydsl)) // + : fragments; + } } diff --git a/src/test/java/org/springframework/data/repository/core/support/RepositoryFactoryBeanSupportUnitTests.java b/src/test/java/org/springframework/data/repository/core/support/RepositoryFactoryBeanSupportUnitTests.java index 9411028b1..c6359ae01 100755 --- a/src/test/java/org/springframework/data/repository/core/support/RepositoryFactoryBeanSupportUnitTests.java +++ b/src/test/java/org/springframework/data/repository/core/support/RepositoryFactoryBeanSupportUnitTests.java @@ -21,8 +21,9 @@ import static org.mockito.Mockito.*; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; - +import org.springframework.data.querydsl.QuerydslPredicateExecutor; import org.springframework.data.repository.Repository; +import org.springframework.data.repository.core.RepositoryInformation; import org.springframework.test.util.ReflectionTestUtils; /** @@ -59,5 +60,19 @@ public class RepositoryFactoryBeanSupportUnitTests { .withMessageContaining("Repository interface"); } + @Test // DATACMNS-1117 + public void returnsRepositoryInformationForFragmentSetup() { + + RepositoryFactoryBeanSupport factoryBean = // + new DummyRepositoryFactoryBean<>(SampleWithQuerydslRepository.class); + factoryBean.afterPropertiesSet(); + + RepositoryInformation information = factoryBean.getRepositoryInformation(); + + assertThat(information.getQueryMethods()).isEmpty(); + } + interface SampleRepository extends Repository {} + + interface SampleWithQuerydslRepository extends Repository, QuerydslPredicateExecutor {} }