,
private NamedQueries namedQueries;
private MappingContext, ?> mappingContext;
private ClassLoader classLoader;
+ private BeanFactory beanFactory;
private boolean lazyInit = false;
private EvaluationContextProvider evaluationContextProvider = DefaultEvaluationContextProvider.INSTANCE;
@@ -151,6 +155,16 @@ public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.beans.factory.BeanFactoryAware#setBeanFactory(org.springframework.beans.factory.BeanFactory)
+ */
+ @Override
+ public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
+ this.beanFactory = beanFactory;
+
+ }
+
/*
* (non-Javadoc)
* @see org.springframework.data.repository.core.support.RepositoryFactoryInformation#getEntityInformation()
@@ -167,8 +181,8 @@ public EntityInformation getEntityInformation() {
*/
public RepositoryInformation getRepositoryInformation() {
- return this.factory.getRepositoryInformation(repositoryMetadata, customImplementation == null ? null
- : customImplementation.getClass());
+ return this.factory.getRepositoryInformation(repositoryMetadata,
+ customImplementation == null ? null : customImplementation.getClass());
}
/*
@@ -227,9 +241,10 @@ public void afterPropertiesSet() {
this.factory = createRepositoryFactory();
this.factory.setQueryLookupStrategyKey(queryLookupStrategyKey);
this.factory.setNamedQueries(namedQueries);
- this.factory.setBeanClassLoader(classLoader);
this.factory.setEvaluationContextProvider(evaluationContextProvider);
this.factory.setRepositoryBaseClass(repositoryBaseClass);
+ this.factory.setBeanClassLoader(classLoader);
+ this.factory.setBeanFactory(beanFactory);
this.repositoryMetadata = this.factory.getRepositoryMetadata(repositoryInterface);
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 56c5ae52b3..b45ec1757f 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
@@ -29,11 +29,15 @@
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.interceptor.ExposeInvocationInterceptor;
import org.springframework.beans.BeanUtils;
+import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor;
+import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.EntityInformation;
import org.springframework.data.repository.core.NamedQueries;
@@ -57,7 +61,7 @@
*
* @author Oliver Gierke
*/
-public abstract class RepositoryFactorySupport implements BeanClassLoaderAware {
+public abstract class RepositoryFactorySupport implements BeanClassLoaderAware, BeanFactoryAware {
private static final boolean IS_JAVA_8 = org.springframework.util.ClassUtils.isPresent("java.util.Optional",
RepositoryFactorySupport.class.getClassLoader());
@@ -72,6 +76,7 @@ public abstract class RepositoryFactorySupport implements BeanClassLoaderAware {
private NamedQueries namedQueries = PropertiesBasedNamedQueries.EMPTY;
private ClassLoader classLoader = org.springframework.util.ClassUtils.getDefaultClassLoader();
private EvaluationContextProvider evaluationContextProvider = DefaultEvaluationContextProvider.INSTANCE;
+ private BeanFactory beanFactory;
private QueryCollectingQueryCreationListener collectingListener = new QueryCollectingQueryCreationListener();
@@ -106,6 +111,15 @@ public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader == null ? org.springframework.util.ClassUtils.getDefaultClassLoader() : classLoader;
}
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.beans.factory.BeanFactoryAware#setBeanFactory(org.springframework.beans.factory.BeanFactory)
+ */
+ @Override
+ public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
+ this.beanFactory = beanFactory;
+ }
+
/**
* Sets the {@link EvaluationContextProvider} to be used to evaluate SpEL expressions in manually defined queries.
*
@@ -307,9 +321,9 @@ private void validate(RepositoryInformation repositoryInformation, Object custom
if (null == customImplementation && repositoryInformation.hasCustomMethod()) {
- throw new IllegalArgumentException(String.format(
- "You have custom methods in %s but not provided a custom implementation!",
- repositoryInformation.getRepositoryInterface()));
+ throw new IllegalArgumentException(
+ String.format("You have custom methods in %s but not provided a custom implementation!",
+ repositoryInformation.getRepositoryInterface()));
}
validate(repositoryInformation);
@@ -412,8 +426,14 @@ public QueryExecutorMethodInterceptor(RepositoryInformation repositoryInformatio
return;
}
+ SpelAwareProxyProjectionFactory factory = new SpelAwareProxyProjectionFactory();
+ factory.setBeanClassLoader(classLoader);
+ factory.setBeanFactory(beanFactory);
+
for (Method method : queryMethods) {
- RepositoryQuery query = lookupStrategy.resolveQuery(method, repositoryInformation, namedQueries);
+
+ RepositoryQuery query = lookupStrategy.resolveQuery(method, repositoryInformation, factory, namedQueries);
+
invokeListeners(query);
queries.put(method, query);
}
diff --git a/src/main/java/org/springframework/data/repository/query/Parameter.java b/src/main/java/org/springframework/data/repository/query/Parameter.java
index 9c9f3df6ea..b90c84f053 100644
--- a/src/main/java/org/springframework/data/repository/query/Parameter.java
+++ b/src/main/java/org/springframework/data/repository/query/Parameter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2013 the original author or authors.
+ * Copyright 2008-2015 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.
@@ -17,12 +17,15 @@
import static java.lang.String.*;
+import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import org.springframework.core.MethodParameter;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
+import org.springframework.data.util.ClassTypeInformation;
+import org.springframework.data.util.TypeInformation;
import org.springframework.util.Assert;
/**
@@ -38,6 +41,7 @@ public class Parameter {
private static final String POSITION_PARAMETER_TEMPLATE = "?%s";
private final MethodParameter parameter;
+ private final boolean isDynamicProjectionParameter;
/**
* Creates a new {@link Parameter} for the given {@link MethodParameter}.
@@ -47,7 +51,9 @@ public class Parameter {
protected Parameter(MethodParameter parameter) {
Assert.notNull(parameter);
+
this.parameter = parameter;
+ this.isDynamicProjectionParameter = isDynamicProjectionParameter(parameter);
}
/**
@@ -57,7 +63,7 @@ protected Parameter(MethodParameter parameter) {
* @see #TYPES
*/
public boolean isSpecialParameter() {
- return TYPES.contains(parameter.getParameterType());
+ return isDynamicProjectionParameter || TYPES.contains(parameter.getParameterType());
}
/**
@@ -69,6 +75,15 @@ public boolean isBindable() {
return !isSpecialParameter();
}
+ /**
+ * Returns whether the current {@link Parameter} is the one used for dynamic projections.
+ *
+ * @return
+ */
+ public boolean isDynamicProjectionParameter() {
+ return isDynamicProjectionParameter;
+ }
+
/**
* Returns the placeholder to be used for the parameter. Can either be a named one or positional.
*
@@ -157,4 +172,31 @@ boolean isPageable() {
boolean isSort() {
return Sort.class.isAssignableFrom(getType());
}
+
+ /**
+ * Returns whether the given {@link MethodParameter} is a dynamic projection parameter, which means it carries a
+ * dynamic type parameter which is identical to the type parameter of the actually returned type.
+ *
+ *
+ * Collection findBy…(…, Class type);
+ *
+ *
+ * @param parameter must not be {@literal null}.
+ * @return
+ */
+ private static boolean isDynamicProjectionParameter(MethodParameter parameter) {
+
+ Method method = parameter.getMethod();
+
+ ClassTypeInformation> ownerType = ClassTypeInformation.from(parameter.getDeclaringClass());
+ TypeInformation> parameterTypes = ownerType.getParameterTypes(method).get(parameter.getParameterIndex());
+ TypeInformation