DATACMNS-533 - Infrastructure support for SpEL expressions in manually defined queries.
Extracted SPI build for DATAJPA-564 into Spring Data Commons. Simplified the configuration setup code and removed the ability to define a custom EvaluationContextProvider for now. We directly declare a bean definition which automatically picks up EvaluationContextExtensions. RepositoryFactory(Bean)Support is now aware of the EvaluationContextProvider to hand it to the template method that creates the QueryLookupStrategy. Deprecated the previously existing template method in favor of an extended one. Removed variable declarations from the extension interface for now as usually properties serve the same purposes as variables which makes the latter superfluous for now. Applied some JavaDoc and API signature polish. Added unit tests for ExtensionAwareEvaluationContextProvider. Related pull request: spring-projects/spring-data-jpa#101 Related ticket: DATAJPA-564
This commit is contained in:
@@ -27,12 +27,14 @@ import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
|
||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
import org.springframework.core.type.filter.RegexPatternTypeFilter;
|
||||
import org.springframework.data.repository.query.ExtensionAwareEvaluationContextProvider;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -116,6 +118,12 @@ class RepositoryBeanDefinitionBuilder {
|
||||
builder.addDependsOn(customImplementationBeanName);
|
||||
}
|
||||
|
||||
RootBeanDefinition evaluationContextProviderDefinition = new RootBeanDefinition(
|
||||
ExtensionAwareEvaluationContextProvider.class);
|
||||
evaluationContextProviderDefinition.setSource(configuration.getSource());
|
||||
|
||||
builder.addPropertyValue("evaluationContextProvider", evaluationContextProviderDefinition);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,9 +29,11 @@ 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.query.EvaluationContextProvider;
|
||||
import org.springframework.data.repository.query.QueryLookupStrategy;
|
||||
import org.springframework.data.repository.query.QueryLookupStrategy.Key;
|
||||
import org.springframework.data.repository.query.QueryMethod;
|
||||
import org.springframework.data.repository.query.DefaultEvaluationContextProvider;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -54,6 +56,7 @@ public abstract class RepositoryFactoryBeanSupport<T extends Repository<S, ID>,
|
||||
private MappingContext<?, ?> mappingContext;
|
||||
private ClassLoader classLoader;
|
||||
private boolean lazyInit = false;
|
||||
private EvaluationContextProvider evaluationContextProvider = DefaultEvaluationContextProvider.INSTANCE;
|
||||
|
||||
private T repository;
|
||||
|
||||
@@ -108,6 +111,17 @@ public abstract class RepositoryFactoryBeanSupport<T extends Repository<S, ID>,
|
||||
this.mappingContext = mappingContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link EvaluationContextProvider} to be used to evaluate SpEL expressions in manually defined queries.
|
||||
*
|
||||
* @param evaluationContextProvider can be {@literal null}, defaults to
|
||||
* {@link DefaultEvaluationContextProvider#INSTANCE}.
|
||||
*/
|
||||
public void setEvaluationContextProvider(EvaluationContextProvider evaluationContextProvider) {
|
||||
this.evaluationContextProvider = evaluationContextProvider == null ? DefaultEvaluationContextProvider.INSTANCE
|
||||
: evaluationContextProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures whether to initialize the repository proxy lazily. This defaults to {@literal false}.
|
||||
*
|
||||
@@ -203,6 +217,7 @@ public abstract class RepositoryFactoryBeanSupport<T extends Repository<S, ID>,
|
||||
this.factory.setQueryLookupStrategyKey(queryLookupStrategyKey);
|
||||
this.factory.setNamedQueries(namedQueries);
|
||||
this.factory.setBeanClassLoader(classLoader);
|
||||
this.factory.setEvaluationContextProvider(evaluationContextProvider);
|
||||
|
||||
this.repositoryMetadata = this.factory.getRepositoryMetadata(repositoryInterface);
|
||||
|
||||
|
||||
@@ -42,6 +42,8 @@ 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.query.DefaultEvaluationContextProvider;
|
||||
import org.springframework.data.repository.query.EvaluationContextProvider;
|
||||
import org.springframework.data.repository.query.QueryLookupStrategy;
|
||||
import org.springframework.data.repository.query.QueryLookupStrategy.Key;
|
||||
import org.springframework.data.repository.query.QueryMethod;
|
||||
@@ -72,6 +74,7 @@ public abstract class RepositoryFactorySupport implements BeanClassLoaderAware {
|
||||
private List<QueryCreationListener<?>> queryPostProcessors = new ArrayList<QueryCreationListener<?>>();
|
||||
private NamedQueries namedQueries = PropertiesBasedNamedQueries.EMPTY;
|
||||
private ClassLoader classLoader = org.springframework.util.ClassUtils.getDefaultClassLoader();
|
||||
private EvaluationContextProvider evaluationContextProvider = DefaultEvaluationContextProvider.INSTANCE;
|
||||
|
||||
private QueryCollectingQueryCreationListener collectingListener = new QueryCollectingQueryCreationListener();
|
||||
|
||||
@@ -106,6 +109,17 @@ public abstract class RepositoryFactorySupport implements BeanClassLoaderAware {
|
||||
this.classLoader = classLoader == null ? org.springframework.util.ClassUtils.getDefaultClassLoader() : classLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link EvaluationContextProvider} to be used to evaluate SpEL expressions in manually defined queries.
|
||||
*
|
||||
* @param evaluationContextProvider can be {@literal null}, defaults to
|
||||
* {@link DefaultEvaluationContextProvider#INSTANCE}.
|
||||
*/
|
||||
public void setEvaluationContextProvider(EvaluationContextProvider evaluationContextProvider) {
|
||||
this.evaluationContextProvider = evaluationContextProvider == null ? DefaultEvaluationContextProvider.INSTANCE
|
||||
: evaluationContextProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@link QueryCreationListener} to the factory to plug in functionality triggered right after creation of
|
||||
* {@link RepositoryQuery} instances.
|
||||
@@ -248,6 +262,7 @@ public abstract class RepositoryFactorySupport implements BeanClassLoaderAware {
|
||||
/**
|
||||
* Returns the {@link QueryLookupStrategy} for the given {@link Key}.
|
||||
*
|
||||
* @deprecated favor {@link #getQueryLookupStrategy(Key, EvaluationContextProvider)}
|
||||
* @param key can be {@literal null}
|
||||
* @return the {@link QueryLookupStrategy} to use or {@literal null} if no queries should be looked up.
|
||||
*/
|
||||
@@ -255,6 +270,18 @@ public abstract class RepositoryFactorySupport implements BeanClassLoaderAware {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link QueryLookupStrategy} for the given {@link Key} and {@link EvaluationContextProvider}.
|
||||
*
|
||||
* @param key can be {@literal null}.
|
||||
* @param evaluationContextProvider will never be {@literal null}.
|
||||
* @return the {@link QueryLookupStrategy} to use or {@literal null} if no queries should be looked up.
|
||||
* @since 1.9
|
||||
*/
|
||||
protected QueryLookupStrategy getQueryLookupStrategy(Key key, EvaluationContextProvider evaluationContextProvider) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the given repository interface as well as the given custom implementation.
|
||||
*
|
||||
@@ -311,7 +338,9 @@ public abstract class RepositoryFactorySupport implements BeanClassLoaderAware {
|
||||
this.customImplementation = customImplementation;
|
||||
this.target = target;
|
||||
|
||||
QueryLookupStrategy lookupStrategy = getQueryLookupStrategy(queryLookupStrategyKey);
|
||||
QueryLookupStrategy lookupStrategy = getQueryLookupStrategy(queryLookupStrategyKey,
|
||||
RepositoryFactorySupport.this.evaluationContextProvider);
|
||||
lookupStrategy = lookupStrategy == null ? getQueryLookupStrategy(queryLookupStrategyKey) : lookupStrategy;
|
||||
Iterable<Method> queryMethods = repositoryInformation.getQueryMethods();
|
||||
|
||||
if (lookupStrategy == null) {
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2014 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
|
||||
*
|
||||
* http://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.repository.query;
|
||||
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link EvaluationContextProvider} that always creates a new {@link EvaluationContext}.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @since 1.9
|
||||
*/
|
||||
public enum DefaultEvaluationContextProvider implements EvaluationContextProvider {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.EvaluationContextProvider#getEvaluationContext(org.springframework.data.repository.query.Parameters, java.lang.Object[])
|
||||
*/
|
||||
@Override
|
||||
public <T extends Parameters<T, ? extends Parameter>> EvaluationContext getEvaluationContext(T parameters,
|
||||
Object[] parameterValues) {
|
||||
return new StandardEvaluationContext();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2014 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
|
||||
*
|
||||
* http://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.repository.query;
|
||||
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
|
||||
/**
|
||||
* Provides a way to access a centrally defined potentially shared {@link StandardEvaluationContext}.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @since 1.9
|
||||
*/
|
||||
public interface EvaluationContextProvider {
|
||||
|
||||
/**
|
||||
* Returns an {@link EvaluationContext} built using the given {@link Parameters} and parameter values.
|
||||
*
|
||||
* @param parameters the {@link Parameters} instance obtained from the query method the context is built for.
|
||||
* @param parameterValues the values for the parameters.
|
||||
* @return
|
||||
*/
|
||||
<T extends Parameters<T, ? extends Parameter>> EvaluationContext getEvaluationContext(T parameters,
|
||||
Object[] parameterValues);
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
* Copyright 2014 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
|
||||
*
|
||||
* http://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.repository.query;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.expression.BeanFactoryResolver;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.data.repository.query.spi.EvaluationContextExtension;
|
||||
import org.springframework.expression.AccessException;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.MethodExecutor;
|
||||
import org.springframework.expression.MethodResolver;
|
||||
import org.springframework.expression.PropertyAccessor;
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.expression.spel.SpelEvaluationException;
|
||||
import org.springframework.expression.spel.SpelMessage;
|
||||
import org.springframework.expression.spel.support.ReflectivePropertyAccessor;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.TypeUtils;
|
||||
|
||||
/**
|
||||
* An {@link EvaluationContextProvider} that assembles an {@link EvaluationContext} from a list of
|
||||
* {@link EvaluationContextExtension} instances.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @since 1.9
|
||||
*/
|
||||
public class ExtensionAwareEvaluationContextProvider implements EvaluationContextProvider, ApplicationContextAware {
|
||||
|
||||
private List<EvaluationContextExtension> extensions;
|
||||
private ListableBeanFactory beanFactory;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ExtensionAwareEvaluationContextProvider}. Extensions are being looked up lazily from the
|
||||
* {@link BeanFactory} configured.
|
||||
*/
|
||||
public ExtensionAwareEvaluationContextProvider() {}
|
||||
|
||||
/**
|
||||
* Creates a new {@link ExtensionAwareEvaluationContextProvider} for the given {@link EvaluationContextExtension}s.
|
||||
*
|
||||
* @param extensions must not be {@literal null}.
|
||||
*/
|
||||
public ExtensionAwareEvaluationContextProvider(List<? extends EvaluationContextExtension> extensions) {
|
||||
|
||||
Assert.notNull(extensions, "List of EvaluationContextExtensions must not be null!");
|
||||
|
||||
List<EvaluationContextExtension> extensionsToSet = new ArrayList<EvaluationContextExtension>(extensions);
|
||||
Collections.sort(extensionsToSet, AnnotationAwareOrderComparator.INSTANCE);
|
||||
|
||||
this.extensions = Collections.unmodifiableList(extensionsToSet);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
|
||||
*/
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.beanFactory = applicationContext;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.jpa.repository.support.EvaluationContextProvider#getEvaluationContext()
|
||||
*/
|
||||
@Override
|
||||
public <T extends Parameters<T, ? extends Parameter>> StandardEvaluationContext getEvaluationContext(T parameters,
|
||||
Object[] parameterValues) {
|
||||
|
||||
StandardEvaluationContext ec = new StandardEvaluationContext();
|
||||
|
||||
if (beanFactory != null) {
|
||||
ec.setBeanResolver(new BeanFactoryResolver(beanFactory));
|
||||
}
|
||||
|
||||
ExtensionAwarePropertyAccessor accessor = new ExtensionAwarePropertyAccessor(getExtensions());
|
||||
|
||||
ec.addPropertyAccessor(accessor);
|
||||
ec.addPropertyAccessor(new ReflectivePropertyAccessor());
|
||||
ec.addMethodResolver(accessor);
|
||||
|
||||
// Add parameters for indexed access
|
||||
ec.setRootObject(parameterValues);
|
||||
|
||||
// Add parameters as variables if named
|
||||
for (Parameter param : parameters) {
|
||||
if (param.isNamedParameter()) {
|
||||
ec.setVariable(param.getName(), parameterValues[param.getIndex()]);
|
||||
}
|
||||
}
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link EvaluationContextExtension} to be used. Either from the current configuration or the configured
|
||||
* {@link BeanFactory}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private List<EvaluationContextExtension> getExtensions() {
|
||||
|
||||
if (this.extensions != null) {
|
||||
return this.extensions;
|
||||
}
|
||||
|
||||
if (beanFactory == null) {
|
||||
this.extensions = Collections.emptyList();
|
||||
return this.extensions;
|
||||
}
|
||||
|
||||
List<EvaluationContextExtension> extensions = new ArrayList<EvaluationContextExtension>(beanFactory.getBeansOfType(
|
||||
EvaluationContextExtension.class, true, false).values());
|
||||
Collections.sort(extensions, AnnotationAwareOrderComparator.INSTANCE);
|
||||
this.extensions = extensions;
|
||||
|
||||
return extensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @see 1.9
|
||||
*/
|
||||
private static class ExtensionAwarePropertyAccessor implements PropertyAccessor, MethodResolver {
|
||||
|
||||
private final Map<String, EvaluationContextExtension> extensionMap;
|
||||
private final List<EvaluationContextExtension> extensions;
|
||||
private final Map<String, Object> functions;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ExtensionAwarePropertyAccessor} for the given {@link EvaluationContextExtension}s.
|
||||
*
|
||||
* @param extensions must not be {@literal null}.
|
||||
*/
|
||||
public ExtensionAwarePropertyAccessor(List<? extends EvaluationContextExtension> extensions) {
|
||||
|
||||
Assert.notNull(extensions, "Extensions must not be null!");
|
||||
|
||||
Map<String, Object> functions = new HashMap<String, Object>();
|
||||
|
||||
for (EvaluationContextExtension ext : extensions) {
|
||||
|
||||
if (ext.getExtensionId() != null) {
|
||||
functions.put(ext.getExtensionId(), ext.getFunctions());
|
||||
}
|
||||
|
||||
functions.putAll(ext.getFunctions());
|
||||
}
|
||||
|
||||
this.functions = functions;
|
||||
|
||||
this.extensions = new ArrayList<EvaluationContextExtension>(extensions);
|
||||
Collections.reverse(this.extensions);
|
||||
|
||||
this.extensionMap = new HashMap<String, EvaluationContextExtension>(extensions.size());
|
||||
|
||||
for (EvaluationContextExtension extension : extensions) {
|
||||
this.extensionMap.put(extension.getExtensionId(), extension);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.ExtensionAwareEvaluationContextProvider.ReadOnlyPropertyAccessor#canRead(org.springframework.expression.EvaluationContext, java.lang.Object, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
|
||||
if (target instanceof EvaluationContextExtension) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (extensionMap.containsKey(name)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (EvaluationContextExtension extension : extensions) {
|
||||
if (extension.getProperties().containsKey(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.expression.PropertyAccessor#read(org.springframework.expression.EvaluationContext, java.lang.Object, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
|
||||
if (target instanceof EvaluationContextExtension) {
|
||||
return new TypedValue(((EvaluationContextExtension) target).getProperties().get(name));
|
||||
}
|
||||
|
||||
if (extensionMap.containsKey(name)) {
|
||||
return new TypedValue(extensionMap.get(name));
|
||||
}
|
||||
|
||||
for (EvaluationContextExtension extension : extensions) {
|
||||
|
||||
Map<String, Object> properties = extension.getProperties();
|
||||
|
||||
if (properties.containsKey(name)) {
|
||||
return new TypedValue(properties.get(name));
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.expression.MethodResolver#resolve(org.springframework.expression.EvaluationContext, java.lang.Object, java.lang.String, java.util.List)
|
||||
*/
|
||||
@Override
|
||||
public MethodExecutor resolve(EvaluationContext context, Object targetObject, String name,
|
||||
List<TypeDescriptor> argumentTypes) throws AccessException {
|
||||
|
||||
final Method function = targetObject instanceof Map && ((Map<?, ?>) targetObject).containsKey(name) ? (Method) ((Map<?, ?>) targetObject)
|
||||
.get(name) : (Method) functions.get(name);
|
||||
|
||||
Class<?>[] parameterTypes = function.getParameterTypes();
|
||||
if (parameterTypes.length != argumentTypes.size()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (int i = 0; i < parameterTypes.length; i++) {
|
||||
if (!TypeUtils.isAssignable(parameterTypes[i], argumentTypes.get(i).getType())) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return new MethodExecutor() {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.expression.MethodExecutor#execute(org.springframework.expression.EvaluationContext, java.lang.Object, java.lang.Object[])
|
||||
*/
|
||||
@Override
|
||||
public TypedValue execute(EvaluationContext context, Object target, Object... arguments) throws AccessException {
|
||||
|
||||
try {
|
||||
return new TypedValue(function.invoke(null, arguments));
|
||||
} catch (Exception e) {
|
||||
throw new SpelEvaluationException(e, SpelMessage.FUNCTION_REFERENCE_CANNOT_BE_INVOKED, function.getName(),
|
||||
function.getDeclaringClass());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.expression.PropertyAccessor#canWrite(org.springframework.expression.EvaluationContext, java.lang.Object, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.expression.PropertyAccessor#write(org.springframework.expression.EvaluationContext, java.lang.Object, java.lang.String, java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException {
|
||||
// noop
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.expression.PropertyAccessor#getSpecificTargetClasses()
|
||||
*/
|
||||
@Override
|
||||
public Class<?>[] getSpecificTargetClasses() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2014 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
|
||||
*
|
||||
* http://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.repository.query.spi;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.data.repository.query.ExtensionAwareEvaluationContextProvider;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
|
||||
/**
|
||||
* SPI to allow adding a set of properties and function definitions accessible via the root of an
|
||||
* {@link EvaluationContext} provided by a {@link ExtensionAwareEvaluationContextProvider}.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @since 1.9
|
||||
*/
|
||||
public interface EvaluationContextExtension {
|
||||
|
||||
/**
|
||||
* Returns the identifier of the extension. The id can be leveraged by users to fully qualify property lookups and
|
||||
* thus overcome ambiguities in case multiple extensions expose properties with the same name.
|
||||
*
|
||||
* @return the extension id, must not be {@literal null}.
|
||||
*/
|
||||
String getExtensionId();
|
||||
|
||||
/**
|
||||
* Returns the properties exposed by the extension.
|
||||
*
|
||||
* @return the properties
|
||||
*/
|
||||
Map<String, Object> getProperties();
|
||||
|
||||
/**
|
||||
* Returns the functions exposed by the extension.
|
||||
*
|
||||
* @return the functions
|
||||
*/
|
||||
Map<String, Method> getFunctions();
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2014 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
|
||||
*
|
||||
* http://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.repository.query.spi;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A base class for {@link EvaluationContextExtension}s.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @see 1.9
|
||||
*/
|
||||
public abstract class EvaluationContextExtensionSupport implements EvaluationContextExtension {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.EvaluationContextExtension#getProperties()
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> getProperties() {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.EvaluationContextExtension#getFunctions()
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Method> getFunctions() {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* Service provider interfaces to extend the query execution mechanism.
|
||||
*/
|
||||
package org.springframework.data.repository.query.spi;
|
||||
|
||||
Reference in New Issue
Block a user