SPR-7173, SPR-7100
This commit is contained in:
parent
42cdfbcd89
commit
f53621a86f
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright 2002-2010 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.expression;
|
||||
|
||||
/**
|
||||
* A bean resolver can be registered with the evaluation context and will
|
||||
* @author Andy Clement
|
||||
* @since 3.0.3
|
||||
*/
|
||||
public interface BeanResolver {
|
||||
|
||||
/**
|
||||
* Lookup the named bean and return it.
|
||||
* @param context the current evaluation context
|
||||
* @param beanname the name of the bean to lookup
|
||||
* @return a object representing the bean
|
||||
* @throws AccessException if there is an unexpected problem resolving the named bean
|
||||
*/
|
||||
Object resolve(EvaluationContext context, String beanname) throws AccessException;
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -73,6 +73,11 @@ public interface EvaluationContext {
|
|||
*/
|
||||
OperatorOverloader getOperatorOverloader();
|
||||
|
||||
/**
|
||||
* @return a bean resolver that can lookup named beans
|
||||
*/
|
||||
BeanResolver getBeanResolver();
|
||||
|
||||
/**
|
||||
* Set a named variable within this evaluation context to a specified value.
|
||||
* @param name variable to set
|
||||
|
|
|
|||
|
|
@ -93,6 +93,9 @@ public enum SpelMessage {
|
|||
UNABLE_TO_CREATE_LIST_FOR_INDEXING(Kind.ERROR,1054,"Unable to dynamically create a List to replace a null value"),//
|
||||
UNABLE_TO_CREATE_MAP_FOR_INDEXING(Kind.ERROR,1055,"Unable to dynamically create a Map to replace a null value"),//
|
||||
UNABLE_TO_DYNAMICALLY_CREATE_OBJECT(Kind.ERROR,1056,"Unable to dynamically create instance of ''{0}'' to replace a null value"),//
|
||||
NO_BEAN_RESOLVER_REGISTERED(Kind.ERROR,1057,"No bean resolver registered in the context to resolve access to bean ''{0}''"),//
|
||||
EXCEPTION_DURING_BEAN_RESOLUTION(Kind.ERROR, 1058, "A problem occurred when trying to resolve bean ''{0}'':''{1}''"), //
|
||||
INVALID_BEAN_REFERENCE(Kind.ERROR,1059,"@ can only be followed by an identifier or a quoted name"),//
|
||||
;
|
||||
|
||||
private Kind kind;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright 2002-2010 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.expression.spel.ast;
|
||||
|
||||
import org.springframework.expression.AccessException;
|
||||
import org.springframework.expression.BeanResolver;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
import org.springframework.expression.spel.SpelEvaluationException;
|
||||
import org.springframework.expression.spel.SpelMessage;
|
||||
|
||||
/**
|
||||
* Represents a bean reference to a type, for example "@foo" or "@'foo.bar'"
|
||||
*
|
||||
* @author Andy Clement
|
||||
*/
|
||||
public class BeanReference extends SpelNodeImpl {
|
||||
|
||||
private String beanname;
|
||||
|
||||
public BeanReference(int pos,String beanname) {
|
||||
super(pos);
|
||||
this.beanname = beanname;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
BeanResolver beanResolver = state.getEvaluationContext().getBeanResolver();
|
||||
if (beanResolver==null) {
|
||||
throw new SpelEvaluationException(getStartPosition(),SpelMessage.NO_BEAN_RESOLVER_REGISTERED, beanname);
|
||||
}
|
||||
try {
|
||||
TypedValue bean = new TypedValue(beanResolver.resolve(state.getEvaluationContext(),beanname));
|
||||
return bean;
|
||||
} catch (AccessException ae) {
|
||||
throw new SpelEvaluationException( getStartPosition(), ae, SpelMessage.EXCEPTION_DURING_BEAN_RESOLUTION,
|
||||
beanname, ae.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toStringAST() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("@");
|
||||
if (beanname.indexOf('.')==-1) {
|
||||
sb.append(beanname);
|
||||
} else {
|
||||
sb.append("'").append(beanname).append("'");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -28,6 +28,7 @@ import org.springframework.expression.spel.SpelMessage;
|
|||
import org.springframework.expression.spel.SpelParseException;
|
||||
import org.springframework.expression.spel.SpelParserConfiguration;
|
||||
import org.springframework.expression.spel.ast.Assign;
|
||||
import org.springframework.expression.spel.ast.BeanReference;
|
||||
import org.springframework.expression.spel.ast.BooleanLiteral;
|
||||
import org.springframework.expression.spel.ast.CompoundExpression;
|
||||
import org.springframework.expression.spel.ast.ConstructorReference;
|
||||
|
|
@ -437,6 +438,8 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
return pop();
|
||||
} else if (maybeEatTypeReference() || maybeEatNullReference() || maybeEatConstructorReference() || maybeEatMethodOrProperty(false) || maybeEatFunctionOrVar()) {
|
||||
return pop();
|
||||
} else if (maybeEatBeanReference()) {
|
||||
return pop();
|
||||
} else if (maybeEatProjection(false) || maybeEatSelection(false) || maybeEatIndexer()) {
|
||||
return pop();
|
||||
} else {
|
||||
|
|
@ -444,7 +447,30 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
}
|
||||
}
|
||||
|
||||
// parse: @beanname @'bean.name'
|
||||
// quoted if dotted
|
||||
private boolean maybeEatBeanReference() {
|
||||
if (peekToken(TokenKind.BEAN_REF)) {
|
||||
Token beanRefToken = nextToken();
|
||||
Token beanNameToken = null;
|
||||
String beanname = null;
|
||||
if (peekToken(TokenKind.IDENTIFIER)) {
|
||||
beanNameToken = eatToken(TokenKind.IDENTIFIER);
|
||||
beanname = beanNameToken.data;
|
||||
} else if (peekToken(TokenKind.LITERAL_STRING)) {
|
||||
beanNameToken = eatToken(TokenKind.LITERAL_STRING);
|
||||
beanname = beanNameToken.stringValue();
|
||||
beanname = beanname.substring(1, beanname.length() - 1);
|
||||
} else {
|
||||
raiseInternalException(beanRefToken.startpos,SpelMessage.INVALID_BEAN_REFERENCE);
|
||||
}
|
||||
|
||||
BeanReference beanReference = new BeanReference(toPos(beanNameToken),beanname);
|
||||
constructedNodes.push(beanReference);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean maybeEatTypeReference() {
|
||||
if (peekToken(TokenKind.IDENTIFIER)) {
|
||||
|
|
@ -454,7 +480,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
}
|
||||
nextToken();
|
||||
eatToken(TokenKind.LPAREN);
|
||||
SpelNodeImpl node = eatPossiblyQualifiedId(true);
|
||||
SpelNodeImpl node = eatPossiblyQualifiedId();
|
||||
// dotted qualified id
|
||||
eatToken(TokenKind.RPAREN);
|
||||
constructedNodes.push(new TypeReference(toPos(typeName),node));
|
||||
|
|
@ -518,29 +544,22 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
}
|
||||
|
||||
/**
|
||||
* Eat an identifier, possibly qualified (meaning that it is dotted). If the dollarAllowed parameter is true then
|
||||
* it will process any dollar characters found between names, and this allows it to support inner type references
|
||||
* correctly. For example 'com.foo.bar.Outer$Inner' will produce the identifier sequence com, foo, bar, Outer, $Inner,
|
||||
* note that the $ has been prefixed onto the Inner identifier. The code in TypeReference which reforms this into
|
||||
* a typename copes with the $ prefixed identifiers.
|
||||
* Eat an identifier, possibly qualified (meaning that it is dotted).
|
||||
* TODO AndyC Could create complete identifiers (a.b.c) here rather than a sequence of them? (a, b, c)
|
||||
*/
|
||||
private SpelNodeImpl eatPossiblyQualifiedId(boolean dollarAllowed) {
|
||||
private SpelNodeImpl eatPossiblyQualifiedId() {
|
||||
List<SpelNodeImpl> qualifiedIdPieces = new ArrayList<SpelNodeImpl>();
|
||||
Token startnode = eatToken(TokenKind.IDENTIFIER);
|
||||
qualifiedIdPieces.add(new Identifier(startnode.stringValue(),toPos(startnode)));
|
||||
boolean dollar = false;
|
||||
while (peekToken(TokenKind.DOT,true) || (dollarAllowed && (dollar = peekToken(TokenKind.DOLLAR,true)))) {
|
||||
while (peekToken(TokenKind.DOT,true)) {
|
||||
Token node = eatToken(TokenKind.IDENTIFIER);
|
||||
if (dollar) {
|
||||
qualifiedIdPieces.add(new Identifier("$"+node.stringValue(),((node.startpos-1)<<16)+node.endpos));
|
||||
} else {
|
||||
qualifiedIdPieces.add(new Identifier(node.stringValue(),toPos(node)));
|
||||
}
|
||||
}
|
||||
return new QualifiedIdentifier(toPos(startnode.startpos,qualifiedIdPieces.get(qualifiedIdPieces.size()-1).getEndPosition()),qualifiedIdPieces.toArray(new SpelNodeImpl[qualifiedIdPieces.size()]));
|
||||
}
|
||||
|
||||
// This is complicated due to the support for dollars in identifiers. Dollars are normally separate tokens but
|
||||
// there we want to combine a series of identifiers and dollars into a single identifier
|
||||
private boolean maybeEatMethodOrProperty(boolean nullSafeNavigation) {
|
||||
if (peekToken(TokenKind.IDENTIFIER)) {
|
||||
Token methodOrPropertyName = nextToken();
|
||||
|
|
@ -557,6 +576,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
//constructor
|
||||
|
|
@ -564,7 +584,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
private boolean maybeEatConstructorReference() {
|
||||
if (peekIdentifierToken("new")) {
|
||||
Token newToken = nextToken();
|
||||
SpelNodeImpl possiblyQualifiedConstructorName = eatPossiblyQualifiedId(true);
|
||||
SpelNodeImpl possiblyQualifiedConstructorName = eatPossiblyQualifiedId();
|
||||
List<SpelNodeImpl> nodes = new ArrayList<SpelNodeImpl>();
|
||||
nodes.add(possiblyQualifiedConstructorName);
|
||||
eatConstructorArgs(nodes);
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ enum TokenKind {
|
|||
COLON(":"),HASH("#"),RSQUARE("]"), LSQUARE("["),
|
||||
DOT("."), PLUS("+"), STAR("*"), DIV("/"), NOT("!"), MINUS("-"), SELECT_FIRST("^["), SELECT_LAST("$["), QMARK("?"), PROJECT("!["),
|
||||
GE(">="),GT(">"),LE("<="),LT("<"),EQ("=="),NE("!="),ASSIGN("="), INSTANCEOF("instanceof"), MATCHES("matches"), BETWEEN("between"),
|
||||
SELECT("?["), MOD("%"), POWER("^"), DOLLAR("$"),
|
||||
ELVIS("?:"), SAFE_NAVI("?.");
|
||||
SELECT("?["), MOD("%"), POWER("^"),
|
||||
ELVIS("?:"), SAFE_NAVI("?."), BEAN_REF("@")
|
||||
;
|
||||
|
||||
char[] tokenChars;
|
||||
|
|
|
|||
|
|
@ -96,6 +96,9 @@ class Tokenizer {
|
|||
case ']':
|
||||
pushCharToken(TokenKind.RSQUARE);
|
||||
break;
|
||||
case '@':
|
||||
pushCharToken(TokenKind.BEAN_REF);
|
||||
break;
|
||||
case '^':
|
||||
if (isTwoCharToken(TokenKind.SELECT_FIRST)) {
|
||||
pushPairToken(TokenKind.SELECT_FIRST);
|
||||
|
|
@ -134,7 +137,7 @@ class Tokenizer {
|
|||
if (isTwoCharToken(TokenKind.SELECT_LAST)) {
|
||||
pushPairToken(TokenKind.SELECT_LAST);
|
||||
} else {
|
||||
pushCharToken(TokenKind.DOLLAR);
|
||||
lexIdentifier();
|
||||
}
|
||||
break;
|
||||
case '>':
|
||||
|
|
@ -424,9 +427,9 @@ class Tokenizer {
|
|||
tokens.add(new Token(kind,pos,pos+kind.getLength()));
|
||||
}
|
||||
|
||||
// ID: ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'_'|'0'..'9'|DOT_ESCAPED)*;
|
||||
// ID: ('a'..'z'|'A'..'Z'|'_'|'$') ('a'..'z'|'A'..'Z'|'_'|'$'|'0'..'9'|DOT_ESCAPED)*;
|
||||
private boolean isIdentifier(char ch) {
|
||||
return isAlphabetic(ch) || isDigit(ch) || ch=='_';
|
||||
return isAlphabetic(ch) || isDigit(ch) || ch=='_' || ch=='$';
|
||||
}
|
||||
|
||||
private boolean isChar(char a,char b) {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
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.MethodFilter;
|
||||
|
|
@ -66,6 +67,8 @@ public class StandardEvaluationContext implements EvaluationContext {
|
|||
|
||||
private final Map<String, Object> variables = new HashMap<String, Object>();
|
||||
|
||||
private BeanResolver beanResolver;
|
||||
|
||||
|
||||
public StandardEvaluationContext() {
|
||||
setRootObject(null);
|
||||
|
|
@ -134,6 +137,14 @@ public class StandardEvaluationContext implements EvaluationContext {
|
|||
return this.methodResolvers;
|
||||
}
|
||||
|
||||
public void setBeanResolver(BeanResolver beanResolver) {
|
||||
this.beanResolver = beanResolver;
|
||||
}
|
||||
|
||||
public BeanResolver getBeanResolver() {
|
||||
return this.beanResolver;
|
||||
}
|
||||
|
||||
public void setMethodResolvers(List<MethodResolver> methodResolvers) {
|
||||
this.methodResolvers = methodResolvers;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ import junit.framework.Assert;
|
|||
|
||||
import org.junit.Test;
|
||||
import org.springframework.expression.ParseException;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.standard.SpelExpression;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
|
||||
/**
|
||||
* Parse some expressions and check we get the AST we expect. Rather than inspecting each node in the AST, we ask it to
|
||||
|
|
@ -267,18 +267,18 @@ public class ParsingTests {
|
|||
// parseCheck("{'a','b','a','d','e'}.distinct()");
|
||||
// }
|
||||
|
||||
// // references
|
||||
// public void testReferences01() {
|
||||
// parseCheck("@(foo)");
|
||||
// }
|
||||
//
|
||||
// public void testReferences02() {
|
||||
// parseCheck("@(p:foo)");
|
||||
// }
|
||||
//
|
||||
// public void testReferences04() {
|
||||
// parseCheck("@(a/b/c:foo)", "@(a.b.c:foo)");
|
||||
// }// normalized to '.' for separator in QualifiedIdentifier
|
||||
// references
|
||||
@Test
|
||||
public void testReferences01() {
|
||||
parseCheck("@foo");
|
||||
parseCheck("@'foo.bar'");
|
||||
parseCheck("@\"foo.bar.goo\"","@'foo.bar.goo'");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReferences03() {
|
||||
parseCheck("@$$foo");
|
||||
}
|
||||
|
||||
// properties
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import junit.framework.Assert;
|
|||
|
||||
import org.junit.Test;
|
||||
import org.springframework.expression.AccessException;
|
||||
import org.springframework.expression.BeanResolver;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.Expression;
|
||||
|
|
@ -350,6 +351,47 @@ public class SpringEL300Tests extends ExpressionTestCase {
|
|||
Assert.assertEquals("hello",name);
|
||||
}
|
||||
|
||||
/** $ related identifiers */
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testDollarPrefixedIdentifier_SPR7100() {
|
||||
Holder h = new Holder();
|
||||
StandardEvaluationContext eContext = new StandardEvaluationContext(h);
|
||||
eContext.addPropertyAccessor(new MapAccessor());
|
||||
h.map.put("$foo","wibble");
|
||||
h.map.put("foo$bar","wobble");
|
||||
h.map.put("foobar$$","wabble");
|
||||
h.map.put("$","wubble");
|
||||
h.map.put("$$","webble");
|
||||
h.map.put("$_$","tribble");
|
||||
String name = null;
|
||||
Expression expr = null;
|
||||
|
||||
expr = new SpelExpressionParser().parseRaw("map.$foo");
|
||||
name = expr.getValue(eContext,String.class);
|
||||
Assert.assertEquals("wibble",name);
|
||||
|
||||
expr = new SpelExpressionParser().parseRaw("map.foo$bar");
|
||||
name = expr.getValue(eContext,String.class);
|
||||
Assert.assertEquals("wobble",name);
|
||||
|
||||
expr = new SpelExpressionParser().parseRaw("map.foobar$$");
|
||||
name = expr.getValue(eContext,String.class);
|
||||
Assert.assertEquals("wabble",name);
|
||||
|
||||
expr = new SpelExpressionParser().parseRaw("map.$");
|
||||
name = expr.getValue(eContext,String.class);
|
||||
Assert.assertEquals("wubble",name);
|
||||
|
||||
expr = new SpelExpressionParser().parseRaw("map.$$");
|
||||
name = expr.getValue(eContext,String.class);
|
||||
Assert.assertEquals("webble",name);
|
||||
|
||||
expr = new SpelExpressionParser().parseRaw("map.$_$");
|
||||
name = expr.getValue(eContext,String.class);
|
||||
Assert.assertEquals("tribble",name);
|
||||
}
|
||||
|
||||
/** Should be accessing Goo.wibble field because 'bar' variable evaluates to "wibble" */
|
||||
@Test
|
||||
public void testIndexingAsAPropertyAccess_SPR6968_3() {
|
||||
|
|
@ -393,6 +435,36 @@ public class SpringEL300Tests extends ExpressionTestCase {
|
|||
Assert.assertEquals("world",g.value);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDollars() {
|
||||
StandardEvaluationContext eContext = new StandardEvaluationContext(new XX());
|
||||
Expression expr = null;
|
||||
expr = new SpelExpressionParser().parseRaw("m['$foo']");
|
||||
eContext.setVariable("file_name","$foo");
|
||||
Assert.assertEquals("wibble",expr.getValue(eContext,String.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDollars2() {
|
||||
StandardEvaluationContext eContext = new StandardEvaluationContext(new XX());
|
||||
Expression expr = null;
|
||||
expr = new SpelExpressionParser().parseRaw("m[$foo]");
|
||||
eContext.setVariable("file_name","$foo");
|
||||
Assert.assertEquals("wibble",expr.getValue(eContext,String.class));
|
||||
}
|
||||
|
||||
static class XX {
|
||||
public Map<String,String> m;
|
||||
|
||||
public String floo ="bar";
|
||||
|
||||
public XX() {
|
||||
m = new HashMap<String,String>();
|
||||
m.put("$foo","wibble");
|
||||
m.put("bar","siddle");
|
||||
}
|
||||
}
|
||||
|
||||
static class Goo {
|
||||
|
||||
public static Goo instance = new Goo();
|
||||
|
|
@ -411,6 +483,11 @@ public class SpringEL300Tests extends ExpressionTestCase {
|
|||
|
||||
}
|
||||
|
||||
static class Holder {
|
||||
|
||||
public Map map = new HashMap();
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
private void checkTemplateParsing(String expression, String expectedValue) throws Exception {
|
||||
|
|
@ -452,5 +529,102 @@ public class SpringEL300Tests extends ExpressionTestCase {
|
|||
}
|
||||
};
|
||||
|
||||
// @Test
|
||||
// public void testFails() {
|
||||
//
|
||||
// StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
|
||||
// evaluationContext.setVariable("target", new Foo2());
|
||||
// for (int i = 0; i < 300000; i++) {
|
||||
// evaluationContext.addPropertyAccessor(new MapAccessor());
|
||||
// ExpressionParser parser = new SpelExpressionParser();
|
||||
// Expression expression = parser.parseExpression("#target.execute(payload)");
|
||||
// Message message = new Message();
|
||||
// message.setPayload(i+"");
|
||||
// expression.getValue(evaluationContext, message);
|
||||
// }
|
||||
// }
|
||||
|
||||
static class Foo2 {
|
||||
public void execute(String str){
|
||||
System.out.println("Value: " + str);
|
||||
}
|
||||
}
|
||||
|
||||
static class Message{
|
||||
private String payload;
|
||||
|
||||
public String getPayload() {
|
||||
return payload;
|
||||
}
|
||||
|
||||
public void setPayload(String payload) {
|
||||
this.payload = payload;
|
||||
}
|
||||
}
|
||||
|
||||
// bean resolver tests
|
||||
|
||||
@Test
|
||||
public void beanResolution() {
|
||||
StandardEvaluationContext eContext = new StandardEvaluationContext(new XX());
|
||||
Expression expr = null;
|
||||
|
||||
// no resolver registered == exception
|
||||
try {
|
||||
expr = new SpelExpressionParser().parseRaw("@foo");
|
||||
Assert.assertEquals("custard",expr.getValue(eContext,String.class));
|
||||
} catch (SpelEvaluationException see) {
|
||||
Assert.assertEquals(SpelMessage.NO_BEAN_RESOLVER_REGISTERED,see.getMessageCode());
|
||||
Assert.assertEquals("foo",see.getInserts()[0]);
|
||||
}
|
||||
|
||||
eContext.setBeanResolver(new MyBeanResolver());
|
||||
|
||||
// bean exists
|
||||
expr = new SpelExpressionParser().parseRaw("@foo");
|
||||
Assert.assertEquals("custard",expr.getValue(eContext,String.class));
|
||||
|
||||
// bean does not exist
|
||||
expr = new SpelExpressionParser().parseRaw("@bar");
|
||||
Assert.assertEquals(null,expr.getValue(eContext,String.class));
|
||||
|
||||
// bean name will cause AccessException
|
||||
expr = new SpelExpressionParser().parseRaw("@goo");
|
||||
try {
|
||||
Assert.assertEquals(null,expr.getValue(eContext,String.class));
|
||||
} catch (SpelEvaluationException see) {
|
||||
Assert.assertEquals(SpelMessage.EXCEPTION_DURING_BEAN_RESOLUTION,see.getMessageCode());
|
||||
Assert.assertEquals("goo",see.getInserts()[0]);
|
||||
Assert.assertTrue(see.getCause() instanceof AccessException);
|
||||
Assert.assertTrue(((AccessException)see.getCause()).getMessage().startsWith("DONT"));
|
||||
}
|
||||
|
||||
// bean exists
|
||||
expr = new SpelExpressionParser().parseRaw("@'foo.bar'");
|
||||
Assert.assertEquals("trouble",expr.getValue(eContext,String.class));
|
||||
|
||||
// bean exists
|
||||
try {
|
||||
expr = new SpelExpressionParser().parseRaw("@378");
|
||||
Assert.assertEquals("trouble",expr.getValue(eContext,String.class));
|
||||
} catch (SpelParseException spe) {
|
||||
Assert.assertEquals(SpelMessage.INVALID_BEAN_REFERENCE,spe.getMessageCode());
|
||||
}
|
||||
}
|
||||
|
||||
static class MyBeanResolver implements BeanResolver {
|
||||
public Object resolve(EvaluationContext context, String beanname) throws AccessException {
|
||||
if (beanname.equals("foo")) {
|
||||
return "custard";
|
||||
} else if (beanname.equals("foo.bar")) {
|
||||
return "trouble";
|
||||
} else if (beanname.equals("goo")) {
|
||||
throw new AccessException("DONT ASK ME ABOUT GOO");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// end bean resolver tests
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue