spring SimpleEvaluationContext 源码
spring SimpleEvaluationContext 代码
文件路径:/spring-expression/src/main/java/org/springframework/expression/spel/support/SimpleEvaluationContext.java
/*
* Copyright 2002-2018 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.expression.spel.support;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.BeanResolver;
import org.springframework.expression.ConstructorResolver;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.MethodResolver;
import org.springframework.expression.OperatorOverloader;
import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.TypeComparator;
import org.springframework.expression.TypeConverter;
import org.springframework.expression.TypeLocator;
import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.lang.Nullable;
/**
* A basic implementation of {@link EvaluationContext} that focuses on a subset
* of essential SpEL features and customization options, targeting simple
* condition evaluation and in particular data binding scenarios.
*
* <p>In many cases, the full extent of the SpEL language is not required and
* should be meaningfully restricted. Examples include but are not limited to
* data binding expressions, property-based filters, and others. To that effect,
* {@code SimpleEvaluationContext} is tailored to support only a subset of the
* SpEL language syntax, e.g. excluding references to Java types, constructors,
* and bean references.
*
* <p>When creating a {@code SimpleEvaluationContext} you need to choose the
* level of support that you need for property access in SpEL expressions:
* <ul>
* <li>A custom {@code PropertyAccessor} (typically not reflection-based),
* potentially combined with a {@link DataBindingPropertyAccessor}</li>
* <li>Data binding properties for read-only access</li>
* <li>Data binding properties for read and write</li>
* </ul>
*
* <p>Conveniently, {@link SimpleEvaluationContext#forReadOnlyDataBinding()}
* enables read access to properties via {@link DataBindingPropertyAccessor};
* same for {@link SimpleEvaluationContext#forReadWriteDataBinding()} when
* write access is needed as well. Alternatively, configure custom accessors
* via {@link SimpleEvaluationContext#forPropertyAccessors}, and potentially
* activate method resolution and/or a type converter through the builder.
*
* <p>Note that {@code SimpleEvaluationContext} is typically not configured
* with a default root object. Instead it is meant to be created once and
* used repeatedly through {@code getValue} calls on a pre-compiled
* {@link org.springframework.expression.Expression} with both an
* {@code EvaluationContext} and a root object as arguments:
* {@link org.springframework.expression.Expression#getValue(EvaluationContext, Object)}.
*
* <p>For more power and flexibility, in particular for internal configuration
* scenarios, consider using {@link StandardEvaluationContext} instead.
*
* @author Rossen Stoyanchev
* @author Juergen Hoeller
* @since 4.3.15
* @see #forPropertyAccessors
* @see #forReadOnlyDataBinding()
* @see #forReadWriteDataBinding()
* @see StandardEvaluationContext
* @see StandardTypeConverter
* @see DataBindingPropertyAccessor
*/
public final class SimpleEvaluationContext implements EvaluationContext {
private static final TypeLocator typeNotFoundTypeLocator = typeName -> {
throw new SpelEvaluationException(SpelMessage.TYPE_NOT_FOUND, typeName);
};
private final TypedValue rootObject;
private final List<PropertyAccessor> propertyAccessors;
private final List<MethodResolver> methodResolvers;
private final TypeConverter typeConverter;
private final TypeComparator typeComparator = new StandardTypeComparator();
private final OperatorOverloader operatorOverloader = new StandardOperatorOverloader();
private final Map<String, Object> variables = new HashMap<>();
private SimpleEvaluationContext(List<PropertyAccessor> accessors, List<MethodResolver> resolvers,
@Nullable TypeConverter converter, @Nullable TypedValue rootObject) {
this.propertyAccessors = accessors;
this.methodResolvers = resolvers;
this.typeConverter = (converter != null ? converter : new StandardTypeConverter());
this.rootObject = (rootObject != null ? rootObject : TypedValue.NULL);
}
/**
* Return the specified root object, if any.
*/
@Override
public TypedValue getRootObject() {
return this.rootObject;
}
/**
* Return the specified {@link PropertyAccessor} delegates, if any.
* @see #forPropertyAccessors
*/
@Override
public List<PropertyAccessor> getPropertyAccessors() {
return this.propertyAccessors;
}
/**
* Return an empty list, always, since this context does not support the
* use of type references.
*/
@Override
public List<ConstructorResolver> getConstructorResolvers() {
return Collections.emptyList();
}
/**
* Return the specified {@link MethodResolver} delegates, if any.
* @see Builder#withMethodResolvers
*/
@Override
public List<MethodResolver> getMethodResolvers() {
return this.methodResolvers;
}
/**
* {@code SimpleEvaluationContext} does not support the use of bean references.
* @return always {@code null}
*/
@Override
@Nullable
public BeanResolver getBeanResolver() {
return null;
}
/**
* {@code SimpleEvaluationContext} does not support use of type references.
* @return {@code TypeLocator} implementation that raises a
* {@link SpelEvaluationException} with {@link SpelMessage#TYPE_NOT_FOUND}.
*/
@Override
public TypeLocator getTypeLocator() {
return typeNotFoundTypeLocator;
}
/**
* The configured {@link TypeConverter}.
* <p>By default this is {@link StandardTypeConverter}.
* @see Builder#withTypeConverter
* @see Builder#withConversionService
*/
@Override
public TypeConverter getTypeConverter() {
return this.typeConverter;
}
/**
* Return an instance of {@link StandardTypeComparator}.
*/
@Override
public TypeComparator getTypeComparator() {
return this.typeComparator;
}
/**
* Return an instance of {@link StandardOperatorOverloader}.
*/
@Override
public OperatorOverloader getOperatorOverloader() {
return this.operatorOverloader;
}
@Override
public void setVariable(String name, @Nullable Object value) {
this.variables.put(name, value);
}
@Override
@Nullable
public Object lookupVariable(String name) {
return this.variables.get(name);
}
/**
* Create a {@code SimpleEvaluationContext} for the specified {@link PropertyAccessor}
* delegates: typically a custom {@code PropertyAccessor} specific to a use case
* (e.g. attribute resolution in a custom data structure), potentially combined with
* a {@link DataBindingPropertyAccessor} if property dereferences are needed as well.
* @param accessors the accessor delegates to use
* @see DataBindingPropertyAccessor#forReadOnlyAccess()
* @see DataBindingPropertyAccessor#forReadWriteAccess()
*/
public static Builder forPropertyAccessors(PropertyAccessor... accessors) {
for (PropertyAccessor accessor : accessors) {
if (accessor.getClass() == ReflectivePropertyAccessor.class) {
throw new IllegalArgumentException("SimpleEvaluationContext is not designed for use with a plain " +
"ReflectivePropertyAccessor. Consider using DataBindingPropertyAccessor or a custom subclass.");
}
}
return new Builder(accessors);
}
/**
* Create a {@code SimpleEvaluationContext} for read-only access to
* public properties via {@link DataBindingPropertyAccessor}.
* @see DataBindingPropertyAccessor#forReadOnlyAccess()
* @see #forPropertyAccessors
*/
public static Builder forReadOnlyDataBinding() {
return new Builder(DataBindingPropertyAccessor.forReadOnlyAccess());
}
/**
* Create a {@code SimpleEvaluationContext} for read-write access to
* public properties via {@link DataBindingPropertyAccessor}.
* @see DataBindingPropertyAccessor#forReadWriteAccess()
* @see #forPropertyAccessors
*/
public static Builder forReadWriteDataBinding() {
return new Builder(DataBindingPropertyAccessor.forReadWriteAccess());
}
/**
* Builder for {@code SimpleEvaluationContext}.
*/
public static class Builder {
private final List<PropertyAccessor> accessors;
private List<MethodResolver> resolvers = Collections.emptyList();
@Nullable
private TypeConverter typeConverter;
@Nullable
private TypedValue rootObject;
public Builder(PropertyAccessor... accessors) {
this.accessors = Arrays.asList(accessors);
}
/**
* Register the specified {@link MethodResolver} delegates for
* a combination of property access and method resolution.
* @param resolvers the resolver delegates to use
* @see #withInstanceMethods()
* @see SimpleEvaluationContext#forPropertyAccessors
*/
public Builder withMethodResolvers(MethodResolver... resolvers) {
for (MethodResolver resolver : resolvers) {
if (resolver.getClass() == ReflectiveMethodResolver.class) {
throw new IllegalArgumentException("SimpleEvaluationContext is not designed for use with a plain " +
"ReflectiveMethodResolver. Consider using DataBindingMethodResolver or a custom subclass.");
}
}
this.resolvers = Arrays.asList(resolvers);
return this;
}
/**
* Register a {@link DataBindingMethodResolver} for instance method invocation purposes
* (i.e. not supporting static methods) in addition to the specified property accessors,
* typically in combination with a {@link DataBindingPropertyAccessor}.
* @see #withMethodResolvers
* @see SimpleEvaluationContext#forReadOnlyDataBinding()
* @see SimpleEvaluationContext#forReadWriteDataBinding()
*/
public Builder withInstanceMethods() {
this.resolvers = Collections.singletonList(DataBindingMethodResolver.forInstanceMethodInvocation());
return this;
}
/**
* Register a custom {@link ConversionService}.
* <p>By default a {@link StandardTypeConverter} backed by a
* {@link org.springframework.core.convert.support.DefaultConversionService} is used.
* @see #withTypeConverter
* @see StandardTypeConverter#StandardTypeConverter(ConversionService)
*/
public Builder withConversionService(ConversionService conversionService) {
this.typeConverter = new StandardTypeConverter(conversionService);
return this;
}
/**
* Register a custom {@link TypeConverter}.
* <p>By default a {@link StandardTypeConverter} backed by a
* {@link org.springframework.core.convert.support.DefaultConversionService} is used.
* @see #withConversionService
* @see StandardTypeConverter#StandardTypeConverter()
*/
public Builder withTypeConverter(TypeConverter converter) {
this.typeConverter = converter;
return this;
}
/**
* Specify a default root object to resolve against.
* <p>Default is none, expecting an object argument at evaluation time.
* @see org.springframework.expression.Expression#getValue(EvaluationContext)
* @see org.springframework.expression.Expression#getValue(EvaluationContext, Object)
*/
public Builder withRootObject(Object rootObject) {
this.rootObject = new TypedValue(rootObject);
return this;
}
/**
* Specify a typed root object to resolve against.
* <p>Default is none, expecting an object argument at evaluation time.
* @see org.springframework.expression.Expression#getValue(EvaluationContext)
* @see org.springframework.expression.Expression#getValue(EvaluationContext, Object)
*/
public Builder withTypedRootObject(Object rootObject, TypeDescriptor typeDescriptor) {
this.rootObject = new TypedValue(rootObject, typeDescriptor);
return this;
}
public SimpleEvaluationContext build() {
return new SimpleEvaluationContext(this.accessors, this.resolvers, this.typeConverter, this.rootObject);
}
}
}
相关信息
相关文章
spring DataBindingMethodResolver 源码
spring DataBindingPropertyAccessor 源码
spring ReflectiveConstructorExecutor 源码
spring ReflectiveConstructorResolver 源码
spring ReflectiveMethodExecutor 源码
spring ReflectiveMethodResolver 源码
0
赞
热门推荐
-
2、 - 优质文章
-
3、 gate.io
-
8、 golang
-
9、 openharmony
-
10、 Vue中input框自动聚焦