001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.expression.spel.support; 018 019import java.lang.reflect.Method; 020import java.util.ArrayList; 021import java.util.HashMap; 022import java.util.List; 023import java.util.Map; 024 025import org.springframework.core.convert.TypeDescriptor; 026import org.springframework.expression.BeanResolver; 027import org.springframework.expression.ConstructorResolver; 028import org.springframework.expression.EvaluationContext; 029import org.springframework.expression.MethodFilter; 030import org.springframework.expression.MethodResolver; 031import org.springframework.expression.OperatorOverloader; 032import org.springframework.expression.PropertyAccessor; 033import org.springframework.expression.TypeComparator; 034import org.springframework.expression.TypeConverter; 035import org.springframework.expression.TypeLocator; 036import org.springframework.expression.TypedValue; 037import org.springframework.util.Assert; 038 039/** 040 * A powerful and highly configurable {@link EvaluationContext} implementation. 041 * This context uses standard implementations of all applicable strategies, 042 * based on reflection to resolve properties, methods and fields. 043 * 044 * <p>For a simpler builder-style context variant for data-binding purposes, 045 * consider using {@link SimpleEvaluationContext} instead which allows for 046 * opting into several SpEL features as needed by specific evaluation cases. 047 * 048 * @author Andy Clement 049 * @author Juergen Hoeller 050 * @author Sam Brannen 051 * @since 3.0 052 */ 053public class StandardEvaluationContext implements EvaluationContext { 054 055 private TypedValue rootObject; 056 057 private List<ConstructorResolver> constructorResolvers; 058 059 private List<MethodResolver> methodResolvers; 060 061 private BeanResolver beanResolver; 062 063 private ReflectiveMethodResolver reflectiveMethodResolver; 064 065 private List<PropertyAccessor> propertyAccessors; 066 067 private TypeLocator typeLocator; 068 069 private TypeConverter typeConverter; 070 071 private TypeComparator typeComparator = new StandardTypeComparator(); 072 073 private OperatorOverloader operatorOverloader = new StandardOperatorOverloader(); 074 075 private final Map<String, Object> variables = new HashMap<String, Object>(); 076 077 078 /** 079 * Create a {@code StandardEvaluationContext} with a null root object. 080 */ 081 public StandardEvaluationContext() { 082 setRootObject(null); 083 } 084 085 /** 086 * Create a {@code StandardEvaluationContext} with the given root object. 087 * @param rootObject the root object to use 088 * @see #setRootObject 089 */ 090 public StandardEvaluationContext(Object rootObject) { 091 setRootObject(rootObject); 092 } 093 094 095 public void setRootObject(Object rootObject, TypeDescriptor typeDescriptor) { 096 this.rootObject = new TypedValue(rootObject, typeDescriptor); 097 } 098 099 public void setRootObject(Object rootObject) { 100 this.rootObject = (rootObject != null ? new TypedValue(rootObject) : TypedValue.NULL); 101 } 102 103 @Override 104 public TypedValue getRootObject() { 105 return this.rootObject; 106 } 107 108 public void setPropertyAccessors(List<PropertyAccessor> propertyAccessors) { 109 this.propertyAccessors = propertyAccessors; 110 } 111 112 @Override 113 public List<PropertyAccessor> getPropertyAccessors() { 114 ensurePropertyAccessorsInitialized(); 115 return this.propertyAccessors; 116 } 117 118 public void addPropertyAccessor(PropertyAccessor accessor) { 119 ensurePropertyAccessorsInitialized(); 120 this.propertyAccessors.add(this.propertyAccessors.size() - 1, accessor); 121 } 122 123 public boolean removePropertyAccessor(PropertyAccessor accessor) { 124 return this.propertyAccessors.remove(accessor); 125 } 126 127 public void setConstructorResolvers(List<ConstructorResolver> constructorResolvers) { 128 this.constructorResolvers = constructorResolvers; 129 } 130 131 @Override 132 public List<ConstructorResolver> getConstructorResolvers() { 133 ensureConstructorResolversInitialized(); 134 return this.constructorResolvers; 135 } 136 137 public void addConstructorResolver(ConstructorResolver resolver) { 138 ensureConstructorResolversInitialized(); 139 this.constructorResolvers.add(this.constructorResolvers.size() - 1, resolver); 140 } 141 142 public boolean removeConstructorResolver(ConstructorResolver resolver) { 143 ensureConstructorResolversInitialized(); 144 return this.constructorResolvers.remove(resolver); 145 } 146 147 public void setMethodResolvers(List<MethodResolver> methodResolvers) { 148 this.methodResolvers = methodResolvers; 149 } 150 151 @Override 152 public List<MethodResolver> getMethodResolvers() { 153 ensureMethodResolversInitialized(); 154 return this.methodResolvers; 155 } 156 157 public void addMethodResolver(MethodResolver resolver) { 158 ensureMethodResolversInitialized(); 159 this.methodResolvers.add(this.methodResolvers.size() - 1, resolver); 160 } 161 162 public boolean removeMethodResolver(MethodResolver methodResolver) { 163 ensureMethodResolversInitialized(); 164 return this.methodResolvers.remove(methodResolver); 165 } 166 167 public void setBeanResolver(BeanResolver beanResolver) { 168 this.beanResolver = beanResolver; 169 } 170 171 @Override 172 public BeanResolver getBeanResolver() { 173 return this.beanResolver; 174 } 175 176 public void setTypeLocator(TypeLocator typeLocator) { 177 Assert.notNull(typeLocator, "TypeLocator must not be null"); 178 this.typeLocator = typeLocator; 179 } 180 181 @Override 182 public TypeLocator getTypeLocator() { 183 if (this.typeLocator == null) { 184 this.typeLocator = new StandardTypeLocator(); 185 } 186 return this.typeLocator; 187 } 188 189 public void setTypeConverter(TypeConverter typeConverter) { 190 Assert.notNull(typeConverter, "TypeConverter must not be null"); 191 this.typeConverter = typeConverter; 192 } 193 194 @Override 195 public TypeConverter getTypeConverter() { 196 if (this.typeConverter == null) { 197 this.typeConverter = new StandardTypeConverter(); 198 } 199 return this.typeConverter; 200 } 201 202 public void setTypeComparator(TypeComparator typeComparator) { 203 Assert.notNull(typeComparator, "TypeComparator must not be null"); 204 this.typeComparator = typeComparator; 205 } 206 207 @Override 208 public TypeComparator getTypeComparator() { 209 return this.typeComparator; 210 } 211 212 public void setOperatorOverloader(OperatorOverloader operatorOverloader) { 213 Assert.notNull(operatorOverloader, "OperatorOverloader must not be null"); 214 this.operatorOverloader = operatorOverloader; 215 } 216 217 @Override 218 public OperatorOverloader getOperatorOverloader() { 219 return this.operatorOverloader; 220 } 221 222 @Override 223 public void setVariable(String name, Object value) { 224 this.variables.put(name, value); 225 } 226 227 public void setVariables(Map<String, Object> variables) { 228 this.variables.putAll(variables); 229 } 230 231 public void registerFunction(String name, Method method) { 232 this.variables.put(name, method); 233 } 234 235 @Override 236 public Object lookupVariable(String name) { 237 return this.variables.get(name); 238 } 239 240 /** 241 * Register a {@code MethodFilter} which will be called during method resolution 242 * for the specified type. 243 * <p>The {@code MethodFilter} may remove methods and/or sort the methods which 244 * will then be used by SpEL as the candidates to look through for a match. 245 * @param type the type for which the filter should be called 246 * @param filter a {@code MethodFilter}, or {@code null} to unregister a filter for the type 247 * @throws IllegalStateException if the {@link ReflectiveMethodResolver} is not in use 248 */ 249 public void registerMethodFilter(Class<?> type, MethodFilter filter) throws IllegalStateException { 250 ensureMethodResolversInitialized(); 251 if (this.reflectiveMethodResolver != null) { 252 this.reflectiveMethodResolver.registerMethodFilter(type, filter); 253 } 254 else { 255 throw new IllegalStateException("Method filter cannot be set as the reflective method resolver is not in use"); 256 } 257 } 258 259 260 private void ensurePropertyAccessorsInitialized() { 261 if (this.propertyAccessors == null) { 262 initializePropertyAccessors(); 263 } 264 } 265 266 private synchronized void initializePropertyAccessors() { 267 if (this.propertyAccessors == null) { 268 List<PropertyAccessor> defaultAccessors = new ArrayList<PropertyAccessor>(); 269 defaultAccessors.add(new ReflectivePropertyAccessor()); 270 this.propertyAccessors = defaultAccessors; 271 } 272 } 273 274 private void ensureConstructorResolversInitialized() { 275 if (this.constructorResolvers == null) { 276 initializeConstructorResolvers(); 277 } 278 } 279 280 private synchronized void initializeConstructorResolvers() { 281 if (this.constructorResolvers == null) { 282 List<ConstructorResolver> defaultResolvers = new ArrayList<ConstructorResolver>(); 283 defaultResolvers.add(new ReflectiveConstructorResolver()); 284 this.constructorResolvers = defaultResolvers; 285 } 286 } 287 288 private void ensureMethodResolversInitialized() { 289 if (this.methodResolvers == null) { 290 initializeMethodResolvers(); 291 } 292 } 293 294 private synchronized void initializeMethodResolvers() { 295 if (this.methodResolvers == null) { 296 List<MethodResolver> defaultResolvers = new ArrayList<MethodResolver>(); 297 this.reflectiveMethodResolver = new ReflectiveMethodResolver(); 298 defaultResolvers.add(this.reflectiveMethodResolver); 299 this.methodResolvers = defaultResolvers; 300 } 301 } 302 303}