Mixed polishing along with recent changes
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2011 the original author or authors.
|
* Copyright 2002-2014 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -29,13 +29,13 @@ public interface CacheManager {
|
|||||||
/**
|
/**
|
||||||
* Return the cache associated with the given name.
|
* Return the cache associated with the given name.
|
||||||
* @param name cache identifier (must not be {@code null})
|
* @param name cache identifier (must not be {@code null})
|
||||||
* @return associated cache, or {@code null} if none is found
|
* @return the associated cache, or {@code null} if none is found
|
||||||
*/
|
*/
|
||||||
Cache getCache(String name);
|
Cache getCache(String name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a collection of the caches known by this cache manager.
|
* Return a collection of the caches known by this cache manager.
|
||||||
* @return names of caches known by the cache manager.
|
* @return names of caches known by the cache manager
|
||||||
*/
|
*/
|
||||||
Collection<String> getCacheNames();
|
Collection<String> getCacheNames();
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2002-2014 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -30,9 +30,10 @@ import org.springframework.expression.spel.SpelEvaluationException;
|
|||||||
public class CompoundExpression extends SpelNodeImpl {
|
public class CompoundExpression extends SpelNodeImpl {
|
||||||
|
|
||||||
public CompoundExpression(int pos,SpelNodeImpl... expressionComponents) {
|
public CompoundExpression(int pos,SpelNodeImpl... expressionComponents) {
|
||||||
super(pos,expressionComponents);
|
super(pos, expressionComponents);
|
||||||
if (expressionComponents.length<2) {
|
if (expressionComponents.length < 2) {
|
||||||
throw new IllegalStateException("Dont build compound expression less than one entry: "+expressionComponents.length);
|
throw new IllegalStateException("Do not build compound expression less than one entry: " +
|
||||||
|
expressionComponents.length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,11 +43,9 @@ public class CompoundExpression extends SpelNodeImpl {
|
|||||||
if (getChildCount() == 1) {
|
if (getChildCount() == 1) {
|
||||||
return this.children[0].getValueRef(state);
|
return this.children[0].getValueRef(state);
|
||||||
}
|
}
|
||||||
TypedValue result = null;
|
SpelNodeImpl nextNode = this.children[0];
|
||||||
SpelNodeImpl nextNode = null;
|
|
||||||
try {
|
try {
|
||||||
nextNode = this.children[0];
|
TypedValue result = nextNode.getValueInternal(state);
|
||||||
result = nextNode.getValueInternal(state);
|
|
||||||
int cc = getChildCount();
|
int cc = getChildCount();
|
||||||
for (int i = 1; i < cc - 1; i++) {
|
for (int i = 1; i < cc - 1; i++) {
|
||||||
try {
|
try {
|
||||||
@@ -75,8 +74,8 @@ public class CompoundExpression extends SpelNodeImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluates a compound expression. This involves evaluating each piece in turn and the return value from each piece
|
* Evaluates a compound expression. This involves evaluating each piece in turn and the
|
||||||
* is the active context object for the subsequent piece.
|
* return value from each piece is the active context object for the subsequent piece.
|
||||||
* @param state the state in which the expression is being evaluated
|
* @param state the state in which the expression is being evaluated
|
||||||
* @return the final value from the last piece of the compound expression
|
* @return the final value from the last piece of the compound expression
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2002-2014 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -34,7 +34,7 @@ import org.springframework.expression.spel.support.ReflectivePropertyAccessor;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* An Indexer can index into some proceeding structure to access a particular piece of it.
|
* An Indexer can index into some proceeding structure to access a particular piece of it.
|
||||||
* Supported structures are: strings/collections (lists/sets)/arrays
|
* Supported structures are: strings / collections (lists/sets) / arrays.
|
||||||
*
|
*
|
||||||
* @author Andy Clement
|
* @author Andy Clement
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
@@ -88,319 +88,8 @@ public class Indexer extends SpelNodeImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private class ArrayIndexingValueRef implements ValueRef {
|
|
||||||
|
|
||||||
private final TypeConverter typeConverter;
|
|
||||||
|
|
||||||
private final Object array;
|
|
||||||
|
|
||||||
private final int index;
|
|
||||||
|
|
||||||
private final TypeDescriptor typeDescriptor;
|
|
||||||
|
|
||||||
|
|
||||||
ArrayIndexingValueRef(TypeConverter typeConverter, Object array, int index, TypeDescriptor typeDescriptor) {
|
|
||||||
this.typeConverter = typeConverter;
|
|
||||||
this.array = array;
|
|
||||||
this.index = index;
|
|
||||||
this.typeDescriptor = typeDescriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypedValue getValue() {
|
|
||||||
Object arrayElement = accessArrayElement(this.array, this.index);
|
|
||||||
return new TypedValue(arrayElement, this.typeDescriptor.elementTypeDescriptor(arrayElement));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setValue(Object newValue) {
|
|
||||||
setArrayElement(this.typeConverter, this.array, this.index, newValue,
|
|
||||||
this.typeDescriptor.getElementTypeDescriptor().getType());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isWritable() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
|
||||||
private class MapIndexingValueRef implements ValueRef {
|
|
||||||
|
|
||||||
private final TypeConverter typeConverter;
|
|
||||||
|
|
||||||
private final Map map;
|
|
||||||
|
|
||||||
private final Object key;
|
|
||||||
|
|
||||||
private final TypeDescriptor mapEntryTypeDescriptor;
|
|
||||||
|
|
||||||
|
|
||||||
MapIndexingValueRef(TypeConverter typeConverter, Map map, Object key,
|
|
||||||
TypeDescriptor mapEntryTypeDescriptor) {
|
|
||||||
this.typeConverter = typeConverter;
|
|
||||||
this.map = map;
|
|
||||||
this.key = key;
|
|
||||||
this.mapEntryTypeDescriptor = mapEntryTypeDescriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypedValue getValue() {
|
|
||||||
Object value = this.map.get(this.key);
|
|
||||||
return new TypedValue(value,
|
|
||||||
this.mapEntryTypeDescriptor.getMapValueTypeDescriptor(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setValue(Object newValue) {
|
|
||||||
if (this.mapEntryTypeDescriptor.getMapValueTypeDescriptor() != null) {
|
|
||||||
newValue = this.typeConverter.convertValue(newValue, TypeDescriptor.forObject(newValue),
|
|
||||||
this.mapEntryTypeDescriptor.getMapValueTypeDescriptor());
|
|
||||||
}
|
|
||||||
this.map.put(this.key, newValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isWritable() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private class PropertyIndexingValueRef implements ValueRef {
|
|
||||||
|
|
||||||
private final Object targetObject;
|
|
||||||
|
|
||||||
private final String name;
|
|
||||||
|
|
||||||
private final EvaluationContext evaluationContext;
|
|
||||||
|
|
||||||
private final TypeDescriptor targetObjectTypeDescriptor;
|
|
||||||
|
|
||||||
|
|
||||||
public PropertyIndexingValueRef(Object targetObject, String value, EvaluationContext evaluationContext,
|
|
||||||
TypeDescriptor targetObjectTypeDescriptor) {
|
|
||||||
this.targetObject = targetObject;
|
|
||||||
this.name = value;
|
|
||||||
this.evaluationContext = evaluationContext;
|
|
||||||
this.targetObjectTypeDescriptor = targetObjectTypeDescriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypedValue getValue() {
|
|
||||||
Class<?> targetObjectRuntimeClass = getObjectClass(this.targetObject);
|
|
||||||
try {
|
|
||||||
if (Indexer.this.cachedReadName != null && Indexer.this.cachedReadName.equals(this.name) && Indexer.this.cachedReadTargetType != null &&
|
|
||||||
Indexer.this.cachedReadTargetType.equals(targetObjectRuntimeClass)) {
|
|
||||||
// it is OK to use the cached accessor
|
|
||||||
return Indexer.this.cachedReadAccessor.read(this.evaluationContext, this.targetObject, this.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<PropertyAccessor> accessorsToTry = AstUtils.getPropertyAccessorsToTry(
|
|
||||||
targetObjectRuntimeClass, this.evaluationContext.getPropertyAccessors());
|
|
||||||
|
|
||||||
if (accessorsToTry != null) {
|
|
||||||
for (PropertyAccessor accessor : accessorsToTry) {
|
|
||||||
if (accessor.canRead(this.evaluationContext, this.targetObject, this.name)) {
|
|
||||||
if (accessor instanceof ReflectivePropertyAccessor) {
|
|
||||||
accessor = ((ReflectivePropertyAccessor) accessor).createOptimalAccessor(
|
|
||||||
this.evaluationContext, this.targetObject, this.name);
|
|
||||||
}
|
|
||||||
Indexer.this.cachedReadAccessor = accessor;
|
|
||||||
Indexer.this.cachedReadName = this.name;
|
|
||||||
Indexer.this.cachedReadTargetType = targetObjectRuntimeClass;
|
|
||||||
return accessor.read(this.evaluationContext, this.targetObject, this.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (AccessException ex) {
|
|
||||||
throw new SpelEvaluationException(getStartPosition(), ex, SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE,
|
|
||||||
this.targetObjectTypeDescriptor.toString());
|
|
||||||
}
|
|
||||||
throw new SpelEvaluationException(getStartPosition(), SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE,
|
|
||||||
this.targetObjectTypeDescriptor.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setValue(Object newValue) {
|
|
||||||
Class<?> contextObjectClass = getObjectClass(this.targetObject);
|
|
||||||
try {
|
|
||||||
if (Indexer.this.cachedWriteName != null && Indexer.this.cachedWriteName.equals(this.name) && Indexer.this.cachedWriteTargetType != null &&
|
|
||||||
Indexer.this.cachedWriteTargetType.equals(contextObjectClass)) {
|
|
||||||
// it is OK to use the cached accessor
|
|
||||||
Indexer.this.cachedWriteAccessor.write(this.evaluationContext, this.targetObject, this.name, newValue);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
List<PropertyAccessor> accessorsToTry =
|
|
||||||
AstUtils.getPropertyAccessorsToTry(contextObjectClass, this.evaluationContext.getPropertyAccessors());
|
|
||||||
if (accessorsToTry != null) {
|
|
||||||
for (PropertyAccessor accessor : accessorsToTry) {
|
|
||||||
if (accessor.canWrite(this.evaluationContext, this.targetObject, this.name)) {
|
|
||||||
Indexer.this.cachedWriteName = this.name;
|
|
||||||
Indexer.this.cachedWriteTargetType = contextObjectClass;
|
|
||||||
Indexer.this.cachedWriteAccessor = accessor;
|
|
||||||
accessor.write(this.evaluationContext, this.targetObject, this.name, newValue);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (AccessException ex) {
|
|
||||||
throw new SpelEvaluationException(getStartPosition(), ex, SpelMessage.EXCEPTION_DURING_PROPERTY_WRITE,
|
|
||||||
this.name, ex.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isWritable() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
|
||||||
private class CollectionIndexingValueRef implements ValueRef {
|
|
||||||
|
|
||||||
private final Collection collection;
|
|
||||||
|
|
||||||
private final int index;
|
|
||||||
|
|
||||||
private final TypeDescriptor collectionEntryTypeDescriptor;
|
|
||||||
|
|
||||||
private final TypeConverter typeConverter;
|
|
||||||
|
|
||||||
private final boolean growCollection;
|
|
||||||
|
|
||||||
private final int maximumSize;
|
|
||||||
|
|
||||||
|
|
||||||
CollectionIndexingValueRef(Collection collection, int index, TypeDescriptor collectionEntryTypeDescriptor,
|
|
||||||
TypeConverter typeConverter, boolean growCollection, int maximumSize) {
|
|
||||||
this.collection = collection;
|
|
||||||
this.index = index;
|
|
||||||
this.collectionEntryTypeDescriptor = collectionEntryTypeDescriptor;
|
|
||||||
this.typeConverter = typeConverter;
|
|
||||||
this.growCollection = growCollection;
|
|
||||||
this.maximumSize = maximumSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypedValue getValue() {
|
|
||||||
growCollectionIfNecessary();
|
|
||||||
if (this.collection instanceof List) {
|
|
||||||
Object o = ((List) this.collection).get(this.index);
|
|
||||||
return new TypedValue(o, this.collectionEntryTypeDescriptor.elementTypeDescriptor(o));
|
|
||||||
}
|
|
||||||
int pos = 0;
|
|
||||||
for (Object o : this.collection) {
|
|
||||||
if (pos == this.index) {
|
|
||||||
return new TypedValue(o, this.collectionEntryTypeDescriptor.elementTypeDescriptor(o));
|
|
||||||
}
|
|
||||||
pos++;
|
|
||||||
}
|
|
||||||
throw new IllegalStateException("Failed to find indexed element " + this.index + ": " + this.collection);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setValue(Object newValue) {
|
|
||||||
growCollectionIfNecessary();
|
|
||||||
if (this.collection instanceof List) {
|
|
||||||
List list = (List) this.collection;
|
|
||||||
if (this.collectionEntryTypeDescriptor.getElementTypeDescriptor() != null) {
|
|
||||||
newValue = this.typeConverter.convertValue(newValue, TypeDescriptor.forObject(newValue),
|
|
||||||
this.collectionEntryTypeDescriptor.getElementTypeDescriptor());
|
|
||||||
}
|
|
||||||
list.set(this.index, newValue);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new SpelEvaluationException(getStartPosition(), SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE,
|
|
||||||
this.collectionEntryTypeDescriptor.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isWritable() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private class StringIndexingLValue implements ValueRef {
|
|
||||||
|
|
||||||
private final String target;
|
|
||||||
|
|
||||||
private final int index;
|
|
||||||
|
|
||||||
private final TypeDescriptor typeDescriptor;
|
|
||||||
|
|
||||||
|
|
||||||
public StringIndexingLValue(String target, int index, TypeDescriptor typeDescriptor) {
|
|
||||||
this.target = target;
|
|
||||||
this.index = index;
|
|
||||||
this.typeDescriptor = typeDescriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TypedValue getValue() {
|
|
||||||
if (this.index >= this.target.length()) {
|
|
||||||
throw new SpelEvaluationException(getStartPosition(), SpelMessage.STRING_INDEX_OUT_OF_BOUNDS,
|
|
||||||
this.target.length(), this.index);
|
|
||||||
}
|
|
||||||
return new TypedValue(String.valueOf(this.target.charAt(this.index)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setValue(Object newValue) {
|
|
||||||
throw new SpelEvaluationException(getStartPosition(), SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE,
|
|
||||||
this.typeDescriptor.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isWritable() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ValueRef getValueRef(ExpressionState state) throws EvaluationException {
|
protected ValueRef getValueRef(ExpressionState state) throws EvaluationException {
|
||||||
|
|
||||||
TypedValue context = state.getActiveContextObject();
|
TypedValue context = state.getActiveContextObject();
|
||||||
Object targetObject = context.getValue();
|
Object targetObject = context.getValue();
|
||||||
TypeDescriptor targetObjectTypeDescriptor = context.getTypeDescriptor();
|
TypeDescriptor targetObjectTypeDescriptor = context.getTypeDescriptor();
|
||||||
@@ -483,9 +172,9 @@ public class Indexer extends SpelNodeImpl {
|
|||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setArrayElement(TypeConverter converter, Object ctx, int idx, Object newValue, Class<?> clazz)
|
private void setArrayElement(TypeConverter converter, Object ctx, int idx, Object newValue,
|
||||||
throws EvaluationException {
|
Class<?> arrayComponentType) throws EvaluationException {
|
||||||
Class<?> arrayComponentType = clazz;
|
|
||||||
if (arrayComponentType == Integer.TYPE) {
|
if (arrayComponentType == Integer.TYPE) {
|
||||||
int[] array = (int[]) ctx;
|
int[] array = (int[]) ctx;
|
||||||
checkAccess(array.length, idx);
|
checkAccess(array.length, idx);
|
||||||
@@ -538,7 +227,7 @@ public class Indexer extends SpelNodeImpl {
|
|||||||
Object[] array = (Object[]) ctx;
|
Object[] array = (Object[]) ctx;
|
||||||
checkAccess(array.length, idx);
|
checkAccess(array.length, idx);
|
||||||
array[idx] = converter.convertValue(newValue, TypeDescriptor.forObject(newValue),
|
array[idx] = converter.convertValue(newValue, TypeDescriptor.forObject(newValue),
|
||||||
TypeDescriptor.valueOf(clazz));
|
TypeDescriptor.valueOf(arrayComponentType));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -598,4 +287,304 @@ public class Indexer extends SpelNodeImpl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private class ArrayIndexingValueRef implements ValueRef {
|
||||||
|
|
||||||
|
private final TypeConverter typeConverter;
|
||||||
|
|
||||||
|
private final Object array;
|
||||||
|
|
||||||
|
private final int index;
|
||||||
|
|
||||||
|
private final TypeDescriptor typeDescriptor;
|
||||||
|
|
||||||
|
|
||||||
|
ArrayIndexingValueRef(TypeConverter typeConverter, Object array, int index, TypeDescriptor typeDescriptor) {
|
||||||
|
this.typeConverter = typeConverter;
|
||||||
|
this.array = array;
|
||||||
|
this.index = index;
|
||||||
|
this.typeDescriptor = typeDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypedValue getValue() {
|
||||||
|
Object arrayElement = accessArrayElement(this.array, this.index);
|
||||||
|
return new TypedValue(arrayElement, this.typeDescriptor.elementTypeDescriptor(arrayElement));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setValue(Object newValue) {
|
||||||
|
setArrayElement(this.typeConverter, this.array, this.index, newValue,
|
||||||
|
this.typeDescriptor.getElementTypeDescriptor().getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isWritable() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||||
|
private static class MapIndexingValueRef implements ValueRef {
|
||||||
|
|
||||||
|
private final TypeConverter typeConverter;
|
||||||
|
|
||||||
|
private final Map map;
|
||||||
|
|
||||||
|
private final Object key;
|
||||||
|
|
||||||
|
private final TypeDescriptor mapEntryTypeDescriptor;
|
||||||
|
|
||||||
|
public MapIndexingValueRef(TypeConverter typeConverter, Map map, Object key, TypeDescriptor mapEntryTypeDescriptor) {
|
||||||
|
this.typeConverter = typeConverter;
|
||||||
|
this.map = map;
|
||||||
|
this.key = key;
|
||||||
|
this.mapEntryTypeDescriptor = mapEntryTypeDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypedValue getValue() {
|
||||||
|
Object value = this.map.get(this.key);
|
||||||
|
return new TypedValue(value,
|
||||||
|
this.mapEntryTypeDescriptor.getMapValueTypeDescriptor(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setValue(Object newValue) {
|
||||||
|
if (this.mapEntryTypeDescriptor.getMapValueTypeDescriptor() != null) {
|
||||||
|
newValue = this.typeConverter.convertValue(newValue, TypeDescriptor.forObject(newValue),
|
||||||
|
this.mapEntryTypeDescriptor.getMapValueTypeDescriptor());
|
||||||
|
}
|
||||||
|
this.map.put(this.key, newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isWritable() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private class PropertyIndexingValueRef implements ValueRef {
|
||||||
|
|
||||||
|
private final Object targetObject;
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
private final EvaluationContext evaluationContext;
|
||||||
|
|
||||||
|
private final TypeDescriptor targetObjectTypeDescriptor;
|
||||||
|
|
||||||
|
public PropertyIndexingValueRef(Object targetObject, String value, EvaluationContext evaluationContext,
|
||||||
|
TypeDescriptor targetObjectTypeDescriptor) {
|
||||||
|
this.targetObject = targetObject;
|
||||||
|
this.name = value;
|
||||||
|
this.evaluationContext = evaluationContext;
|
||||||
|
this.targetObjectTypeDescriptor = targetObjectTypeDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypedValue getValue() {
|
||||||
|
Class<?> targetObjectRuntimeClass = getObjectClass(this.targetObject);
|
||||||
|
try {
|
||||||
|
if (Indexer.this.cachedReadName != null && Indexer.this.cachedReadName.equals(this.name) &&
|
||||||
|
Indexer.this.cachedReadTargetType != null &&
|
||||||
|
Indexer.this.cachedReadTargetType.equals(targetObjectRuntimeClass)) {
|
||||||
|
// It is OK to use the cached accessor
|
||||||
|
return Indexer.this.cachedReadAccessor.read(this.evaluationContext, this.targetObject, this.name);
|
||||||
|
}
|
||||||
|
List<PropertyAccessor> accessorsToTry = AstUtils.getPropertyAccessorsToTry(
|
||||||
|
targetObjectRuntimeClass, this.evaluationContext.getPropertyAccessors());
|
||||||
|
if (accessorsToTry != null) {
|
||||||
|
for (PropertyAccessor accessor : accessorsToTry) {
|
||||||
|
if (accessor.canRead(this.evaluationContext, this.targetObject, this.name)) {
|
||||||
|
if (accessor instanceof ReflectivePropertyAccessor) {
|
||||||
|
accessor = ((ReflectivePropertyAccessor) accessor).createOptimalAccessor(
|
||||||
|
this.evaluationContext, this.targetObject, this.name);
|
||||||
|
}
|
||||||
|
Indexer.this.cachedReadAccessor = accessor;
|
||||||
|
Indexer.this.cachedReadName = this.name;
|
||||||
|
Indexer.this.cachedReadTargetType = targetObjectRuntimeClass;
|
||||||
|
return accessor.read(this.evaluationContext, this.targetObject, this.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (AccessException ex) {
|
||||||
|
throw new SpelEvaluationException(getStartPosition(), ex, SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE,
|
||||||
|
this.targetObjectTypeDescriptor.toString());
|
||||||
|
}
|
||||||
|
throw new SpelEvaluationException(getStartPosition(), SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE,
|
||||||
|
this.targetObjectTypeDescriptor.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setValue(Object newValue) {
|
||||||
|
Class<?> contextObjectClass = getObjectClass(this.targetObject);
|
||||||
|
try {
|
||||||
|
if (Indexer.this.cachedWriteName != null && Indexer.this.cachedWriteName.equals(this.name) &&
|
||||||
|
Indexer.this.cachedWriteTargetType != null &&
|
||||||
|
Indexer.this.cachedWriteTargetType.equals(contextObjectClass)) {
|
||||||
|
// It is OK to use the cached accessor
|
||||||
|
Indexer.this.cachedWriteAccessor.write(this.evaluationContext, this.targetObject, this.name, newValue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<PropertyAccessor> accessorsToTry =
|
||||||
|
AstUtils.getPropertyAccessorsToTry(contextObjectClass, this.evaluationContext.getPropertyAccessors());
|
||||||
|
if (accessorsToTry != null) {
|
||||||
|
for (PropertyAccessor accessor : accessorsToTry) {
|
||||||
|
if (accessor.canWrite(this.evaluationContext, this.targetObject, this.name)) {
|
||||||
|
Indexer.this.cachedWriteName = this.name;
|
||||||
|
Indexer.this.cachedWriteTargetType = contextObjectClass;
|
||||||
|
Indexer.this.cachedWriteAccessor = accessor;
|
||||||
|
accessor.write(this.evaluationContext, this.targetObject, this.name, newValue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (AccessException ex) {
|
||||||
|
throw new SpelEvaluationException(getStartPosition(), ex, SpelMessage.EXCEPTION_DURING_PROPERTY_WRITE,
|
||||||
|
this.name, ex.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isWritable() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
|
private class CollectionIndexingValueRef implements ValueRef {
|
||||||
|
|
||||||
|
private final Collection collection;
|
||||||
|
|
||||||
|
private final int index;
|
||||||
|
|
||||||
|
private final TypeDescriptor collectionEntryDescriptor;
|
||||||
|
|
||||||
|
private final TypeConverter typeConverter;
|
||||||
|
|
||||||
|
private final boolean growCollection;
|
||||||
|
|
||||||
|
private final int maximumSize;
|
||||||
|
|
||||||
|
public CollectionIndexingValueRef(Collection collection, int index, TypeDescriptor collectionEntryTypeDescriptor,
|
||||||
|
TypeConverter typeConverter, boolean growCollection, int maximumSize) {
|
||||||
|
this.collection = collection;
|
||||||
|
this.index = index;
|
||||||
|
this.collectionEntryDescriptor = collectionEntryTypeDescriptor;
|
||||||
|
this.typeConverter = typeConverter;
|
||||||
|
this.growCollection = growCollection;
|
||||||
|
this.maximumSize = maximumSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypedValue getValue() {
|
||||||
|
growCollectionIfNecessary();
|
||||||
|
if (this.collection instanceof List) {
|
||||||
|
Object o = ((List) this.collection).get(this.index);
|
||||||
|
return new TypedValue(o, this.collectionEntryDescriptor.elementTypeDescriptor(o));
|
||||||
|
}
|
||||||
|
int pos = 0;
|
||||||
|
for (Object o : this.collection) {
|
||||||
|
if (pos == this.index) {
|
||||||
|
return new TypedValue(o, this.collectionEntryDescriptor.elementTypeDescriptor(o));
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("Failed to find indexed element " + this.index + ": " + this.collection);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setValue(Object newValue) {
|
||||||
|
growCollectionIfNecessary();
|
||||||
|
if (this.collection instanceof List) {
|
||||||
|
List list = (List) this.collection;
|
||||||
|
if (this.collectionEntryDescriptor.getElementTypeDescriptor() != null) {
|
||||||
|
newValue = this.typeConverter.convertValue(newValue, TypeDescriptor.forObject(newValue),
|
||||||
|
this.collectionEntryDescriptor.getElementTypeDescriptor());
|
||||||
|
}
|
||||||
|
list.set(this.index, newValue);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new SpelEvaluationException(getStartPosition(), SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE,
|
||||||
|
this.collectionEntryDescriptor.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.collectionEntryDescriptor.getElementTypeDescriptor() == null) {
|
||||||
|
throw new SpelEvaluationException(getStartPosition(), SpelMessage.UNABLE_TO_GROW_COLLECTION_UNKNOWN_ELEMENT_TYPE);
|
||||||
|
}
|
||||||
|
TypeDescriptor elementType = this.collectionEntryDescriptor.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isWritable() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private class StringIndexingLValue implements ValueRef {
|
||||||
|
|
||||||
|
private final String target;
|
||||||
|
|
||||||
|
private final int index;
|
||||||
|
|
||||||
|
private final TypeDescriptor typeDescriptor;
|
||||||
|
|
||||||
|
public StringIndexingLValue(String target, int index, TypeDescriptor typeDescriptor) {
|
||||||
|
this.target = target;
|
||||||
|
this.index = index;
|
||||||
|
this.typeDescriptor = typeDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypedValue getValue() {
|
||||||
|
if (this.index >= this.target.length()) {
|
||||||
|
throw new SpelEvaluationException(getStartPosition(), SpelMessage.STRING_INDEX_OUT_OF_BOUNDS,
|
||||||
|
this.target.length(), this.index);
|
||||||
|
}
|
||||||
|
return new TypedValue(String.valueOf(this.target.charAt(this.index)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setValue(Object newValue) {
|
||||||
|
throw new SpelEvaluationException(getStartPosition(), SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE,
|
||||||
|
this.typeDescriptor.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isWritable() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2002-2014 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -37,6 +37,7 @@ public abstract class SpelNodeImpl implements SpelNode {
|
|||||||
|
|
||||||
private static SpelNodeImpl[] NO_CHILDREN = new SpelNodeImpl[0];
|
private static SpelNodeImpl[] NO_CHILDREN = new SpelNodeImpl[0];
|
||||||
|
|
||||||
|
|
||||||
protected int pos; // start = top 16bits, end = bottom 16bits
|
protected int pos; // start = top 16bits, end = bottom 16bits
|
||||||
|
|
||||||
protected SpelNodeImpl[] children = SpelNodeImpl.NO_CHILDREN;
|
protected SpelNodeImpl[] children = SpelNodeImpl.NO_CHILDREN;
|
||||||
@@ -152,22 +153,21 @@ public abstract class SpelNodeImpl implements SpelNode {
|
|||||||
return ExpressionUtils.convertTypedValue(state.getEvaluationContext(), getValueInternal(state), desiredReturnType);
|
return ExpressionUtils.convertTypedValue(state.getEvaluationContext(), getValueInternal(state), desiredReturnType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract TypedValue getValueInternal(ExpressionState expressionState) throws EvaluationException;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public abstract String toStringAST();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getStartPosition() {
|
public int getStartPosition() {
|
||||||
return (this.pos>>16);
|
return (this.pos >> 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getEndPosition() {
|
public int getEndPosition() {
|
||||||
return (this.pos&0xffff);
|
return (this.pos & 0xffff);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ValueRef getValueRef(ExpressionState state) throws EvaluationException {
|
protected ValueRef getValueRef(ExpressionState state) throws EvaluationException {
|
||||||
throw new SpelEvaluationException(this.pos,SpelMessage.NOT_ASSIGNABLE,toStringAST());
|
throw new SpelEvaluationException(this.pos, SpelMessage.NOT_ASSIGNABLE, toStringAST());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public abstract TypedValue getValueInternal(ExpressionState expressionState) throws EvaluationException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,9 +81,19 @@ public class MapAccessTests extends AbstractExpressionTests {
|
|||||||
Object bean = new TestBean("name1", new TestBean("name2", null, "Description 2", 15, props1), "description 1", 6, props1);
|
Object bean = new TestBean("name1", new TestBean("name2", null, "Description 2", 15, props1), "description 1", 6, props1);
|
||||||
|
|
||||||
ExpressionParser parser = new SpelExpressionParser();
|
ExpressionParser parser = new SpelExpressionParser();
|
||||||
Expression exp = parser.parseExpression("testBean.properties['key2']");
|
Expression expr = parser.parseExpression("testBean.properties['key2']");
|
||||||
String key = (String) exp.getValue(bean);
|
assertEquals("value2", expr.getValue(bean));
|
||||||
assertNotNull(key);
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetValueFromRootMap() {
|
||||||
|
Map<String, String> map = new HashMap<String, String>();
|
||||||
|
map.put("key", "value");
|
||||||
|
EvaluationContext context = new StandardEvaluationContext(map);
|
||||||
|
|
||||||
|
ExpressionParser spelExpressionParser = new SpelExpressionParser();
|
||||||
|
Expression expr = spelExpressionParser.parseExpression("#root['key']");
|
||||||
|
assertEquals("value", expr.getValue(map));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -31,9 +31,7 @@ import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
|
|||||||
import org.springframework.messaging.simp.SimpMessageType;
|
import org.springframework.messaging.simp.SimpMessageType;
|
||||||
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
||||||
import org.springframework.messaging.support.MessageBuilder;
|
import org.springframework.messaging.support.MessageBuilder;
|
||||||
import org.springframework.messaging.support.MessageHeaderAccessor;
|
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.CollectionUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides support for messages sent to "user" destinations, translating the
|
* Provides support for messages sent to "user" destinations, translating the
|
||||||
@@ -60,7 +58,7 @@ public class UserDestinationMessageHandler implements MessageHandler, SmartLifec
|
|||||||
|
|
||||||
private final UserDestinationResolver userDestinationResolver;
|
private final UserDestinationResolver userDestinationResolver;
|
||||||
|
|
||||||
private Object lifecycleMonitor = new Object();
|
private final Object lifecycleMonitor = new Object();
|
||||||
|
|
||||||
private volatile boolean running = false;
|
private volatile boolean running = false;
|
||||||
|
|
||||||
@@ -85,12 +83,6 @@ public class UserDestinationMessageHandler implements MessageHandler, SmartLifec
|
|||||||
this.userDestinationResolver = userDestinationResolver;
|
this.userDestinationResolver = userDestinationResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the configured {@link UserDestinationResolver}.
|
|
||||||
*/
|
|
||||||
public UserDestinationResolver getUserDestinationResolver() {
|
|
||||||
return this.userDestinationResolver;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the configured messaging template for sending messages with
|
* Return the configured messaging template for sending messages with
|
||||||
@@ -100,16 +92,24 @@ public class UserDestinationMessageHandler implements MessageHandler, SmartLifec
|
|||||||
return this.brokerMessagingTemplate;
|
return this.brokerMessagingTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public boolean isAutoStartup() {
|
* Return the configured {@link UserDestinationResolver}.
|
||||||
return true;
|
*/
|
||||||
|
public UserDestinationResolver getUserDestinationResolver() {
|
||||||
|
return this.userDestinationResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getPhase() {
|
public int getPhase() {
|
||||||
return Integer.MAX_VALUE;
|
return Integer.MAX_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAutoStartup() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final boolean isRunning() {
|
public final boolean isRunning() {
|
||||||
synchronized (this.lifecycleMonitor) {
|
synchronized (this.lifecycleMonitor) {
|
||||||
@@ -143,9 +143,9 @@ public class UserDestinationMessageHandler implements MessageHandler, SmartLifec
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleMessage(Message<?> message) throws MessagingException {
|
public void handleMessage(Message<?> message) throws MessagingException {
|
||||||
|
|
||||||
UserDestinationResult result = this.userDestinationResolver.resolveDestination(message);
|
UserDestinationResult result = this.userDestinationResolver.resolveDestination(message);
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
return;
|
return;
|
||||||
@@ -154,13 +154,11 @@ public class UserDestinationMessageHandler implements MessageHandler, SmartLifec
|
|||||||
if (destinations.isEmpty()) {
|
if (destinations.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor.wrap(message);
|
SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor.wrap(message);
|
||||||
if (SimpMessageType.MESSAGE.equals(headerAccessor.getMessageType())) {
|
if (SimpMessageType.MESSAGE.equals(headerAccessor.getMessageType())) {
|
||||||
headerAccessor.setHeader(SUBSCRIBE_DESTINATION, result.getSubscribeDestination());
|
headerAccessor.setHeader(SUBSCRIBE_DESTINATION, result.getSubscribeDestination());
|
||||||
message = MessageBuilder.withPayload(message.getPayload()).setHeaders(headerAccessor).build();
|
message = MessageBuilder.withPayload(message.getPayload()).setHeaders(headerAccessor).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (String targetDestination : destinations) {
|
for (String targetDestination : destinations) {
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Sending message to resolved destination=" + targetDestination);
|
logger.debug("Sending message to resolved destination=" + targetDestination);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2012 the original author or authors.
|
* Copyright 2002-2014 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -16,10 +16,10 @@
|
|||||||
|
|
||||||
package org.springframework.transaction.interceptor;
|
package org.springframework.transaction.interceptor;
|
||||||
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rule determining whether or not a given exception (and any subclasses)
|
* Rule determining whether or not a given exception (and any subclasses)
|
||||||
* should cause a rollback.
|
* should cause a rollback.
|
||||||
@@ -60,7 +60,7 @@ public class RollbackRuleAttribute implements Serializable{
|
|||||||
* not a {@code Throwable} type or is {@code null}
|
* not a {@code Throwable} type or is {@code null}
|
||||||
*/
|
*/
|
||||||
public RollbackRuleAttribute(Class<?> clazz) {
|
public RollbackRuleAttribute(Class<?> clazz) {
|
||||||
Assert.notNull(clazz, "'clazz' cannot be null.");
|
Assert.notNull(clazz, "'clazz' cannot be null");
|
||||||
if (!Throwable.class.isAssignableFrom(clazz)) {
|
if (!Throwable.class.isAssignableFrom(clazz)) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Cannot construct rollback rule from [" + clazz.getName() + "]: it's not a Throwable");
|
"Cannot construct rollback rule from [" + clazz.getName() + "]: it's not a Throwable");
|
||||||
@@ -87,7 +87,7 @@ public class RollbackRuleAttribute implements Serializable{
|
|||||||
* {@code exceptionName} is {@code null} or empty
|
* {@code exceptionName} is {@code null} or empty
|
||||||
*/
|
*/
|
||||||
public RollbackRuleAttribute(String exceptionName) {
|
public RollbackRuleAttribute(String exceptionName) {
|
||||||
Assert.hasText(exceptionName, "'exceptionName' cannot be null or empty.");
|
Assert.hasText(exceptionName, "'exceptionName' cannot be null or empty");
|
||||||
this.exceptionName = exceptionName;
|
this.exceptionName = exceptionName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,7 +111,7 @@ public class RollbackRuleAttribute implements Serializable{
|
|||||||
|
|
||||||
|
|
||||||
private int getDepth(Class<?> exceptionClass, int depth) {
|
private int getDepth(Class<?> exceptionClass, int depth) {
|
||||||
if (exceptionClass.getName().indexOf(this.exceptionName) != -1) {
|
if (exceptionClass.getName().contains(this.exceptionName)) {
|
||||||
// Found it!
|
// Found it!
|
||||||
return depth;
|
return depth;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ package org.springframework.web.servlet.mvc.method.annotation;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@@ -101,6 +100,9 @@ public class ServletRequestMethodArgumentResolver implements HandlerMethodArgume
|
|||||||
else if (HttpSession.class.isAssignableFrom(paramType)) {
|
else if (HttpSession.class.isAssignableFrom(paramType)) {
|
||||||
return request.getSession();
|
return request.getSession();
|
||||||
}
|
}
|
||||||
|
else if (HttpMethod.class.equals(paramType)) {
|
||||||
|
return ((ServletWebRequest) webRequest).getHttpMethod();
|
||||||
|
}
|
||||||
else if (Principal.class.isAssignableFrom(paramType)) {
|
else if (Principal.class.isAssignableFrom(paramType)) {
|
||||||
return request.getUserPrincipal();
|
return request.getUserPrincipal();
|
||||||
}
|
}
|
||||||
@@ -120,13 +122,10 @@ public class ServletRequestMethodArgumentResolver implements HandlerMethodArgume
|
|||||||
else if (Reader.class.isAssignableFrom(paramType)) {
|
else if (Reader.class.isAssignableFrom(paramType)) {
|
||||||
return request.getReader();
|
return request.getReader();
|
||||||
}
|
}
|
||||||
else if (HttpMethod.class.equals(paramType)) {
|
|
||||||
return ((ServletWebRequest) webRequest).getHttpMethod();
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
// should never happen..
|
// should never happen...
|
||||||
Method method = parameter.getMethod();
|
throw new UnsupportedOperationException(
|
||||||
throw new UnsupportedOperationException("Unknown parameter type: " + paramType + " in method: " + method);
|
"Unknown parameter type: " + paramType + " in method: " + parameter.getMethod());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ package org.springframework.web.servlet.tags.form;
|
|||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.servlet.ServletRequest;
|
import javax.servlet.ServletRequest;
|
||||||
import javax.servlet.ServletResponse;
|
import javax.servlet.ServletResponse;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
@@ -424,7 +423,6 @@ public class FormTag extends AbstractHtmlElementTag {
|
|||||||
* with the context and servlet paths, and the result is used. Otherwise, the
|
* with the context and servlet paths, and the result is used. Otherwise, the
|
||||||
* {@link org.springframework.web.servlet.support.RequestContext#getRequestUri()
|
* {@link org.springframework.web.servlet.support.RequestContext#getRequestUri()
|
||||||
* originating URI} is used.
|
* originating URI} is used.
|
||||||
*
|
|
||||||
* @return the value that is to be used for the '{@code action}' attribute
|
* @return the value that is to be used for the '{@code action}' attribute
|
||||||
*/
|
*/
|
||||||
protected String resolveAction() throws JspException {
|
protected String resolveAction() throws JspException {
|
||||||
@@ -436,7 +434,8 @@ public class FormTag extends AbstractHtmlElementTag {
|
|||||||
}
|
}
|
||||||
else if (StringUtils.hasText(servletRelativeAction)) {
|
else if (StringUtils.hasText(servletRelativeAction)) {
|
||||||
String pathToServlet = getRequestContext().getPathToServlet();
|
String pathToServlet = getRequestContext().getPathToServlet();
|
||||||
if (servletRelativeAction.startsWith("/") && !servletRelativeAction.startsWith(getRequestContext().getContextPath())) {
|
if (servletRelativeAction.startsWith("/") &&
|
||||||
|
!servletRelativeAction.startsWith(getRequestContext().getContextPath())) {
|
||||||
servletRelativeAction = pathToServlet + servletRelativeAction;
|
servletRelativeAction = pathToServlet + servletRelativeAction;
|
||||||
}
|
}
|
||||||
servletRelativeAction = getDisplayString(evaluate(ACTION_ATTRIBUTE, servletRelativeAction));
|
servletRelativeAction = getDisplayString(evaluate(ACTION_ATTRIBUTE, servletRelativeAction));
|
||||||
@@ -444,12 +443,12 @@ public class FormTag extends AbstractHtmlElementTag {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
String requestUri = getRequestContext().getRequestUri();
|
String requestUri = getRequestContext().getRequestUri();
|
||||||
String encoding = pageContext.getResponse().getCharacterEncoding();
|
String encoding = this.pageContext.getResponse().getCharacterEncoding();
|
||||||
try {
|
try {
|
||||||
requestUri = UriUtils.encodePath(requestUri, encoding);
|
requestUri = UriUtils.encodePath(requestUri, encoding);
|
||||||
}
|
}
|
||||||
catch (UnsupportedEncodingException e) {
|
catch (UnsupportedEncodingException ex) {
|
||||||
throw new JspException(e);
|
// shouldn't happen - if it does, proceed with requestUri as-is
|
||||||
}
|
}
|
||||||
ServletResponse response = this.pageContext.getResponse();
|
ServletResponse response = this.pageContext.getResponse();
|
||||||
if (response instanceof HttpServletResponse) {
|
if (response instanceof HttpServletResponse) {
|
||||||
@@ -476,7 +475,7 @@ public class FormTag extends AbstractHtmlElementTag {
|
|||||||
private String processAction(String action) {
|
private String processAction(String action) {
|
||||||
RequestDataValueProcessor processor = getRequestContext().getRequestDataValueProcessor();
|
RequestDataValueProcessor processor = getRequestContext().getRequestDataValueProcessor();
|
||||||
ServletRequest request = this.pageContext.getRequest();
|
ServletRequest request = this.pageContext.getRequest();
|
||||||
if ((processor != null) && (request instanceof HttpServletRequest)) {
|
if (processor != null && request instanceof HttpServletRequest) {
|
||||||
action = processor.processAction((HttpServletRequest) request, action, getHttpMethod());
|
action = processor.processAction((HttpServletRequest) request, action, getHttpMethod());
|
||||||
}
|
}
|
||||||
return action;
|
return action;
|
||||||
|
|||||||
Reference in New Issue
Block a user