diff --git a/src/main/java/org/springframework/data/projection/SpelAwareProxyProjectionFactory.java b/src/main/java/org/springframework/data/projection/SpelAwareProxyProjectionFactory.java index f3b60a9c6..449a6a0ed 100644 --- a/src/main/java/org/springframework/data/projection/SpelAwareProxyProjectionFactory.java +++ b/src/main/java/org/springframework/data/projection/SpelAwareProxyProjectionFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2016 the original author or authors. + * Copyright 2015-2017 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. @@ -39,6 +39,7 @@ import org.springframework.util.ReflectionUtils; * @author Oliver Gierke * @author Thomas Darimont * @author Mark Paluch + * @author Jens Schauder * @since 1.10 */ public class SpelAwareProxyProjectionFactory extends ProxyProjectionFactory implements BeanFactoryAware { @@ -63,29 +64,7 @@ public class SpelAwareProxyProjectionFactory extends ProxyProjectionFactory impl */ @Override protected ProjectionInformation createProjectionInformation(Class projectionType) { - - return new DefaultProjectionInformation(projectionType) { - - /* - * (non-Javadoc) - * @see org.springframework.data.projection.DefaultProjectionInformation#isInputProperty(java.beans.PropertyDescriptor) - */ - @Override - protected boolean isInputProperty(PropertyDescriptor descriptor) { - - if (!super.isInputProperty(descriptor)) { - return false; - } - - Method readMethod = descriptor.getReadMethod(); - - if (readMethod == null) { - return false; - } - - return AnnotationUtils.findAnnotation(readMethod, Value.class) == null; - } - }; + return new SpelAwareProjectionInformation(projectionType); } /** @@ -121,4 +100,31 @@ public class SpelAwareProxyProjectionFactory extends ProxyProjectionFactory impl return callback.hasFoundAnnotation(); } + + protected static class SpelAwareProjectionInformation extends DefaultProjectionInformation { + + protected SpelAwareProjectionInformation(Class projectionType) { + super(projectionType); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.projection.DefaultProjectionInformation#isInputProperty(java.beans.PropertyDescriptor) + */ + @Override + protected boolean isInputProperty(PropertyDescriptor descriptor) { + + if (!super.isInputProperty(descriptor)) { + return false; + } + + Method readMethod = descriptor.getReadMethod(); + + if (readMethod == null) { + return false; + } + + return AnnotationUtils.findAnnotation(readMethod, Value.class) == null; + } + } } 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 738389e2c..a27049135 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 @@ -34,6 +34,7 @@ import java.util.stream.Collectors; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; +import org.jetbrains.annotations.NotNull; import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.interceptor.ExposeInvocationInterceptor; import org.springframework.beans.BeanUtils; @@ -45,6 +46,7 @@ import org.springframework.core.MethodParameter; import org.springframework.core.ResolvableType; import org.springframework.core.convert.TypeDescriptor; import org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor; +import org.springframework.data.projection.ProjectionFactory; import org.springframework.data.projection.SpelAwareProxyProjectionFactory; import org.springframework.data.repository.Repository; import org.springframework.data.repository.core.EntityInformation; @@ -77,6 +79,7 @@ import org.springframework.util.ConcurrentReferenceHashMap.ReferenceType; * @author Oliver Gierke * @author Mark Paluch * @author Christoph Strobl + * @author Jens Schauder */ public abstract class RepositoryFactorySupport implements BeanClassLoaderAware, BeanFactoryAware { @@ -312,7 +315,10 @@ public abstract class RepositoryFactorySupport implements BeanClassLoaderAware, postProcessors.forEach(processor -> processor.postProcess(result, information)); result.addAdvice(new DefaultMethodInvokingMethodInterceptor()); - result.addAdvice(new QueryExecutorMethodInterceptor(information)); + result.addAdvice(new QueryExecutorMethodInterceptor( // + information, // + getProjectionFactory(classLoader, beanFactory) // + )); composition = composition.append(RepositoryFragment.implemented(target)); result.addAdvice(new ImplementationMethodExecutionInterceptor(composition)); @@ -320,6 +326,16 @@ public abstract class RepositoryFactorySupport implements BeanClassLoaderAware, return (T) result.getProxy(classLoader); } + @NotNull + protected ProjectionFactory getProjectionFactory(ClassLoader classLoader, BeanFactory beanFactory) { + + SpelAwareProxyProjectionFactory factory = new SpelAwareProxyProjectionFactory(); + factory.setBeanClassLoader(classLoader); + factory.setBeanFactory(beanFactory); + + return factory; + } + /** * Returns the {@link RepositoryMetadata} for the given repository interface. * @@ -501,7 +517,8 @@ public abstract class RepositoryFactorySupport implements BeanClassLoaderAware, * Creates a new {@link QueryExecutorMethodInterceptor}. Builds a model of {@link QueryMethod}s to be invoked on * execution of repository interface methods. */ - public QueryExecutorMethodInterceptor(RepositoryInformation repositoryInformation) { + public QueryExecutorMethodInterceptor(RepositoryInformation repositoryInformation, + ProjectionFactory projectionFactory) { this.resultHandler = new QueryExecutionResultHandler(); @@ -515,18 +532,20 @@ public abstract class RepositoryFactorySupport implements BeanClassLoaderAware, + "infrastructure apparently does not support query methods!"); } - this.queries = lookupStrategy.map(it -> { - - SpelAwareProxyProjectionFactory factory = new SpelAwareProxyProjectionFactory(); - factory.setBeanClassLoader(classLoader); - factory.setBeanFactory(beanFactory); + this.queries = lookupStrategy.map( // + it -> mapMethodsToQuery(repositoryInformation, projectionFactory, it) // + ).orElse(Collections.emptyMap()); + } - return repositoryInformation.getQueryMethods().stream()// - .map(method -> Pair.of(method, it.resolveQuery(method, repositoryInformation, factory, namedQueries)))// - .peek(pair -> invokeListeners(pair.getSecond()))// - .collect(Pair.toMap()); + private Map mapMethodsToQuery(RepositoryInformation repositoryInformation, + ProjectionFactory projectionFactory, QueryLookupStrategy lookupStrategy) { - }).orElse(Collections.emptyMap()); + return repositoryInformation.getQueryMethods().stream() // + .map(method -> Pair.of( // + method, // + lookupStrategy.resolveQuery(method, repositoryInformation, projectionFactory, namedQueries))) // + .peek(pair -> invokeListeners(pair.getSecond())) // + .collect(Pair.toMap()); } @SuppressWarnings({ "rawtypes", "unchecked" }) diff --git a/src/test/java/org/springframework/data/repository/core/support/QueryExecutorMethodInterceptorUnitTests.java b/src/test/java/org/springframework/data/repository/core/support/QueryExecutorMethodInterceptorUnitTests.java index ef9f67b71..2e685e2ea 100755 --- a/src/test/java/org/springframework/data/repository/core/support/QueryExecutorMethodInterceptorUnitTests.java +++ b/src/test/java/org/springframework/data/repository/core/support/QueryExecutorMethodInterceptorUnitTests.java @@ -23,6 +23,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.data.projection.SpelAwareProxyProjectionFactory; import org.springframework.data.repository.core.RepositoryInformation; import org.springframework.data.repository.query.QueryLookupStrategy; import org.springframework.data.util.Streamable; @@ -32,6 +33,7 @@ import org.springframework.data.util.Streamable; * * @author Oliver Gierke * @author Mark Paluch + * @author Jens Schauder */ @RunWith(MockitoJUnitRunner.class) public class QueryExecutorMethodInterceptorUnitTests { @@ -46,7 +48,7 @@ public class QueryExecutorMethodInterceptorUnitTests { when(information.hasQueryMethods()).thenReturn(true); when(factory.getQueryLookupStrategy(any(), any())).thenReturn(Optional.empty()); - factory.new QueryExecutorMethodInterceptor(information); + factory.new QueryExecutorMethodInterceptor(information, new SpelAwareProxyProjectionFactory()); } @Test @@ -55,7 +57,7 @@ public class QueryExecutorMethodInterceptorUnitTests { when(information.getQueryMethods()).thenReturn(Streamable.empty()); when(factory.getQueryLookupStrategy(any(), any())).thenReturn(Optional.of(strategy)); - factory.new QueryExecutorMethodInterceptor(information); + factory.new QueryExecutorMethodInterceptor(information, new SpelAwareProxyProjectionFactory()); verify(strategy, times(0)).resolveQuery(any(), any(), any(), any()); }