summaryrefslogtreecommitdiff
path: root/spring-expression/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'spring-expression/src/main')
-rw-r--r--spring-expression/src/main/java/org/springframework/expression/BeanResolver.java9
-rw-r--r--spring-expression/src/main/java/org/springframework/expression/spel/CodeFlow.java147
-rw-r--r--spring-expression/src/main/java/org/springframework/expression/spel/SpelMessage.java4
-rw-r--r--spring-expression/src/main/java/org/springframework/expression/spel/ast/BeanReference.java12
-rw-r--r--spring-expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java4
-rw-r--r--spring-expression/src/main/java/org/springframework/expression/spel/ast/InlineList.java12
-rw-r--r--spring-expression/src/main/java/org/springframework/expression/spel/ast/OperatorInstanceof.java22
-rw-r--r--spring-expression/src/main/java/org/springframework/expression/spel/standard/InternalSpelExpressionParser.java13
-rw-r--r--spring-expression/src/main/java/org/springframework/expression/spel/standard/TokenKind.java4
-rw-r--r--spring-expression/src/main/java/org/springframework/expression/spel/standard/Tokenizer.java12
-rw-r--r--spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java53
-rw-r--r--spring-expression/src/main/java/org/springframework/expression/spel/support/StandardTypeConverter.java10
12 files changed, 176 insertions, 126 deletions
diff --git a/spring-expression/src/main/java/org/springframework/expression/BeanResolver.java b/spring-expression/src/main/java/org/springframework/expression/BeanResolver.java
index c95501ba..1f6726f1 100644
--- a/spring-expression/src/main/java/org/springframework/expression/BeanResolver.java
+++ b/spring-expression/src/main/java/org/springframework/expression/BeanResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2016 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,7 +18,9 @@ package org.springframework.expression;
/**
* A bean resolver can be registered with the evaluation context
- * and will kick in for {@code @myBeanName} still expressions.
+ * and will kick in for {@code @myBeanName} and {@code &myBeanName} expressions.
+ * The <tt>&</tt> variant syntax allows access to the factory bean where
+ * relevant.
*
* @author Andy Clement
* @since 3.0.3
@@ -26,7 +28,8 @@ package org.springframework.expression;
public interface BeanResolver {
/**
- * Look up the named bean and return it.
+ * Look up the named bean and return it. If attempting to access a factory
+ * bean the name will have a <tt>&</tt> prefix.
* @param context the current evaluation context
* @param beanName the name of the bean to lookup
* @return an object representing the bean
diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/CodeFlow.java b/spring-expression/src/main/java/org/springframework/expression/spel/CodeFlow.java
index 2d20e195..decb2f1c 100644
--- a/spring-expression/src/main/java/org/springframework/expression/spel/CodeFlow.java
+++ b/spring-expression/src/main/java/org/springframework/expression/spel/CodeFlow.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2015 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -148,6 +148,72 @@ public class CodeFlow implements Opcodes {
}
/**
+ * Called after the main expression evaluation method has been generated, this
+ * method will callback any registered FieldAdders or ClinitAdders to add any
+ * extra information to the class representing the compiled expression.
+ */
+ public void finish() {
+ if (this.fieldAdders != null) {
+ for (FieldAdder fieldAdder : this.fieldAdders) {
+ fieldAdder.generateField(cw,this);
+ }
+ }
+ if (this.clinitAdders != null) {
+ MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "<clinit>", "()V", null, null);
+ mv.visitCode();
+ this.nextFreeVariableId = 0; // To 0 because there is no 'this' in a clinit
+ for (ClinitAdder clinitAdder : this.clinitAdders) {
+ clinitAdder.generateCode(mv, this);
+ }
+ mv.visitInsn(RETURN);
+ mv.visitMaxs(0,0); // not supplied due to COMPUTE_MAXS
+ mv.visitEnd();
+ }
+ }
+
+ /**
+ * Register a FieldAdder which will add a new field to the generated
+ * class to support the code produced by an ast nodes primary
+ * generateCode() method.
+ */
+ public void registerNewField(FieldAdder fieldAdder) {
+ if (this.fieldAdders == null) {
+ this.fieldAdders = new ArrayList<FieldAdder>();
+ }
+ this.fieldAdders.add(fieldAdder);
+ }
+
+ /**
+ * Register a ClinitAdder which will add code to the static
+ * initializer in the generated class to support the code
+ * produced by an ast nodes primary generateCode() method.
+ */
+ public void registerNewClinit(ClinitAdder clinitAdder) {
+ if (this.clinitAdders == null) {
+ this.clinitAdders = new ArrayList<ClinitAdder>();
+ }
+ this.clinitAdders.add(clinitAdder);
+ }
+
+ public int nextFieldId() {
+ return this.nextFieldId++;
+ }
+
+ public int nextFreeVariableId() {
+ return this.nextFreeVariableId++;
+ }
+
+ public String getClassName() {
+ return this.clazzName;
+ }
+
+ @Deprecated
+ public String getClassname() {
+ return this.clazzName;
+ }
+
+
+ /**
* Insert any necessary cast and value call to convert from a boxed type to a
* primitive value
* @param mv the method visitor into which instructions should be inserted
@@ -779,74 +845,6 @@ public class CodeFlow implements Opcodes {
}
/**
- * Called after the main expression evaluation method has been generated, this
- * method will callback any registered FieldAdders or ClinitAdders to add any
- * extra information to the class representing the compiled expression.
- */
- public void finish() {
- if (fieldAdders != null) {
- for (FieldAdder fieldAdder: fieldAdders) {
- fieldAdder.generateField(cw,this);
- }
- }
- if (clinitAdders != null) {
- MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "<clinit>", "()V", null, null);
- mv.visitCode();
- nextFreeVariableId = 0; // To 0 because there is no 'this' in a clinit
- for (ClinitAdder clinitAdder: clinitAdders) {
- clinitAdder.generateCode(mv, this);
- }
- mv.visitInsn(RETURN);
- mv.visitMaxs(0,0); // not supplied due to COMPUTE_MAXS
- mv.visitEnd();
- }
- }
-
- /**
- * Register a FieldAdder which will add a new field to the generated
- * class to support the code produced by an ast nodes primary
- * generateCode() method.
- */
- public void registerNewField(FieldAdder fieldAdder) {
- if (fieldAdders == null) {
- fieldAdders = new ArrayList<FieldAdder>();
- }
- fieldAdders.add(fieldAdder);
- }
-
- /**
- * Register a ClinitAdder which will add code to the static
- * initializer in the generated class to support the code
- * produced by an ast nodes primary generateCode() method.
- */
- public void registerNewClinit(ClinitAdder clinitAdder) {
- if (clinitAdders == null) {
- clinitAdders = new ArrayList<ClinitAdder>();
- }
- clinitAdders.add(clinitAdder);
- }
-
- public int nextFieldId() {
- return nextFieldId++;
- }
-
- public int nextFreeVariableId() {
- return nextFreeVariableId++;
- }
-
- public String getClassname() {
- return clazzName;
- }
-
- public interface FieldAdder {
- public void generateField(ClassWriter cw, CodeFlow codeflow);
- }
-
- public interface ClinitAdder {
- public void generateCode(MethodVisitor mv, CodeFlow codeflow);
- }
-
- /**
* Create the optimal instruction for loading a number on the stack.
* @param mv where to insert the bytecode
* @param value the value to be loaded
@@ -977,4 +975,15 @@ public class CodeFlow implements Opcodes {
}
+ public interface FieldAdder {
+
+ void generateField(ClassWriter cw, CodeFlow codeflow);
+ }
+
+
+ public interface ClinitAdder {
+
+ void generateCode(MethodVisitor mv, CodeFlow codeflow);
+ }
+
}
diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/SpelMessage.java b/spring-expression/src/main/java/org/springframework/expression/spel/SpelMessage.java
index 1431554a..40c7054c 100644
--- a/spring-expression/src/main/java/org/springframework/expression/spel/SpelMessage.java
+++ b/spring-expression/src/main/java/org/springframework/expression/spel/SpelMessage.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2014 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -214,7 +214,7 @@ public enum SpelMessage {
"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"),
+ "@ or & can only be followed by an identifier or a quoted name"),
TYPE_NAME_EXPECTED_FOR_ARRAY_CONSTRUCTION(Kind.ERROR, 1060,
"Expected the type of the new array to be specified as a String but found ''{0}''"),
diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/BeanReference.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/BeanReference.java
index 5f0c8404..67021482 100644
--- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/BeanReference.java
+++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/BeanReference.java
@@ -25,12 +25,15 @@ 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'"
- *
+ * Represents a bean reference to a type, for example <tt>@foo</tt> or <tt>@'foo.bar'</tt>.
+ * For a FactoryBean the syntax <tt>&foo</tt> can be used to access the factory itself.
+ *
* @author Andy Clement
*/
public class BeanReference extends SpelNodeImpl {
+ private final static String FACTORY_BEAN_PREFIX = "&";
+
private final String beanName;
@@ -59,7 +62,10 @@ public class BeanReference extends SpelNodeImpl {
@Override
public String toStringAST() {
- StringBuilder sb = new StringBuilder("@");
+ StringBuilder sb = new StringBuilder();
+ if (!this.beanName.startsWith(FACTORY_BEAN_PREFIX)) {
+ sb.append("@");
+ }
if (!this.beanName.contains(".")) {
sb.append(this.beanName);
}
diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java
index ae15a6f1..32a837ea 100644
--- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java
+++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2015 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -694,7 +694,7 @@ public class Indexer extends SpelNodeImpl {
newElements--;
}
}
- catch (Exception ex) {
+ catch (Throwable ex) {
throw new SpelEvaluationException(getStartPosition(), ex, SpelMessage.UNABLE_TO_GROW_COLLECTION);
}
}
diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/InlineList.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/InlineList.java
index b4134b63..1a435b86 100644
--- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/InlineList.java
+++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/InlineList.java
@@ -132,8 +132,8 @@ public class InlineList extends SpelNodeImpl {
@Override
public void generateCode(MethodVisitor mv, CodeFlow codeflow) {
- final String constantFieldName = "inlineList$"+codeflow.nextFieldId();
- final String clazzname = codeflow.getClassname();
+ final String constantFieldName = "inlineList$" + codeflow.nextFieldId();
+ final String className = codeflow.getClassName();
codeflow.registerNewField(new CodeFlow.FieldAdder() {
public void generateField(ClassWriter cw, CodeFlow codeflow) {
@@ -143,11 +143,11 @@ public class InlineList extends SpelNodeImpl {
codeflow.registerNewClinit(new CodeFlow.ClinitAdder() {
public void generateCode(MethodVisitor mv, CodeFlow codeflow) {
- generateClinitCode(clazzname,constantFieldName, mv,codeflow,false);
+ generateClinitCode(className, constantFieldName, mv, codeflow, false);
}
});
- mv.visitFieldInsn(GETSTATIC, clazzname, constantFieldName, "Ljava/util/List;");
+ mv.visitFieldInsn(GETSTATIC, className, constantFieldName, "Ljava/util/List;");
codeflow.pushDescriptor("Ljava/util/List");
}
@@ -158,8 +158,8 @@ public class InlineList extends SpelNodeImpl {
if (!nested) {
mv.visitFieldInsn(PUTSTATIC, clazzname, constantFieldName, "Ljava/util/List;");
}
- int childcount = getChildCount();
- for (int c=0; c < childcount; c++) {
+ int childCount = getChildCount();
+ for (int c = 0; c < childCount; c++) {
if (!nested) {
mv.visitFieldInsn(GETSTATIC, clazzname, constantFieldName, "Ljava/util/List;");
}
diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OperatorInstanceof.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OperatorInstanceof.java
index 5a3063b6..6c880bdd 100644
--- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OperatorInstanceof.java
+++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OperatorInstanceof.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2014 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -53,8 +53,9 @@ public class OperatorInstanceof extends Operator {
*/
@Override
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
+ SpelNodeImpl rightOperand = getRightOperand();
TypedValue left = getLeftOperand().getValueInternal(state);
- TypedValue right = getRightOperand().getValueInternal(state);
+ TypedValue right = rightOperand.getValueInternal(state);
Object leftValue = left.getValue();
Object rightValue = right.getValue();
BooleanTypedValue result = null;
@@ -71,7 +72,11 @@ public class OperatorInstanceof extends Operator {
result = BooleanTypedValue.forValue(rightClass.isAssignableFrom(leftValue.getClass()));
}
this.type = rightClass;
- this.exitTypeDescriptor = "Z";
+ if (rightOperand instanceof TypeReference) {
+ // Can only generate bytecode where the right operand is a direct type reference,
+ // not if it is indirect (for example when right operand is a variable reference)
+ this.exitTypeDescriptor = "Z";
+ }
return result;
}
@@ -83,7 +88,16 @@ public class OperatorInstanceof extends Operator {
@Override
public void generateCode(MethodVisitor mv, CodeFlow cf) {
getLeftOperand().generateCode(mv, cf);
- mv.visitTypeInsn(INSTANCEOF,Type.getInternalName(this.type));
+ CodeFlow.insertBoxIfNecessary(mv, cf.lastDescriptor());
+ if (this.type.isPrimitive()) {
+ // always false - but left operand code always driven
+ // in case it had side effects
+ mv.visitInsn(POP);
+ mv.visitInsn(ICONST_0); // value of false
+ }
+ else {
+ mv.visitTypeInsn(INSTANCEOF,Type.getInternalName(this.type));
+ }
cf.pushDescriptor(this.exitTypeDescriptor);
}
diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/standard/InternalSpelExpressionParser.java b/spring-expression/src/main/java/org/springframework/expression/spel/standard/InternalSpelExpressionParser.java
index 8531aa0d..600ffda6 100644
--- a/spring-expression/src/main/java/org/springframework/expression/spel/standard/InternalSpelExpressionParser.java
+++ b/spring-expression/src/main/java/org/springframework/expression/spel/standard/InternalSpelExpressionParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2015 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -525,7 +525,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
// parse: @beanname @'bean.name'
// quoted if dotted
private boolean maybeEatBeanReference() {
- if (peekToken(TokenKind.BEAN_REF)) {
+ if (peekToken(TokenKind.BEAN_REF) || peekToken(TokenKind.FACTORY_BEAN_REF)) {
Token beanRefToken = nextToken();
Token beanNameToken = null;
String beanName = null;
@@ -543,7 +543,14 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
SpelMessage.INVALID_BEAN_REFERENCE);
}
- BeanReference beanReference = new BeanReference(toPos(beanNameToken) ,beanName);
+ BeanReference beanReference = null;
+ if (beanRefToken.getKind() == TokenKind.FACTORY_BEAN_REF) {
+ String beanNameString = new StringBuilder().append(TokenKind.FACTORY_BEAN_REF.tokenChars).append(beanName).toString();
+ beanReference = new BeanReference(toPos(beanRefToken.startPos,beanNameToken.endPos),beanNameString);
+ }
+ else {
+ beanReference = new BeanReference(toPos(beanNameToken) ,beanName);
+ }
this.constructedNodes.push(beanReference);
return true;
}
diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/standard/TokenKind.java b/spring-expression/src/main/java/org/springframework/expression/spel/standard/TokenKind.java
index 4a31941e..0b577554 100644
--- a/spring-expression/src/main/java/org/springframework/expression/spel/standard/TokenKind.java
+++ b/spring-expression/src/main/java/org/springframework/expression/spel/standard/TokenKind.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2014 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -112,6 +112,8 @@ enum TokenKind {
BEAN_REF("@"),
+ FACTORY_BEAN_REF("&"),
+
SYMBOLIC_OR("||"),
SYMBOLIC_AND("&&"),
diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/standard/Tokenizer.java b/spring-expression/src/main/java/org/springframework/expression/spel/standard/Tokenizer.java
index fb912228..e0408f10 100644
--- a/spring-expression/src/main/java/org/springframework/expression/spel/standard/Tokenizer.java
+++ b/spring-expression/src/main/java/org/springframework/expression/spel/standard/Tokenizer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2013 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -182,12 +182,12 @@ class Tokenizer {
}
break;
case '&':
- if (!isTwoCharToken(TokenKind.SYMBOLIC_AND)) {
- throw new InternalParseException(new SpelParseException(
- this.expressionString, this.pos, SpelMessage.MISSING_CHARACTER,
- "&"));
+ if (isTwoCharToken(TokenKind.SYMBOLIC_AND)) {
+ pushPairToken(TokenKind.SYMBOLIC_AND);
+ }
+ else {
+ pushCharToken(TokenKind.FACTORY_BEAN_REF);
}
- pushPairToken(TokenKind.SYMBOLIC_AND);
break;
case '|':
if (!isTwoCharToken(TokenKind.SYMBOLIC_OR)) {
diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java
index 4a3a5cfe..8cb54e8f 100644
--- a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java
+++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2015 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -33,7 +33,6 @@ import org.springframework.asm.MethodVisitor;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.Property;
import org.springframework.core.convert.TypeDescriptor;
-import org.springframework.core.style.ToStringCreator;
import org.springframework.expression.AccessException;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException;
@@ -70,11 +69,14 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
}
- private final Map<CacheKey, InvokerPair> readerCache = new ConcurrentHashMap<CacheKey, InvokerPair>(64);
+ private final Map<PropertyCacheKey, InvokerPair> readerCache =
+ new ConcurrentHashMap<PropertyCacheKey, InvokerPair>(64);
- private final Map<CacheKey, Member> writerCache = new ConcurrentHashMap<CacheKey, Member>(64);
+ private final Map<PropertyCacheKey, Member> writerCache =
+ new ConcurrentHashMap<PropertyCacheKey, Member>(64);
- private final Map<CacheKey, TypeDescriptor> typeDescriptorCache = new ConcurrentHashMap<CacheKey, TypeDescriptor>(64);
+ private final Map<PropertyCacheKey, TypeDescriptor> typeDescriptorCache =
+ new ConcurrentHashMap<PropertyCacheKey, TypeDescriptor>(64);
private InvokerPair lastReadInvokerPair;
@@ -96,7 +98,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
if (type.isArray() && name.equals("length")) {
return true;
}
- CacheKey cacheKey = new CacheKey(type, name, target instanceof Class);
+ PropertyCacheKey cacheKey = new PropertyCacheKey(type, name, target instanceof Class);
if (this.readerCache.containsKey(cacheKey)) {
return true;
}
@@ -140,7 +142,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
return new TypedValue(Array.getLength(target));
}
- CacheKey cacheKey = new CacheKey(type, name, target instanceof Class);
+ PropertyCacheKey cacheKey = new PropertyCacheKey(type, name, target instanceof Class);
InvokerPair invoker = this.readerCache.get(cacheKey);
lastReadInvokerPair = invoker;
@@ -202,7 +204,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
return false;
}
Class<?> type = (target instanceof Class ? (Class<?>) target : target.getClass());
- CacheKey cacheKey = new CacheKey(type, name, target instanceof Class);
+ PropertyCacheKey cacheKey = new PropertyCacheKey(type, name, target instanceof Class);
if (this.writerCache.containsKey(cacheKey)) {
return true;
}
@@ -244,7 +246,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
throw new AccessException("Type conversion failure", evaluationException);
}
}
- CacheKey cacheKey = new CacheKey(type, name, target instanceof Class);
+ PropertyCacheKey cacheKey = new PropertyCacheKey(type, name, target instanceof Class);
Member cachedMember = this.writerCache.get(cacheKey);
if (cachedMember == null || cachedMember instanceof Method) {
@@ -301,7 +303,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
if (type.isArray() && name.equals("length")) {
return TypeDescriptor.valueOf(Integer.TYPE);
}
- CacheKey cacheKey = new CacheKey(type, name, target instanceof Class);
+ PropertyCacheKey cacheKey = new PropertyCacheKey(type, name, target instanceof Class);
TypeDescriptor typeDescriptor = this.typeDescriptorCache.get(cacheKey);
if (typeDescriptor == null) {
// attempt to populate the cache entry
@@ -466,7 +468,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
return this;
}
- CacheKey cacheKey = new CacheKey(type, name, target instanceof Class);
+ PropertyCacheKey cacheKey = new PropertyCacheKey(type, name, target instanceof Class);
InvokerPair invocationTarget = this.readerCache.get(cacheKey);
if (invocationTarget == null || invocationTarget.member instanceof Method) {
@@ -520,17 +522,17 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
}
- private static class CacheKey {
+ private static final class PropertyCacheKey implements Comparable<PropertyCacheKey> {
private final Class<?> clazz;
- private final String name;
+ private final String property;
private boolean targetIsClass;
- public CacheKey(Class<?> clazz, String name, boolean targetIsClass) {
+ public PropertyCacheKey(Class<?> clazz, String name, boolean targetIsClass) {
this.clazz = clazz;
- this.name = name;
+ this.property = name;
this.targetIsClass = targetIsClass;
}
@@ -539,23 +541,32 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
if (this == other) {
return true;
}
- if (!(other instanceof CacheKey)) {
+ if (!(other instanceof PropertyCacheKey)) {
return false;
}
- CacheKey otherKey = (CacheKey) other;
- return (this.clazz.equals(otherKey.clazz) && this.name.equals(otherKey.name) &&
+ PropertyCacheKey otherKey = (PropertyCacheKey) other;
+ return (this.clazz == otherKey.clazz && this.property.equals(otherKey.property) &&
this.targetIsClass == otherKey.targetIsClass);
}
@Override
public int hashCode() {
- return (this.clazz.hashCode() * 29 + this.name.hashCode());
+ return (this.clazz.hashCode() * 29 + this.property.hashCode());
}
@Override
public String toString() {
- return new ToStringCreator(this).append("clazz", this.clazz).append("name",
- this.name).append("targetIsClass", this.targetIsClass).toString();
+ return "CacheKey [clazz=" + this.clazz.getName() + ", property=" + this.property + ", " +
+ this.property + ", targetIsClass=" + this.targetIsClass + "]";
+ }
+
+ @Override
+ public int compareTo(PropertyCacheKey other) {
+ int result = this.clazz.getName().compareTo(other.clazz.getName());
+ if (result == 0) {
+ result = this.property.compareTo(other.property);
+ }
+ return result;
}
}
diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/StandardTypeConverter.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/StandardTypeConverter.java
index 690a7e57..253e4bb3 100644
--- a/spring-expression/src/main/java/org/springframework/expression/spel/support/StandardTypeConverter.java
+++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/StandardTypeConverter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2013 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -36,7 +36,7 @@ import org.springframework.util.Assert;
*/
public class StandardTypeConverter implements TypeConverter {
- private static ConversionService defaultConversionService;
+ private static volatile ConversionService defaultConversionService;
private final ConversionService conversionService;
@@ -45,10 +45,8 @@ public class StandardTypeConverter implements TypeConverter {
* Create a StandardTypeConverter for the default ConversionService.
*/
public StandardTypeConverter() {
- synchronized (this) {
- if (defaultConversionService == null) {
- defaultConversionService = new DefaultConversionService();
- }
+ if (defaultConversionService == null) {
+ defaultConversionService = new DefaultConversionService();
}
this.conversionService = defaultConversionService;
}