提交 29303ef5 编写于 作者: A Andy Clement

Allow MapAccessor to be compilable in SpEL expressions

With this change the MapAccessor now extends CompilablePropertyAccessor
rather than just PropertyAccessor. This means that any expression that
ends up using the MapAccessor is now compilable for fast performance.

Issue: SPR-13638
上级 610b5a20
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-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.
......@@ -18,10 +18,12 @@ package org.springframework.context.expression;
import java.util.Map;
import org.springframework.asm.MethodVisitor;
import org.springframework.expression.AccessException;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.CodeFlow;
import org.springframework.expression.spel.CompilablePropertyAccessor;
/**
* EL property accessor that knows how to traverse the keys
......@@ -31,7 +33,7 @@ import org.springframework.expression.TypedValue;
* @author Andy Clement
* @since 3.0
*/
public class MapAccessor implements PropertyAccessor {
public class MapAccessor implements CompilablePropertyAccessor {
@Override
public Class<?>[] getSpecificTargetClasses() {
......@@ -87,4 +89,27 @@ public class MapAccessor implements PropertyAccessor {
}
}
@Override
public boolean isCompilable() {
return true;
}
@Override
public Class<?> getPropertyType() {
return Object.class;
}
@Override
public void generateCode(String propertyName, MethodVisitor mv, CodeFlow cf) {
String descriptor = cf.lastDescriptor();
if (descriptor == null || !descriptor.equals("Ljava/util/Map")) {
if (descriptor == null) {
cf.loadTarget(mv);
}
CodeFlow.insertCheckCast(mv, "Ljava/util/Map");
}
mv.visitLdcInsn(propertyName);
mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Map", "get","(Ljava/lang/Object;)Ljava/lang/Object;",true);
}
}
/*
* Copyright 2002-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.
* 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.context.expression;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelCompiler;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import static org.junit.Assert.*;
/**
* Unit tests for compilation of {@link MapAccessor}.
*
* @author Andy Clement
*/
public class MapAccessorTests {
@Test
public void mapAccessorCompilable() {
Map<String, Object> testMap = getSimpleTestMap();
StandardEvaluationContext sec = new StandardEvaluationContext();
sec.addPropertyAccessor(new MapAccessor());
SpelExpressionParser sep = new SpelExpressionParser();
// basic
Expression ex = sep.parseExpression("foo");
assertEquals("bar",ex.getValue(sec,testMap));
assertTrue(SpelCompiler.compile(ex));
assertEquals("bar",ex.getValue(sec,testMap));
// compound expression
ex = sep.parseExpression("foo.toUpperCase()");
assertEquals("BAR",ex.getValue(sec,testMap));
assertTrue(SpelCompiler.compile(ex));
assertEquals("BAR",ex.getValue(sec,testMap));
// nested map
Map<String,Map<String,Object>> nestedMap = getNestedTestMap();
ex = sep.parseExpression("aaa.foo.toUpperCase()");
assertEquals("BAR",ex.getValue(sec,nestedMap));
assertTrue(SpelCompiler.compile(ex));
assertEquals("BAR",ex.getValue(sec,nestedMap));
// avoiding inserting checkcast because first part of expression returns a Map
ex = sep.parseExpression("getMap().foo");
MapGetter mapGetter = new MapGetter();
assertEquals("bar",ex.getValue(sec,mapGetter));
assertTrue(SpelCompiler.compile(ex));
assertEquals("bar",ex.getValue(sec,mapGetter));
}
public static class MapGetter {
Map<String,Object> map = new HashMap<String,Object>();
public MapGetter() {
map.put("foo", "bar");
}
@SuppressWarnings("rawtypes")
public Map getMap() {
return map;
}
}
public Map<String,Object> getSimpleTestMap() {
Map<String,Object> map = new HashMap<String,Object>();
map.put("foo","bar");
return map;
}
public Map<String,Map<String,Object>> getNestedTestMap() {
Map<String,Object> map = new HashMap<String,Object>();
map.put("foo","bar");
Map<String,Map<String,Object>> map2 = new HashMap<String,Map<String,Object>>();
map2.put("aaa", map);
return map2;
}
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册