Merge branch '3.2.x' into master

Conflicts:
	gradle.properties
	spring-beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java
	spring-context-support/src/main/java/org/springframework/cache/ehcache/EhCacheManagerFactoryBean.java
	spring-core/src/main/java/org/springframework/core/convert/support/StringToEnumConverterFactory.java
	spring-core/src/main/java/org/springframework/core/env/ReadOnlySystemAttributesMap.java
	spring-jdbc/src/main/java/org/springframework/jdbc/datasource/LazyConnectionDataSourceProxy.java
	spring-jdbc/src/main/java/org/springframework/jdbc/support/lob/AbstractLobHandler.java
	spring-web/src/main/java/org/springframework/http/client/BufferingClientHttpRequestWrapper.java
	spring-web/src/main/java/org/springframework/http/client/SimpleBufferingClientHttpRequest.java
	spring-web/src/main/java/org/springframework/http/converter/BufferedImageHttpMessageConverter.java
	spring-web/src/main/java/org/springframework/http/converter/FormHttpMessageConverter.java
This commit is contained in:
Chris Beams
2013-03-04 15:41:15 +01:00
1450 changed files with 17678 additions and 42998 deletions

View File

@@ -43,4 +43,4 @@ public interface MethodFilter {
*/
List<Method> filter(List<Method> methods);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -108,7 +108,9 @@ public enum SpelMessage {
OPERAND_NOT_INCREMENTABLE(Kind.ERROR,1066,"the expression component ''{0}'' does not support increment"), //
OPERAND_NOT_DECREMENTABLE(Kind.ERROR,1067,"the expression component ''{0}'' does not support decrement"), //
NOT_ASSIGNABLE(Kind.ERROR,1068,"the expression component ''{0}'' is not assignable"), //
;
MISSING_CHARACTER(Kind.ERROR,1069,"missing expected character ''{0}''"),
LEFT_OPERAND_PROBLEM(Kind.ERROR,1070, "Problem parsing left operand"),
MISSING_SELECTION_EXPRESSION(Kind.ERROR, 1071, "A required selection expression has not been specified");
private Kind kind;
private int code;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* Copyright 2002-2013 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.
@@ -20,6 +20,7 @@ package org.springframework.expression.spel;
* Configuration object for the SpEL expression parser.
*
* @author Juergen Hoeller
* @author Phillip Webb
* @since 3.0
* @see org.springframework.expression.spel.standard.SpelExpressionParser#SpelExpressionParser(SpelParserConfiguration)
*/
@@ -29,19 +30,52 @@ public class SpelParserConfiguration {
private final boolean autoGrowCollections;
private int maximumAutoGrowSize;
/**
* Create a new {@link SpelParserConfiguration} instance.
* @param autoGrowNullReferences if null references should automatically grow
* @param autoGrowCollections if collections should automatically grow
* @see #SpelParserConfiguration(boolean, boolean, int)
*/
public SpelParserConfiguration(boolean autoGrowNullReferences, boolean autoGrowCollections) {
this(autoGrowNullReferences, autoGrowCollections, Integer.MAX_VALUE);
}
/**
* Create a new {@link SpelParserConfiguration} instance.
* @param autoGrowNullReferences if null references should automatically grow
* @param autoGrowCollections if collections should automatically grow
* @param maximumAutoGrowSize the maximum size that the collection can auto grow
*/
public SpelParserConfiguration(boolean autoGrowNullReferences,
boolean autoGrowCollections, int maximumAutoGrowSize) {
this.autoGrowNullReferences = autoGrowNullReferences;
this.autoGrowCollections = autoGrowCollections;
this.maximumAutoGrowSize = maximumAutoGrowSize;
}
/**
* @return {@code true} if {@code null} references should be automatically grown
*/
public boolean isAutoGrowNullReferences() {
return this.autoGrowNullReferences;
}
/**
* @return {@code true} if collections should be automatically grown
*/
public boolean isAutoGrowCollections() {
return this.autoGrowCollections;
}
/**
* @return the maximum size that a collection can auto grow
*/
public int getMaximumAutoGrowSize() {
return this.maximumAutoGrowSize;
}
}

View File

@@ -36,6 +36,7 @@ public class CompoundExpression extends SpelNodeImpl {
}
}
@Override
protected ValueRef getValueRef(ExpressionState state) throws EvaluationException {
if (getChildCount()==1) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -38,6 +38,7 @@ import org.springframework.expression.spel.support.ReflectivePropertyAccessor;
* (lists/sets)/arrays
*
* @author Andy Clement
* @author Phillip Webb
* @since 3.0
*/
// TODO support multidimensional arrays
@@ -257,25 +258,20 @@ public class Indexer extends SpelNodeImpl {
private final boolean growCollection;
private int maximumSize;
CollectionIndexingValueRef(Collection collection, int index, TypeDescriptor collectionEntryTypeDescriptor,
TypeConverter typeConverter, boolean growCollection) {
TypeConverter typeConverter, boolean growCollection, int maximumSize) {
this.collection = collection;
this.index = index;
this.collectionEntryTypeDescriptor = collectionEntryTypeDescriptor;
this.typeConverter = typeConverter;
this.growCollection = growCollection;
this.maximumSize = maximumSize;
}
public TypedValue getValue() {
if (this.index >= this.collection.size()) {
if (this.growCollection) {
growCollection(this.collectionEntryTypeDescriptor, this.index, this.collection);
}
else {
throw new SpelEvaluationException(getStartPosition(), SpelMessage.COLLECTION_INDEX_OUT_OF_BOUNDS,
this.collection.size(), this.index);
}
}
growCollectionIfNecessary();
if (this.collection instanceof List) {
Object o = ((List) this.collection).get(this.index);
return new TypedValue(o, this.collectionEntryTypeDescriptor.elementTypeDescriptor(o));
@@ -291,15 +287,7 @@ public class Indexer extends SpelNodeImpl {
}
public void setValue(Object newValue) {
if (this.index >= this.collection.size()) {
if (this.growCollection) {
growCollection(this.collectionEntryTypeDescriptor, this.index, this.collection);
}
else {
throw new SpelEvaluationException(getStartPosition(), SpelMessage.COLLECTION_INDEX_OUT_OF_BOUNDS,
this.collection.size(), this.index);
}
}
growCollectionIfNecessary();
if (this.collection instanceof List) {
List list = (List) this.collection;
if (this.collectionEntryTypeDescriptor.getElementTypeDescriptor() != null) {
@@ -314,6 +302,36 @@ public class Indexer extends SpelNodeImpl {
}
}
private void growCollectionIfNecessary() {
if (this.index >= this.collection.size()) {
if (!this.growCollection) {
throw new SpelEvaluationException(getStartPosition(), SpelMessage.COLLECTION_INDEX_OUT_OF_BOUNDS,
this.collection.size(), this.index);
}
if(this.index >= this.maximumSize) {
throw new SpelEvaluationException(getStartPosition(), SpelMessage.UNABLE_TO_GROW_COLLECTION);
}
if (this.collectionEntryTypeDescriptor.getElementTypeDescriptor() == null) {
throw new SpelEvaluationException(getStartPosition(), SpelMessage.UNABLE_TO_GROW_COLLECTION_UNKNOWN_ELEMENT_TYPE);
}
TypeDescriptor elementType = this.collectionEntryTypeDescriptor.getElementTypeDescriptor();
try {
int newElements = this.index - this.collection.size();
while (newElements >= 0) {
(this.collection).add(elementType.getType().newInstance());
newElements--;
}
}
catch (Exception ex) {
throw new SpelEvaluationException(getStartPosition(), ex, SpelMessage.UNABLE_TO_GROW_COLLECTION);
}
}
}
public boolean isWritable() {
return true;
}
@@ -403,7 +421,8 @@ public class Indexer extends SpelNodeImpl {
}
else if (targetObject instanceof Collection) {
return new CollectionIndexingValueRef((Collection<?>) targetObject, idx, targetObjectTypeDescriptor,
state.getTypeConverter(), state.getConfiguration().isAutoGrowCollections());
state.getTypeConverter(), state.getConfiguration().isAutoGrowCollections(),
state.getConfiguration().getMaximumAutoGrowSize());
}
else if (targetObject instanceof String) {
return new StringIndexingLValue((String) targetObject, idx, targetObjectTypeDescriptor);
@@ -421,32 +440,6 @@ public class Indexer extends SpelNodeImpl {
targetObjectTypeDescriptor.toString());
}
/**
* Attempt to grow the specified collection so that the specified index is valid.
* @param targetType the type of the elements in the collection
* @param index the index into the collection that needs to be valid
* @param collection the collection to grow with elements
*/
private void growCollection(TypeDescriptor targetType, int index, Collection<Object> collection) {
if (targetType.getElementTypeDescriptor() == null) {
throw new SpelEvaluationException(getStartPosition(), SpelMessage.UNABLE_TO_GROW_COLLECTION_UNKNOWN_ELEMENT_TYPE);
}
TypeDescriptor elementType = targetType.getElementTypeDescriptor();
Object newCollectionElement;
try {
int newElements = index - collection.size();
while (newElements > 0) {
collection.add(elementType.getType().newInstance());
newElements--;
}
newCollectionElement = elementType.getType().newInstance();
}
catch (Exception ex) {
throw new SpelEvaluationException(getStartPosition(), ex, SpelMessage.UNABLE_TO_GROW_COLLECTION);
}
collection.add(newCollectionElement);
}
@Override
public String toStringAST() {
StringBuilder sb = new StringBuilder();

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -17,23 +17,32 @@
package org.springframework.expression.spel.ast;
import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.*;
import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.InternalParseException;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.expression.spel.SpelParseException;
/**
* Common superclass for nodes representing literals (boolean, string, number, etc).
*
* @author Andy Clement
* @author Juergen Hoeller
*/
public abstract class Literal extends SpelNodeImpl {
protected String literalValue;
private final String originalValue;
public Literal(String payload, int pos) {
public Literal(String originalValue, int pos) {
super(pos);
this.literalValue = payload;
this.originalValue = originalValue;
}
public abstract TypedValue getLiteralValue();
public final String getOriginalValue() {
return this.originalValue;
}
@Override
public final TypedValue getValueInternal(ExpressionState state) throws SpelEvaluationException {
@@ -50,10 +59,13 @@ public abstract class Literal extends SpelNodeImpl {
return toString();
}
public abstract TypedValue getLiteralValue();
/**
* Process the string form of a number, using the specified base if supplied and return an appropriate literal to
* hold it. Any suffix to indicate a long will be taken into account (either 'l' or 'L' is supported).
*
* @param numberToken the token holding the number as its payload (eg. 1234 or 0xCAFE)
* @param radix the base of number
* @return a subtype of Literal that can represent it
@@ -62,7 +74,8 @@ public abstract class Literal extends SpelNodeImpl {
try {
int value = Integer.parseInt(numberToken, radix);
return new IntLiteral(numberToken, pos, value);
} catch (NumberFormatException nfe) {
}
catch (NumberFormatException nfe) {
throw new InternalParseException(new SpelParseException(pos>>16, nfe, SpelMessage.NOT_AN_INTEGER, numberToken));
}
}
@@ -71,25 +84,26 @@ public abstract class Literal extends SpelNodeImpl {
try {
long value = Long.parseLong(numberToken, radix);
return new LongLiteral(numberToken, pos, value);
} catch (NumberFormatException nfe) {
}
catch (NumberFormatException nfe) {
throw new InternalParseException(new SpelParseException(pos>>16, nfe, SpelMessage.NOT_A_LONG, numberToken));
}
}
public static Literal getRealLiteral(String numberToken, int pos, boolean isFloat) {
try {
if (isFloat) {
float value = Float.parseFloat(numberToken);
return new FloatLiteral(numberToken, pos, value);
} else {
}
else {
double value = Double.parseDouble(numberToken);
return new RealLiteral(numberToken, pos, value);
}
} catch (NumberFormatException nfe) {
}
catch (NumberFormatException nfe) {
throw new InternalParseException(new SpelParseException(pos>>16, nfe, SpelMessage.NOT_A_REAL, numberToken));
}
}
}

View File

@@ -70,7 +70,7 @@ public class Projection extends SpelNodeImpl {
if (operand instanceof Map) {
Map<?, ?> mapData = (Map<?, ?>) operand;
List<Object> result = new ArrayList<Object>();
for (Map.Entry<?,?> entry : mapData.entrySet()) {
for (Map.Entry<?, ?> entry : mapData.entrySet()) {
try {
state.pushActiveContextObject(new TypedValue(entry));
result.add(this.children[0].getValueInternal(state).getValue());

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -29,6 +29,7 @@ import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
@@ -54,7 +55,9 @@ public class Selection extends SpelNodeImpl {
private final boolean nullSafe;
public Selection(boolean nullSafe, int variant,int pos,SpelNodeImpl expression) {
super(pos,expression);
super(pos, expression != null ? new SpelNodeImpl[] { expression }
: new SpelNodeImpl[] {});
Assert.notNull(expression, "Expression must not be null");
this.nullSafe = nullSafe;
this.variant = variant;
}
@@ -73,9 +76,9 @@ public class Selection extends SpelNodeImpl {
if (operand instanceof Map) {
Map<?, ?> mapdata = (Map<?, ?>) operand;
// TODO don't lose generic info for the new map
Map<Object,Object> result = new HashMap<Object,Object>();
Map<Object, Object> result = new HashMap<Object, Object>();
Object lastKey = null;
for (Map.Entry<?,?> entry : mapdata.entrySet()) {
for (Map.Entry<?, ?> entry : mapdata.entrySet()) {
try {
TypedValue kvpair = new TypedValue(entry);
state.pushActiveContextObject(kvpair);
@@ -101,7 +104,7 @@ public class Selection extends SpelNodeImpl {
return new ValueRef.TypedValueHolderValueRef(new TypedValue(null),this);
}
if (variant == LAST) {
Map<Object,Object> resultMap = new HashMap<Object,Object>();
Map<Object, Object> resultMap = new HashMap<Object, Object>();
Object lastValue = result.get(lastKey);
resultMap.put(lastKey,lastValue);
return new ValueRef.TypedValueHolderValueRef(new TypedValue(resultMap),this);

View File

@@ -149,5 +149,4 @@ public abstract class SpelNodeImpl implements SpelNode {
protected ValueRef getValueRef(ExpressionState state) throws EvaluationException {
throw new SpelEvaluationException(pos,SpelMessage.NOT_ASSIGNABLE,toStringAST());
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -37,6 +37,7 @@ import org.springframework.util.StringUtils;
* Hand written SpEL parser. Instances are reusable but are not thread safe.
*
* @author Andy Clement
* @author Phillip Webb
* @since 3.0
*/
class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
@@ -104,8 +105,8 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
Token t = peekToken();
if (t.kind==TokenKind.ASSIGN) { // a=b
if (expr==null) {
expr = new NullLiteral(toPos(t.startpos-1,t.endpos-1));
}
expr = new NullLiteral(toPos(t.startpos-1,t.endpos-1));
}
nextToken();
SpelNodeImpl assignedValue = eatLogicalOrExpression();
return new Assign(toPos(t),expr,assignedValue);
@@ -139,7 +140,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
while (peekIdentifierToken("or") || peekToken(TokenKind.SYMBOLIC_OR)) {
Token t = nextToken(); //consume OR
SpelNodeImpl rhExpr = eatLogicalAndExpression();
checkRightOperand(t,rhExpr);
checkOperands(t,expr,rhExpr);
expr = new OpOr(toPos(t),expr,rhExpr);
}
return expr;
@@ -151,7 +152,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
while (peekIdentifierToken("and") || peekToken(TokenKind.SYMBOLIC_AND)) {
Token t = nextToken();// consume 'AND'
SpelNodeImpl rhExpr = eatRelationalExpression();
checkRightOperand(t,rhExpr);
checkOperands(t,expr,rhExpr);
expr = new OpAnd(toPos(t),expr,rhExpr);
}
return expr;
@@ -164,7 +165,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
if (relationalOperatorToken != null) {
Token t = nextToken(); //consume relational operator token
SpelNodeImpl rhExpr = eatSumExpression();
checkRightOperand(t,rhExpr);
checkOperands(t,expr,rhExpr);
TokenKind tk = relationalOperatorToken.kind;
if (relationalOperatorToken.isNumericRelationalOperator()) {
int pos = toPos(t);
@@ -217,7 +218,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
while (peekToken(TokenKind.STAR,TokenKind.DIV,TokenKind.MOD)) {
Token t = nextToken(); // consume STAR/DIV/MOD
SpelNodeImpl rhExpr = eatPowerIncDecExpression();
checkRightOperand(t,rhExpr);
checkOperands(t,expr,rhExpr);
if (t.kind==TokenKind.STAR) {
expr = new OpMultiply(toPos(t),expr,rhExpr);
} else if (t.kind==TokenKind.DIV) {
@@ -556,6 +557,9 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
}
nextToken();
SpelNodeImpl expr = eatExpression();
if(expr == null) {
raiseInternalException(toPos(t), SpelMessage.MISSING_SELECTION_EXPRESSION);
}
eatToken(TokenKind.RSQUARE);
if (t.kind==TokenKind.SELECT_FIRST) {
constructedNodes.push(new Selection(nullSafeNavigation,Selection.FIRST,toPos(t),expr));
@@ -836,6 +840,17 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
}
}
private void checkOperands(Token token, SpelNodeImpl left, SpelNodeImpl right) {
checkLeftOperand(token, left);
checkRightOperand(token, right);
}
private void checkLeftOperand(Token token, SpelNodeImpl operandExpression) {
if (operandExpression==null) {
raiseInternalException(token.startpos,SpelMessage.LEFT_OPERAND_PROBLEM);
}
}
private void checkRightOperand(Token token, SpelNodeImpl operandExpression) {
if (operandExpression==null) {
raiseInternalException(token.startpos,SpelMessage.RIGHT_OPERAND_PROBLEM);

View File

@@ -84,4 +84,4 @@ class Token {
public Token asBetweenToken() {
return new Token(TokenKind.BETWEEN,startpos,endpos);
}
}
}

View File

@@ -56,4 +56,4 @@ enum TokenKind {
public int getLength() {
return tokenChars.length;
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -29,6 +29,7 @@ import org.springframework.util.Assert;
* Lex some input data into a stream of tokens that can then be parsed.
*
* @author Andy Clement
* @author Phillip Webb
* @since 3.0
*/
class Tokenizer {
@@ -137,14 +138,20 @@ class Tokenizer {
}
break;
case '&':
if (isTwoCharToken(TokenKind.SYMBOLIC_AND)) {
pushPairToken(TokenKind.SYMBOLIC_AND);
if (!isTwoCharToken(TokenKind.SYMBOLIC_AND)) {
throw new InternalParseException(new SpelParseException(
expressionString, pos,
SpelMessage.MISSING_CHARACTER, "&"));
}
pushPairToken(TokenKind.SYMBOLIC_AND);
break;
case '|':
if (isTwoCharToken(TokenKind.SYMBOLIC_OR)) {
pushPairToken(TokenKind.SYMBOLIC_OR);
if (!isTwoCharToken(TokenKind.SYMBOLIC_OR)) {
throw new InternalParseException(new SpelParseException(
expressionString, pos,
SpelMessage.MISSING_CHARACTER, "|"));
}
pushPairToken(TokenKind.SYMBOLIC_OR);
break;
case '?':
if (isTwoCharToken(TokenKind.SELECT)) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -19,13 +19,16 @@ package org.springframework.expression.spel.support;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.springframework.core.BridgeMethodResolver;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.AccessException;
@@ -37,7 +40,6 @@ import org.springframework.expression.MethodResolver;
import org.springframework.expression.TypeConverter;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.util.CollectionUtils;
/**
* Reflection-based {@link MethodResolver} used by default in
@@ -92,25 +94,16 @@ public class ReflectiveMethodResolver implements MethodResolver {
try {
TypeConverter typeConverter = context.getTypeConverter();
Class<?> type = (targetObject instanceof Class ? (Class<?>) targetObject : targetObject.getClass());
Method[] methods = getMethods(type, targetObject);
List<Method> methods = new ArrayList<Method>(Arrays.asList(getMethods(type, targetObject)));
// If a filter is registered for this type, call it
MethodFilter filter = (this.filters != null ? this.filters.get(type) : null);
if (filter != null) {
List<Method> methodsForFiltering = new ArrayList<Method>();
for (Method method: methods) {
methodsForFiltering.add(method);
}
List<Method> methodsFiltered = filter.filter(methodsForFiltering);
if (CollectionUtils.isEmpty(methodsFiltered)) {
methods = NO_METHODS;
}
else {
methods = methodsFiltered.toArray(new Method[methodsFiltered.size()]);
}
methods = filter.filter(methods);
}
Arrays.sort(methods, new Comparator<Method>() {
// Sort methods into a sensible order
Collections.sort(methods, new Comparator<Method>() {
public int compare(Method m1, Method m2) {
int m1pl = m1.getParameterTypes().length;
int m2pl = m2.getParameterTypes().length;
@@ -118,6 +111,14 @@ public class ReflectiveMethodResolver implements MethodResolver {
}
});
// Resolve any bridge methods
for (int i = 0; i < methods.size(); i++) {
methods.set(i, BridgeMethodResolver.findBridgedMethod(methods.get(i)));
}
// Remove duplicate methods (possible due to resolved bridge methods)
methods = new ArrayList<Method>(new LinkedHashSet<Method>(methods));
Method closeMatch = null;
int closeMatchDistance = Integer.MAX_VALUE;
int[] argsToConvert = null;
@@ -125,9 +126,6 @@ public class ReflectiveMethodResolver implements MethodResolver {
boolean multipleOptions = false;
for (Method method : methods) {
if (method.isBridge()) {
continue;
}
if (method.getName().equals(name)) {
Class<?>[] paramTypes = method.getParameterTypes();
List<TypeDescriptor> paramDescriptors = new ArrayList<TypeDescriptor>(paramTypes.length);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -21,6 +21,8 @@ import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -42,6 +44,7 @@ import org.springframework.util.StringUtils;
*
* @author Andy Clement
* @author Juergen Hoeller
* @author Phillip Webb
* @since 3.0
*/
public class ReflectivePropertyAccessor implements PropertyAccessor {
@@ -284,7 +287,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
private Method findGetterForProperty(String propertyName, Class<?> clazz, Object target) {
Method method = findGetterForProperty(propertyName, clazz, target instanceof Class);
if(method == null && target instanceof Class) {
if (method == null && target instanceof Class) {
method = findGetterForProperty(propertyName, target.getClass(), false);
}
return method;
@@ -292,7 +295,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
private Method findSetterForProperty(String propertyName, Class<?> clazz, Object target) {
Method method = findSetterForProperty(propertyName, clazz, target instanceof Class);
if(method == null && target instanceof Class) {
if (method == null && target instanceof Class) {
method = findSetterForProperty(propertyName, target.getClass(), false);
}
return method;
@@ -300,7 +303,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
private Field findField(String name, Class<?> clazz, Object target) {
Field field = findField(name, clazz, target instanceof Class);
if(field == null && target instanceof Class) {
if (field == null && target instanceof Class) {
field = findField(name, target.getClass(), false);
}
return field;
@@ -310,13 +313,13 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
* Find a getter method for the specified property.
*/
protected Method findGetterForProperty(String propertyName, Class<?> clazz, boolean mustBeStatic) {
Method[] ms = clazz.getMethods();
Method[] ms = getSortedClassMethods(clazz);
String propertyMethodSuffix = getPropertyMethodSuffix(propertyName);
// Try "get*" method...
String getterName = "get" + propertyMethodSuffix;
for (Method method : ms) {
if (!method.isBridge() && method.getName().equals(getterName) && method.getParameterTypes().length == 0 &&
if (method.getName().equals(getterName) && method.getParameterTypes().length == 0 &&
(!mustBeStatic || Modifier.isStatic(method.getModifiers()))) {
return method;
}
@@ -324,7 +327,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
// Try "is*" method...
getterName = "is" + propertyMethodSuffix;
for (Method method : ms) {
if (!method.isBridge() && method.getName().equals(getterName) && method.getParameterTypes().length == 0 &&
if (method.getName().equals(getterName) && method.getParameterTypes().length == 0 &&
(boolean.class.equals(method.getReturnType()) || Boolean.class.equals(method.getReturnType())) &&
(!mustBeStatic || Modifier.isStatic(method.getModifiers()))) {
return method;
@@ -337,10 +340,10 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
* Find a setter method for the specified property.
*/
protected Method findSetterForProperty(String propertyName, Class<?> clazz, boolean mustBeStatic) {
Method[] methods = clazz.getMethods();
Method[] methods = getSortedClassMethods(clazz);
String setterName = "set" + getPropertyMethodSuffix(propertyName);
for (Method method : methods) {
if (!method.isBridge() && method.getName().equals(setterName) && method.getParameterTypes().length == 1 &&
if (method.getName().equals(setterName) && method.getParameterTypes().length == 1 &&
(!mustBeStatic || Modifier.isStatic(method.getModifiers()))) {
return method;
}
@@ -348,6 +351,19 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
return null;
}
/**
* Returns class methods ordered with non bridge methods appearing higher.
*/
private Method[] getSortedClassMethods(Class<?> clazz) {
Method[] methods = clazz.getMethods();
Arrays.sort(methods, new Comparator<Method>() {
public int compare(Method o1, Method o2) {
return (o1.isBridge() == o2.isBridge()) ? 0 : (o1.isBridge() ? 1 : -1);
}
});
return methods;
}
protected String getPropertyMethodSuffix(String propertyName) {
if (propertyName.length() > 1 && Character.isUpperCase(propertyName.charAt(1))) {
return propertyName;
@@ -367,6 +383,20 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
return field;
}
}
// We'll search superclasses and implemented interfaces explicitly,
// although it shouldn't be necessary - however, see SPR-10125.
if (clazz.getSuperclass() != null) {
Field field = findField(name, clazz.getSuperclass(), mustBeStatic);
if (field != null) {
return field;
}
}
for (Class<?> implementedInterface : clazz.getInterfaces()) {
Field field = findField(name, implementedInterface, mustBeStatic);
if (field != null) {
return field;
}
}
return null;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -16,7 +16,14 @@
package org.springframework.expression.spel;
import static org.junit.Assert.*;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.lang.reflect.Method;
import java.util.ArrayList;
@@ -24,7 +31,6 @@ import java.util.List;
import java.util.Map;
import org.junit.Test;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.AccessException;
import org.springframework.expression.BeanResolver;
@@ -48,6 +54,7 @@ import org.springframework.expression.spel.testresources.TestPerson;
* @author Andy Clement
* @author Mark Fisher
* @author Sam Brannen
* @author Phillip Webb
* @since 3.0
*/
public class EvaluationTests extends ExpressionTestCase {
@@ -708,6 +715,23 @@ public class EvaluationTests extends ExpressionTestCase {
}
}
@Test
public void limitCollectionGrowing() throws Exception {
TestClass instance = new TestClass();
StandardEvaluationContext ctx = new StandardEvaluationContext(instance);
SpelExpressionParser parser = new SpelExpressionParser( new SpelParserConfiguration(true, true, 3));
Expression expression = parser.parseExpression("foo[2]");
expression.setValue(ctx, "2");
assertThat(instance.getFoo().size(), equalTo(3));
expression = parser.parseExpression("foo[3]");
try {
expression.setValue(ctx, "3");
} catch(SpelEvaluationException see) {
assertEquals(SpelMessage.UNABLE_TO_GROW_COLLECTION, see.getMessageCode());
assertThat(instance.getFoo().size(), equalTo(3));
}
}
// For now I am making #this not assignable
@Test
public void increment01root() {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -17,6 +17,7 @@
package org.springframework.expression.spel;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.util.HashMap;
import java.util.Map;
@@ -83,9 +84,10 @@ public class MapAccessTests extends ExpressionTestCase {
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("testBean.properties['key2']");
String key= (String)exp.getValue(bean);
String key = (String) exp.getValue(bean);
assertNotNull(key);
}
}
public static class TestBean
{

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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,6 +18,7 @@ package org.springframework.expression.spel;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -213,9 +214,11 @@ public class SpelDocumentationTests extends ExpressionTestCase {
societyContext.setRootObject(new IEEE());
// Officer's Dictionary
Inventor pupin = parser.parseExpression("officers['president']").getValue(societyContext, Inventor.class);
assertNotNull(pupin);
// evaluates to "Idvor"
String city = parser.parseExpression("officers['president'].PlaceOfBirth.city").getValue(societyContext, String.class);
assertNotNull(city);
// setting values
Inventor i = parser.parseExpression("officers['advisors'][0]").getValue(societyContext,Inventor.class);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -16,9 +16,18 @@
package org.springframework.expression.spel;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
@@ -26,8 +35,9 @@ import java.util.Map;
import java.util.Properties;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.AccessException;
import org.springframework.expression.BeanResolver;
@@ -48,17 +58,19 @@ import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.expression.spel.support.StandardTypeLocator;
import org.springframework.expression.spel.testresources.le.div.mod.reserved.Reserver;
import static org.junit.Assert.*;
/**
* Reproduction tests cornering various SpEL JIRA issues.
*
* @author Andy Clement
* @author Juergen Hoeller
* @author Clark Duplichien
* @author Phillip Webb
*/
public class SpelReproTests extends ExpressionTestCase {
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void testNPE_SPR5661() {
evaluate("joinThreeStrings('a',null,'c')", "anullc", String.class);
@@ -1656,11 +1668,21 @@ public class SpelReproTests extends ExpressionTestCase {
assertEquals(Integer.class, value.getTypeDescriptor().getType());
}
@Test
public void SPR_10162_onlyBridgeMethodTest() throws Exception {
ReflectivePropertyAccessor accessor = new ReflectivePropertyAccessor();
StandardEvaluationContext context = new StandardEvaluationContext();
Object target = new OnlyBridgeMethod();
TypedValue value = accessor.read(context, target , "property");
assertEquals(Integer.class, value.getTypeDescriptor().getType());
}
@Test
public void SPR_10091_simpleTestValueType() {
ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext evaluationContext = new StandardEvaluationContext(new BooleanHolder());
Class<?> valueType = parser.parseExpression("simpleProperty").getValueType(evaluationContext);
assertNotNull(valueType);
}
@Test
@@ -1668,6 +1690,7 @@ public class SpelReproTests extends ExpressionTestCase {
ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext evaluationContext = new StandardEvaluationContext(new BooleanHolder());
Object value = parser.parseExpression("simpleProperty").getValue(evaluationContext);
assertNotNull(value);
}
@Test
@@ -1675,6 +1698,7 @@ public class SpelReproTests extends ExpressionTestCase {
ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext evaluationContext = new StandardEvaluationContext(new BooleanHolder());
Class<?> valueType = parser.parseExpression("primitiveProperty").getValueType(evaluationContext);
assertNotNull(valueType);
}
@Test
@@ -1682,8 +1706,52 @@ public class SpelReproTests extends ExpressionTestCase {
ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext evaluationContext = new StandardEvaluationContext(new BooleanHolder());
Object value = parser.parseExpression("primitiveProperty").getValue(evaluationContext);
assertNotNull(value);
}
@Test
public void SPR_10146_malformedExpressions() throws Exception {
doTestSpr10146("/foo", "EL1070E:(pos 0): Problem parsing left operand");
doTestSpr10146("*foo", "EL1070E:(pos 0): Problem parsing left operand");
doTestSpr10146("%foo", "EL1070E:(pos 0): Problem parsing left operand");
doTestSpr10146("<foo", "EL1070E:(pos 0): Problem parsing left operand");
doTestSpr10146(">foo", "EL1070E:(pos 0): Problem parsing left operand");
doTestSpr10146("&&foo", "EL1070E:(pos 0): Problem parsing left operand");
doTestSpr10146("||foo", "EL1070E:(pos 0): Problem parsing left operand");
doTestSpr10146("&foo", "EL1069E:(pos 0): missing expected character '&'");
doTestSpr10146("|foo", "EL1069E:(pos 0): missing expected character '|'");
}
private void doTestSpr10146(String expression, String expectedMessage) {
thrown.expect(SpelParseException.class);
thrown.expectMessage(expectedMessage);
new SpelExpressionParser().parseExpression(expression);
}
@Test
public void SPR_10125() throws Exception {
StandardEvaluationContext context = new StandardEvaluationContext();
String fromInterface = parser.parseExpression("T("+StaticFinalImpl1.class.getName()+").VALUE").getValue(context, String.class);
assertThat(fromInterface, is("interfaceValue"));
String fromClass = parser.parseExpression("T("+StaticFinalImpl2.class.getName()+").VALUE").getValue(context, String.class);
assertThat(fromClass, is("interfaceValue"));
}
@Test
public void SPR_10210() throws Exception {
StandardEvaluationContext context = new StandardEvaluationContext();
context.setVariable("bridgeExample", new org.springframework.expression.spel.spr10210.D());
Expression parseExpression = parser.parseExpression("#bridgeExample.bridgeMethod()");
parseExpression.getValue(context);
}
@Test
public void SPR_10328() throws Exception {
thrown.expect(SpelParseException.class);
thrown.expectMessage("EL1071E:(pos 2): A required selection expression has not been specified");
Expression exp = parser.parseExpression("$[]");
exp.getValue(Arrays.asList("foo", "bar", "baz"));
}
public static class BooleanHolder {
@@ -1722,4 +1790,28 @@ public class SpelReproTests extends ExpressionTestCase {
}
}
static class PackagePrivateClassWithGetter {
public Integer getProperty() {
return null;
}
}
public static class OnlyBridgeMethod extends PackagePrivateClassWithGetter {
}
public static interface StaticFinal {
public static final String VALUE = "interfaceValue";
}
public abstract static class AbstractStaticFinal implements StaticFinal {
}
public static class StaticFinalImpl1 extends AbstractStaticFinal implements StaticFinal {
}
public static class StaticFinalImpl2 extends AbstractStaticFinal {
}
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright 2002-2013 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.spr10210;
import org.springframework.expression.spel.spr10210.comp.B;
import org.springframework.expression.spel.spr10210.infra.C;
abstract class A extends B<C> {
public void bridgeMethod() {
}
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright 2002-2013 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.spr10210;
public class D extends A {
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright 2002-2013 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.spr10210.comp;
import java.io.Serializable;
import org.springframework.expression.spel.spr10210.infra.C;
public class B<T extends C> implements Serializable {
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright 2002-2013 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.spr10210.infra;
public interface C {
}