DATACMNS-1158 - ProjectionFactory is now configurable by module implementations.
Introduced RepositoryFactorySupport.getProjectionFactory(…) to create a ProjectionFactory to be used for repository instances created. The default implementation uses the SpelAwareProxyProjectionFactory. The ProjectionInformation implementation is now a named class so it can be used for more specialized implementations. Original pull request: #243. Related issue: DATAJPA-1173.
This commit is contained in:
committed by
Oliver Gierke
parent
0237760345
commit
300f3cfd66
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 -> {
|
||||
this.queries = lookupStrategy.map( //
|
||||
it -> mapMethodsToQuery(repositoryInformation, projectionFactory, it) //
|
||||
).orElse(Collections.emptyMap());
|
||||
}
|
||||
|
||||
SpelAwareProxyProjectionFactory factory = new SpelAwareProxyProjectionFactory();
|
||||
factory.setBeanClassLoader(classLoader);
|
||||
factory.setBeanFactory(beanFactory);
|
||||
private Map<Method, RepositoryQuery> mapMethodsToQuery(RepositoryInformation repositoryInformation,
|
||||
ProjectionFactory projectionFactory, QueryLookupStrategy lookupStrategy) {
|
||||
|
||||
return repositoryInformation.getQueryMethods().stream()//
|
||||
.map(method -> Pair.of(method, it.resolveQuery(method, repositoryInformation, factory, namedQueries)))//
|
||||
.peek(pair -> invokeListeners(pair.getSecond()))//
|
||||
.collect(Pair.toMap());
|
||||
|
||||
}).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" })
|
||||
|
||||
Reference in New Issue
Block a user