Fluent query API should use ProjectionFactory provided by the RepositoryFactory.

This commit makes sure to push the ProjectionFactory down to the fluent query to make use of beans registered in the context. Prior to this change the fluent query variant would host its own factory not being aware of its surroundings.

Original pull request: #3432
Closes: #3410
This commit is contained in:
Christoph Strobl
2024-04-17 11:39:55 +02:00
committed by Mark Paluch
parent 4d720316c3
commit 0af9c62e04
15 changed files with 162 additions and 36 deletions

View File

@@ -21,6 +21,7 @@ import java.lang.reflect.Method;
import java.util.Optional;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.lang.Nullable;
/**
@@ -85,4 +86,11 @@ public interface CrudMethodMetadata {
* @since 1.9
*/
Method getMethod();
/**
* @return the {@link ProjectionFactory} to use or {@literal null} if not present.
* @since ??
*/
@Nullable
ProjectionFactory getProjectionFactory();
}

View File

@@ -25,6 +25,7 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Predicate;
import java.util.function.Supplier;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
@@ -38,6 +39,7 @@ import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.Lock;
import org.springframework.data.jpa.repository.Meta;
import org.springframework.data.jpa.repository.QueryHints;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.support.RepositoryProxyPostProcessor;
import org.springframework.lang.Nullable;
@@ -61,6 +63,11 @@ import org.springframework.util.ReflectionUtils;
class CrudMethodMetadataPostProcessor implements RepositoryProxyPostProcessor, BeanClassLoaderAware {
private @Nullable ClassLoader classLoader = ClassUtils.getDefaultClassLoader();
private final Supplier<ProjectionFactory> projectionFactorySupplier;
CrudMethodMetadataPostProcessor(Supplier<ProjectionFactory> projectionFactorySupplier) {
this.projectionFactorySupplier = projectionFactorySupplier;
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
@@ -69,7 +76,8 @@ class CrudMethodMetadataPostProcessor implements RepositoryProxyPostProcessor, B
@Override
public void postProcess(ProxyFactory factory, RepositoryInformation repositoryInformation) {
factory.addAdvice(new CrudMethodMetadataPopulatingMethodInterceptor(repositoryInformation));
factory
.addAdvice(new CrudMethodMetadataPopulatingMethodInterceptor(repositoryInformation, projectionFactorySupplier));
}
/**
@@ -101,11 +109,14 @@ class CrudMethodMetadataPostProcessor implements RepositoryProxyPostProcessor, B
private final ConcurrentMap<Method, CrudMethodMetadata> metadataCache = new ConcurrentHashMap<>();
private final Set<Method> implementations = new HashSet<>();
private final Supplier<ProjectionFactory> projectionFactory;
CrudMethodMetadataPopulatingMethodInterceptor(RepositoryInformation repositoryInformation) {
CrudMethodMetadataPopulatingMethodInterceptor(RepositoryInformation repositoryInformation,
Supplier<ProjectionFactory> projectionFactory) {
ReflectionUtils.doWithMethods(repositoryInformation.getRepositoryInterface(), implementations::add,
method -> !repositoryInformation.isQueryMethod(method));
this.projectionFactory = projectionFactory;
}
/**
@@ -150,7 +161,7 @@ class CrudMethodMetadataPostProcessor implements RepositoryProxyPostProcessor, B
if (methodMetadata == null) {
methodMetadata = new DefaultCrudMethodMetadata(method);
methodMetadata = new DefaultCrudMethodMetadata(method, projectionFactory.get());
CrudMethodMetadata tmp = metadataCache.putIfAbsent(method, methodMetadata);
if (tmp != null) {
@@ -185,15 +196,17 @@ class CrudMethodMetadataPostProcessor implements RepositoryProxyPostProcessor, B
private final @Nullable String comment;
private final Optional<EntityGraph> entityGraph;
private final Method method;
private ProjectionFactory projectionFactory;
/**
* Creates a new {@link DefaultCrudMethodMetadata} for the given {@link Method}.
*
* @param method must not be {@literal null}.
*/
DefaultCrudMethodMetadata(Method method) {
DefaultCrudMethodMetadata(Method method, ProjectionFactory projectionFactory) {
Assert.notNull(method, "Method must not be null");
this.projectionFactory = projectionFactory;
this.lockModeType = findLockModeType(method);
this.queryHints = findQueryHints(method, it -> true);
@@ -274,6 +287,11 @@ class CrudMethodMetadataPostProcessor implements RepositoryProxyPostProcessor, B
public Method getMethod() {
return method;
}
@Override
public ProjectionFactory getProjectionFactory() {
return projectionFactory;
}
}
private static class ThreadBoundTargetSource implements TargetSource {

View File

@@ -34,6 +34,7 @@ import org.springframework.data.domain.ScrollPosition;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Window;
import org.springframework.data.jpa.repository.query.ScrollDelegate;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery;
import org.springframework.data.support.PageableExecutionUtils;
import org.springframework.util.Assert;
@@ -51,6 +52,7 @@ import com.querydsl.jpa.impl.AbstractJPAQuery;
* @author Mark Paluch
* @author Jens Schauder
* @author J.R. Onyschak
* @author Christoph Strobl
* @since 2.6
*/
class FetchableFluentQueryByPredicate<S, R> extends FluentQuerySupport<S, R> implements FetchableFluentQuery<R> {
@@ -64,21 +66,21 @@ class FetchableFluentQueryByPredicate<S, R> extends FluentQuerySupport<S, R> imp
private final Function<Predicate, Boolean> existsOperation;
private final EntityManager entityManager;
public FetchableFluentQueryByPredicate(Predicate predicate, Class<S> entityType,
FetchableFluentQueryByPredicate(Predicate predicate, Class<S> entityType,
Function<Sort, AbstractJPAQuery<?, ?>> finder, PredicateScrollDelegate<S> scroll,
BiFunction<Sort, Pageable, AbstractJPAQuery<?, ?>> pagedFinder, Function<Predicate, Long> countOperation,
Function<Predicate, Boolean> existsOperation, EntityManager entityManager) {
Function<Predicate, Boolean> existsOperation, EntityManager entityManager, ProjectionFactory projectionFactory) {
this(predicate, entityType, (Class<R>) entityType, Sort.unsorted(), 0, Collections.emptySet(), finder, scroll,
pagedFinder, countOperation, existsOperation, entityManager);
pagedFinder, countOperation, existsOperation, entityManager, projectionFactory);
}
private FetchableFluentQueryByPredicate(Predicate predicate, Class<S> entityType, Class<R> resultType, Sort sort,
int limit, Collection<String> properties, Function<Sort, AbstractJPAQuery<?, ?>> finder,
PredicateScrollDelegate<S> scroll, BiFunction<Sort, Pageable, AbstractJPAQuery<?, ?>> pagedFinder,
Function<Predicate, Long> countOperation, Function<Predicate, Boolean> existsOperation,
EntityManager entityManager) {
EntityManager entityManager, ProjectionFactory projectionFactory) {
super(resultType, sort, limit, properties, entityType);
super(resultType, sort, limit, properties, entityType, projectionFactory);
this.predicate = predicate;
this.finder = finder;
this.scroll = scroll;
@@ -94,7 +96,8 @@ class FetchableFluentQueryByPredicate<S, R> extends FluentQuerySupport<S, R> imp
Assert.notNull(sort, "Sort must not be null");
return new FetchableFluentQueryByPredicate<>(predicate, entityType, resultType, this.sort.and(sort), limit,
properties, finder, scroll, pagedFinder, countOperation, existsOperation, entityManager);
properties, finder, scroll, pagedFinder, countOperation, existsOperation, entityManager,
getProjectionFactory());
}
@Override
@@ -103,7 +106,7 @@ class FetchableFluentQueryByPredicate<S, R> extends FluentQuerySupport<S, R> imp
Assert.isTrue(limit >= 0, "Limit must not be negative");
return new FetchableFluentQueryByPredicate<>(predicate, entityType, resultType, sort, limit, properties, finder,
scroll, pagedFinder, countOperation, existsOperation, entityManager);
scroll, pagedFinder, countOperation, existsOperation, entityManager, getProjectionFactory());
}
@Override
@@ -116,14 +119,15 @@ class FetchableFluentQueryByPredicate<S, R> extends FluentQuerySupport<S, R> imp
}
return new FetchableFluentQueryByPredicate<>(predicate, entityType, resultType, sort, limit, properties, finder,
scroll, pagedFinder, countOperation, existsOperation, entityManager);
scroll, pagedFinder, countOperation, existsOperation, entityManager, getProjectionFactory());
}
@Override
public FetchableFluentQuery<R> project(Collection<String> properties) {
return new FetchableFluentQueryByPredicate<>(predicate, entityType, resultType, sort, limit,
mergeProperties(properties), finder, scroll, pagedFinder, countOperation, existsOperation, entityManager);
mergeProperties(properties), finder, scroll, pagedFinder, countOperation, existsOperation, entityManager,
getProjectionFactory());
}
@Override
@@ -230,7 +234,6 @@ class FetchableFluentQueryByPredicate<S, R> extends FluentQuerySupport<S, R> imp
return getConversionFunction(entityType, resultType);
}
static class PredicateScrollDelegate<T> extends ScrollDelegate<T> {
private final ScrollQueryFactory scrollFunction;

View File

@@ -36,6 +36,7 @@ import org.springframework.data.domain.Window;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.query.ScrollDelegate;
import org.springframework.data.jpa.support.PageableUtils;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.repository.query.FluentQuery;
import org.springframework.data.support.PageableExecutionUtils;
import org.springframework.util.Assert;
@@ -47,6 +48,7 @@ import org.springframework.util.Assert;
* @param <S> Domain type
* @param <R> Result type
* @author Greg Turnquist
* @author Christoph Strobl
* @since 3.0
*/
class FetchableFluentQueryBySpecification<S, R> extends FluentQuerySupport<S, R>
@@ -59,20 +61,21 @@ class FetchableFluentQueryBySpecification<S, R> extends FluentQuerySupport<S, R>
private final Function<Specification<S>, Boolean> existsOperation;
private final EntityManager entityManager;
public FetchableFluentQueryBySpecification(Specification<S> spec, Class<S> entityType,
Function<Sort, TypedQuery<S>> finder, SpecificationScrollDelegate<S> scrollDelegate,
Function<Specification<S>, Long> countOperation, Function<Specification<S>, Boolean> existsOperation,
EntityManager entityManager) {
FetchableFluentQueryBySpecification(Specification<S> spec, Class<S> entityType, Function<Sort, TypedQuery<S>> finder,
SpecificationScrollDelegate<S> scrollDelegate, Function<Specification<S>, Long> countOperation,
Function<Specification<S>, Boolean> existsOperation, EntityManager entityManager,
ProjectionFactory projectionFactory) {
this(spec, entityType, (Class<R>) entityType, Sort.unsorted(), 0, Collections.emptySet(), finder, scrollDelegate,
countOperation, existsOperation, entityManager);
countOperation, existsOperation, entityManager, projectionFactory);
}
private FetchableFluentQueryBySpecification(Specification<S> spec, Class<S> entityType, Class<R> resultType,
Sort sort, int limit, Collection<String> properties, Function<Sort, TypedQuery<S>> finder,
SpecificationScrollDelegate<S> scrollDelegate, Function<Specification<S>, Long> countOperation,
Function<Specification<S>, Boolean> existsOperation, EntityManager entityManager) {
Function<Specification<S>, Boolean> existsOperation, EntityManager entityManager,
ProjectionFactory projectionFactory) {
super(resultType, sort, limit, properties, entityType);
super(resultType, sort, limit, properties, entityType, projectionFactory);
this.spec = spec;
this.finder = finder;
this.scroll = scrollDelegate;
@@ -87,7 +90,7 @@ class FetchableFluentQueryBySpecification<S, R> extends FluentQuerySupport<S, R>
Assert.notNull(sort, "Sort must not be null");
return new FetchableFluentQueryBySpecification<>(spec, entityType, resultType, this.sort.and(sort), limit,
properties, finder, scroll, countOperation, existsOperation, entityManager);
properties, finder, scroll, countOperation, existsOperation, entityManager, getProjectionFactory());
}
@Override
@@ -96,7 +99,7 @@ class FetchableFluentQueryBySpecification<S, R> extends FluentQuerySupport<S, R>
Assert.isTrue(limit >= 0, "Limit must not be negative");
return new FetchableFluentQueryBySpecification<>(spec, entityType, resultType, this.sort.and(sort), limit,
properties, finder, scroll, countOperation, existsOperation, entityManager);
properties, finder, scroll, countOperation, existsOperation, entityManager, getProjectionFactory());
}
@Override
@@ -108,14 +111,14 @@ class FetchableFluentQueryBySpecification<S, R> extends FluentQuerySupport<S, R>
}
return new FetchableFluentQueryBySpecification<>(spec, entityType, resultType, sort, limit, properties, finder,
scroll, countOperation, existsOperation, entityManager);
scroll, countOperation, existsOperation, entityManager, getProjectionFactory());
}
@Override
public FetchableFluentQuery<R> project(Collection<String> properties) {
return new FetchableFluentQueryBySpecification<>(spec, entityType, resultType, sort, limit, properties, finder,
scroll, countOperation, existsOperation, entityManager);
scroll, countOperation, existsOperation, entityManager, getProjectionFactory());
}
@Override

View File

@@ -26,6 +26,7 @@ import java.util.function.Function;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.data.domain.ScrollPosition;
import org.springframework.data.domain.Sort;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.lang.Nullable;
@@ -36,6 +37,7 @@ import org.springframework.lang.Nullable;
* @author Greg Turnquist
* @author Jens Schauder
* @author Mark Paluch
* @author Christoph Strobl
* @since 2.6
*/
abstract class FluentQuerySupport<S, R> {
@@ -46,10 +48,10 @@ abstract class FluentQuerySupport<S, R> {
protected final Set<String> properties;
protected final Class<S> entityType;
private final SpelAwareProxyProjectionFactory projectionFactory = new SpelAwareProxyProjectionFactory();
private final ProjectionFactory projectionFactory;
FluentQuerySupport(Class<R> resultType, Sort sort, int limit, @Nullable Collection<String> properties,
Class<S> entityType) {
Class<S> entityType, ProjectionFactory projectionFactory) {
this.resultType = resultType;
this.sort = sort;
@@ -62,6 +64,11 @@ abstract class FluentQuerySupport<S, R> {
}
this.entityType = entityType;
this.projectionFactory = projectionFactory;
}
ProjectionFactory getProjectionFactory() {
return projectionFactory;
}
final Collection<String> mergeProperties(Collection<String> additionalProperties) {

View File

@@ -100,7 +100,7 @@ public class JpaRepositoryFactory extends RepositoryFactorySupport {
this.entityManager = entityManager;
this.extractor = PersistenceProvider.fromEntityManager(entityManager);
this.crudMethodMetadataPostProcessor = new CrudMethodMetadataPostProcessor();
this.crudMethodMetadataPostProcessor = new CrudMethodMetadataPostProcessor(() -> getProjectionFactory());
this.entityPathResolver = SimpleEntityPathResolver.INSTANCE;
this.queryMethodFactory = new DefaultJpaQueryMethodFactory(extractor);
this.queryRewriterProvider = QueryRewriterProvider.simple();

View File

@@ -36,9 +36,12 @@ import org.springframework.data.jpa.repository.query.KeysetScrollDelegate.QueryS
import org.springframework.data.jpa.repository.query.KeysetScrollSpecification;
import org.springframework.data.jpa.repository.support.FetchableFluentQueryByPredicate.PredicateScrollDelegate;
import org.springframework.data.jpa.repository.support.FluentQuerySupport.ScrollQueryFactory;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.data.querydsl.EntityPathResolver;
import org.springframework.data.querydsl.QSort;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery;
import org.springframework.data.support.PageableExecutionUtils;
import org.springframework.lang.Nullable;
@@ -223,7 +226,8 @@ public class QuerydslJpaPredicateExecutor<T> implements QuerydslPredicateExecuto
pagedFinder, //
this::count, //
this::exists, //
entityManager //
entityManager, //
getProjectionFactory()
);
return queryFunction.apply((FetchableFluentQuery<S>) fluentQuery);
@@ -251,7 +255,6 @@ public class QuerydslJpaPredicateExecutor<T> implements QuerydslPredicateExecuto
AbstractJPAQuery<?, ?> query = doCreateQuery(getQueryHints().withFetchGraphs(entityManager), predicate);
CrudMethodMetadata metadata = getRepositoryMethodMetadata();
if (metadata == null) {
return query;
}
@@ -331,6 +334,16 @@ public class QuerydslJpaPredicateExecutor<T> implements QuerydslPredicateExecuto
return querydsl.applySorting(sort, query).fetch();
}
private ProjectionFactory getProjectionFactory() {
CrudMethodMetadata metadata = getRepositoryMethodMetadata();
if(metadata == null || metadata.getProjectionFactory() == null) {
return new SpelAwareProxyProjectionFactory();
}
return metadata.getProjectionFactory();
}
class QuerydslQueryStrategy implements QueryStrategy<Expression<?>, BooleanExpression> {
@Override

View File

@@ -61,6 +61,8 @@ import org.springframework.data.jpa.repository.support.FetchableFluentQueryBySpe
import org.springframework.data.jpa.repository.support.FluentQuerySupport.ScrollQueryFactory;
import org.springframework.data.jpa.repository.support.QueryHints.NoHints;
import org.springframework.data.jpa.support.PageableUtils;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery;
import org.springframework.data.support.PageableExecutionUtils;
import org.springframework.data.util.ProxyUtils;
@@ -524,8 +526,8 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
SpecificationScrollDelegate<T> scrollDelegate = new SpecificationScrollDelegate<>(scrollFunction,
entityInformation);
FetchableFluentQuery<T> fluentQuery = new FetchableFluentQueryBySpecification<>(spec, domainClass, finder,
scrollDelegate, this::count, this::exists, this.entityManager);
FetchableFluentQueryBySpecification<?, T> fluentQuery = new FetchableFluentQueryBySpecification<>(spec, domainClass, finder,
scrollDelegate, this::count, this::exists, this.entityManager, getProjectionFactory());
return queryFunction.apply((FetchableFluentQuery<S>) fluentQuery);
}
@@ -903,6 +905,16 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
}
}
private ProjectionFactory getProjectionFactory() {
CrudMethodMetadata metadata = getRepositoryMethodMetadata();
if(metadata == null || metadata.getProjectionFactory() == null) {
return new SpelAwareProxyProjectionFactory();
}
return metadata.getProjectionFactory();
}
/**
* Executes a count query and transparently sums up all values returned.
*

View File

@@ -0,0 +1,26 @@
/*
* Copyright 2024 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.jpa.repository;
/**
* A trivial component registered via {@literal appication-context.xml} to be called from SpEL.
*/
public class GreetingsFrom {
public String groot(String name) {
return "(%s) - I am Groot!".formatted(name);
}
}

View File

@@ -88,6 +88,11 @@ class JavaConfigUserRepositoryTests extends UserRepositoryTests {
return factory.getObject();
}
@Bean
public GreetingsFrom greetingsFrom() {
return new GreetingsFrom();
}
private NamedQueries namedQueries() throws IOException {
PropertiesFactoryBean factory = new PropertiesFactoryBean();

View File

@@ -51,6 +51,7 @@ import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
@@ -67,6 +68,7 @@ import org.springframework.data.jpa.domain.sample.User;
import org.springframework.data.jpa.repository.sample.SampleEvaluationContextExtension.SampleSecurityContextHolder;
import org.springframework.data.jpa.repository.sample.UserRepository;
import org.springframework.data.jpa.repository.sample.UserRepository.NameOnly;
import org.springframework.stereotype.Component;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.transaction.annotation.Transactional;
@@ -2437,6 +2439,24 @@ class UserRepositoryTests {
.containsExactlyInAnyOrder(firstUser.getFirstname(), thirdUser.getFirstname(), fourthUser.getFirstname());
}
@Test // GH-3410
void findByFluentExampleWithInterfaceBasedProjectionUsingSpEL() {
flushTestUsers();
User prototype = new User();
prototype.setFirstname("v");
List<UserProjectionUsingSpEL> users = repository.findBy(
of(prototype,
matching().withIgnorePaths("age", "createdAt", "active").withMatcher("firstname",
GenericPropertyMatcher::contains)), //
q -> q.as(UserProjectionUsingSpEL.class).all());
assertThat(users).extracting(UserProjectionUsingSpEL::hello)
.contains(new GreetingsFrom().groot(firstUser.getFirstname()));
}
@Test // GH-2294
void findByFluentExampleWithSimplePropertyPathsDoesntLoadUnrequestedPaths() {
@@ -3364,4 +3384,10 @@ class UserRepositoryTests {
private interface UserProjectionInterfaceBased {
String getFirstname();
}
private interface UserProjectionUsingSpEL {
@Value("#{@greetingsFrom.groot(target.firstname)}")
String hello();
}
}

View File

@@ -34,6 +34,7 @@ import org.mockito.quality.Strictness;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.data.jpa.repository.Lock;
import org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor.CrudMethodMetadataPopulatingMethodInterceptor;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.transaction.support.TransactionSynchronizationManager;
@@ -56,7 +57,7 @@ class CrudMethodMetadataPopulatingMethodInterceptorUnitTests {
ProxyFactory factory = new ProxyFactory(new Object());
factory.addInterface(Sample.class);
factory.addAdvice(new CrudMethodMetadataPopulatingMethodInterceptor(information));
factory.addAdvice(new CrudMethodMetadataPopulatingMethodInterceptor(information, SpelAwareProxyProjectionFactory::new));
factory.addAdvice(new MethodInterceptor() {
@Override
@@ -78,7 +79,7 @@ class CrudMethodMetadataPopulatingMethodInterceptorUnitTests {
when(information.getRepositoryInterface()).thenReturn((Class) Sample.class);
CrudMethodMetadataPopulatingMethodInterceptor interceptor = new CrudMethodMetadataPopulatingMethodInterceptor(
information);
information, () -> new SpelAwareProxyProjectionFactory());
interceptor.invoke(invocation);
assertThat(TransactionSynchronizationManager.getResource(method)).isNull();
@@ -88,7 +89,7 @@ class CrudMethodMetadataPopulatingMethodInterceptorUnitTests {
@SuppressWarnings("unchecked")
void looksUpCrudMethodMetadataForEveryInvocation() {
CrudMethodMetadata metadata = new CrudMethodMetadataPostProcessor().getCrudMethodMetadata();
CrudMethodMetadata metadata = new CrudMethodMetadataPostProcessor(() -> new SpelAwareProxyProjectionFactory()).getCrudMethodMetadata();
when(information.isQueryMethod(any())).thenReturn(false);
when(information.getRepositoryInterface()).thenReturn((Class) Sample.class);

View File

@@ -35,7 +35,7 @@ class FetchableFluentQueryByPredicateUnitTests {
Sort s1 = Sort.by(Order.by("s1"));
Sort s2 = Sort.by(Order.by("s2"));
FetchableFluentQueryByPredicate f = new FetchableFluentQueryByPredicate(null, null, null, null, null, null, null,
null);
null, null);
f = (FetchableFluentQueryByPredicate) f.sortBy(s1).sortBy(s2);
assertThat(f.sort).isEqualTo(s1.and(s2));
}

View File

@@ -43,4 +43,6 @@
<bean class="org.springframework.data.jpa.repository.support.EntityManagerBeanDefinitionRegistrarPostProcessor" />
<bean class="org.springframework.data.jpa.repository.GreetingsFrom" name="greetingsFrom" />
</beans>

View File

@@ -28,4 +28,6 @@
<!-- Register custom DAO implementation explicitly -->
<bean id="userRepositoryImpl" class="org.springframework.data.jpa.repository.sample.UserRepositoryImpl" />
<bean class="org.springframework.data.jpa.repository.GreetingsFrom" name="greetingsFrom" />
</beans>