SpEL property-not-found message hints at non-public method/field
Issue: SPR-11535
(cherry picked from commit eeb82c4)
This commit is contained in:
@@ -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");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,8 +19,8 @@ package org.springframework.expression.spel;
|
||||
import java.text.MessageFormat;
|
||||
|
||||
/**
|
||||
* Contains all the messages that can be produced by the Spring Expression Language. Each
|
||||
* message has a kind (info, warn, error) and a code number. Tests can be written to
|
||||
* Contains all the messages that can be produced by the Spring Expression Language.
|
||||
* Each message has a kind (info, warn, error) and a code number. Tests can be written to
|
||||
* expect particular code numbers rather than particular text, enabling the message text
|
||||
* to more easily be modified and the tests to run successfully in different locales.
|
||||
*
|
||||
@@ -30,8 +30,8 @@ import java.text.MessageFormat;
|
||||
* EL1004E: (pos 34): Type cannot be found 'String'
|
||||
* </pre>
|
||||
*
|
||||
* The prefix captures the code and the error kind, whilst the position is
|
||||
* included if it is known.
|
||||
* The prefix captures the code and the error kind, whilst the position is included
|
||||
* if it is known.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
@@ -42,12 +42,10 @@ public enum SpelMessage {
|
||||
"Type conversion problem, cannot convert from {0} to {1}"),
|
||||
|
||||
CONSTRUCTOR_NOT_FOUND(Kind.ERROR, 1002,
|
||||
"Constructor call: No suitable constructor found on type {0} for " +
|
||||
"arguments {1}"),
|
||||
"Constructor call: No suitable constructor found on type {0} for arguments {1}"),
|
||||
|
||||
CONSTRUCTOR_INVOCATION_PROBLEM(Kind.ERROR, 1003,
|
||||
"A problem occurred whilst attempting to construct an object of type " +
|
||||
"''{0}'' using arguments ''{1}''"),
|
||||
"A problem occurred whilst attempting to construct an object of type ''{0}'' using arguments ''{1}''"),
|
||||
|
||||
METHOD_NOT_FOUND(Kind.ERROR, 1004,
|
||||
"Method call: Method {0} cannot be found on {1} type"),
|
||||
@@ -59,16 +57,16 @@ public enum SpelMessage {
|
||||
"The function ''{0}'' could not be found"),
|
||||
|
||||
PROPERTY_OR_FIELD_NOT_READABLE_ON_NULL(Kind.ERROR, 1007,
|
||||
"Field or property ''{0}'' cannot be found on null"),
|
||||
"Property or field ''{0}'' cannot be found on null"),
|
||||
|
||||
PROPERTY_OR_FIELD_NOT_READABLE(Kind.ERROR, 1008,
|
||||
"Field or property ''{0}'' cannot be found on object of type ''{1}''"),
|
||||
"Property or field ''{0}'' cannot be found on object of type ''{1}'' - maybe not public?"),
|
||||
|
||||
PROPERTY_OR_FIELD_NOT_WRITABLE_ON_NULL(Kind.ERROR, 1009,
|
||||
"Field or property ''{0}'' cannot be set on null"),
|
||||
"Property or field ''{0}'' cannot be set on null"),
|
||||
|
||||
PROPERTY_OR_FIELD_NOT_WRITABLE(Kind.ERROR, 1010,
|
||||
"Field or property ''{0}'' cannot be set on object of type ''{1}''"),
|
||||
"Property or field ''{0}'' cannot be set on object of type ''{1}'' - maybe not public?"),
|
||||
|
||||
METHOD_CALL_ON_NULL_OBJECT_NOT_ALLOWED(Kind.ERROR, 1011,
|
||||
"Method call: Attempted to call method {0} on null context object"),
|
||||
@@ -80,8 +78,7 @@ public enum SpelMessage {
|
||||
"Cannot compare instances of {0} and {1}"),
|
||||
|
||||
INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION(Kind.ERROR, 1014,
|
||||
"Incorrect number of arguments for function, {0} supplied but " +
|
||||
"function takes {1}"),
|
||||
"Incorrect number of arguments for function, {0} supplied but function takes {1}"),
|
||||
|
||||
INVALID_TYPE_FOR_SELECTION(Kind.ERROR, 1015,
|
||||
"Cannot perform selection on input data of type ''{0}''"),
|
||||
@@ -99,20 +96,16 @@ public enum SpelMessage {
|
||||
"Projection is not supported on the type ''{0}''"),
|
||||
|
||||
ARGLIST_SHOULD_NOT_BE_EVALUATED(Kind.ERROR, 1020,
|
||||
"The argument list of a lambda expression should never have getValue() " +
|
||||
"called upon it"),
|
||||
"The argument list of a lambda expression should never have getValue() called upon it"),
|
||||
|
||||
EXCEPTION_DURING_PROPERTY_READ(Kind.ERROR, 1021,
|
||||
"A problem occurred whilst attempting to access the property " +
|
||||
"''{0}'': ''{1}''"),
|
||||
"A problem occurred whilst attempting to access the property ''{0}'': ''{1}''"),
|
||||
|
||||
FUNCTION_REFERENCE_CANNOT_BE_INVOKED(Kind.ERROR, 1022,
|
||||
"The function ''{0}'' mapped to an object of type ''{1}'' which " +
|
||||
"cannot be invoked"),
|
||||
"The function ''{0}'' mapped to an object of type ''{1}'' which cannot be invoked"),
|
||||
|
||||
EXCEPTION_DURING_FUNCTION_CALL(Kind.ERROR, 1023,
|
||||
"A problem occurred whilst attempting to invoke the " +
|
||||
"function ''{0}'': ''{1}''"),
|
||||
"A problem occurred whilst attempting to invoke the function ''{0}'': ''{1}''"),
|
||||
|
||||
ARRAY_INDEX_OUT_OF_BOUNDS(Kind.ERROR, 1024,
|
||||
"The array has ''{0}'' elements, index ''{1}'' is invalid"),
|
||||
@@ -127,16 +120,13 @@ public enum SpelMessage {
|
||||
"Indexing into type ''{0}'' is not supported"),
|
||||
|
||||
INSTANCEOF_OPERATOR_NEEDS_CLASS_OPERAND(Kind.ERROR, 1028,
|
||||
"The operator 'instanceof' needs the right operand to be a class, " +
|
||||
"not a ''{0}''"),
|
||||
"The operator 'instanceof' needs the right operand to be a class, not a ''{0}''"),
|
||||
|
||||
EXCEPTION_DURING_METHOD_INVOCATION(Kind.ERROR, 1029,
|
||||
"A problem occurred when trying to execute method ''{0}'' on object " +
|
||||
"of type ''{1}'': ''{2}''"),
|
||||
"A problem occurred when trying to execute method ''{0}'' on object of type ''{1}'': ''{2}''"),
|
||||
|
||||
OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES(Kind.ERROR, 1030,
|
||||
"The operator ''{0}'' is not supported between objects of type " +
|
||||
"''{1}'' and ''{2}''"),
|
||||
"The operator ''{0}'' is not supported between objects of type ''{1}'' and ''{2}''"),
|
||||
|
||||
PROBLEM_LOCATING_METHOD(Kind.ERROR, 1031,
|
||||
"Problem locating method {0} on type {1}"),
|
||||
@@ -145,8 +135,7 @@ public enum SpelMessage {
|
||||
"setValue(ExpressionState, Object) not supported for ''{0}''"),
|
||||
|
||||
MULTIPLE_POSSIBLE_METHODS(Kind.ERROR, 1033,
|
||||
"Method call of ''{0}'' is ambiguous, supported type conversions " +
|
||||
"allow multiple variants to match"),
|
||||
"Method call of ''{0}'' is ambiguous, supported type conversions allow multiple variants to match"),
|
||||
|
||||
EXCEPTION_DURING_PROPERTY_WRITE(Kind.ERROR, 1034,
|
||||
"A problem occurred whilst attempting to set the property ''{0}'': {1}"),
|
||||
@@ -171,8 +160,7 @@ public enum SpelMessage {
|
||||
"The value ''{0}'' cannot be parsed as a double"),
|
||||
|
||||
MORE_INPUT(Kind.ERROR,1041,
|
||||
"After parsing a valid expression, there is still more data in " +
|
||||
"the expression: ''{0}''"),
|
||||
"After parsing a valid expression, there is still more data in the expression: ''{0}''"),
|
||||
|
||||
RIGHT_OPERAND_PROBLEM(Kind.ERROR, 1042,
|
||||
"Problem parsing right operand"),
|
||||
@@ -263,9 +251,12 @@ public enum SpelMessage {
|
||||
MISSING_SELECTION_EXPRESSION(Kind.ERROR, 1071,
|
||||
"A required selection expression has not been specified");
|
||||
|
||||
private Kind kind;
|
||||
private int code;
|
||||
private String message;
|
||||
|
||||
private final Kind kind;
|
||||
|
||||
private final int code;
|
||||
|
||||
private final String message;
|
||||
|
||||
|
||||
private SpelMessage(Kind kind, int code, String message) {
|
||||
@@ -276,10 +267,9 @@ public enum SpelMessage {
|
||||
|
||||
|
||||
/**
|
||||
* Produce a complete message including the prefix, the position (if known) and with the inserts applied to the
|
||||
* message.
|
||||
*
|
||||
* @param pos the position, if less than zero it is ignored and not included in the message
|
||||
* Produce a complete message including the prefix, the position (if known)
|
||||
* and with the inserts applied to the message.
|
||||
* @param pos the position (ignored and not included in the message if less than 0)
|
||||
* @param inserts the inserts to put into the formatted message
|
||||
* @return a formatted message
|
||||
*/
|
||||
@@ -300,8 +290,6 @@ public enum SpelMessage {
|
||||
}
|
||||
|
||||
|
||||
public static enum Kind {
|
||||
INFO, WARNING, ERROR
|
||||
}
|
||||
public static enum Kind { INFO, WARNING, ERROR }
|
||||
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -42,9 +42,11 @@ import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Simple PropertyAccessor that uses reflection to access properties for reading and
|
||||
* writing. A property can be accessed if it is accessible as a field on the object or
|
||||
* through a getter (if being read) or a setter (if being written).
|
||||
* Simple {@link PropertyAccessor} that uses reflection to access properties
|
||||
* for reading and writing.
|
||||
*
|
||||
* <p>A property can be accessed through a public getter method (when being read)
|
||||
* or a public setter method (when being written), and also as a public field.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @author Juergen Hoeller
|
||||
@@ -72,7 +74,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
|
||||
|
||||
|
||||
/**
|
||||
* @return null which means this is a general purpose accessor
|
||||
* Returns {@code null} which means this is a general purpose accessor.
|
||||
*/
|
||||
@Override
|
||||
public Class<?>[] getSpecificTargetClasses() {
|
||||
@@ -94,8 +96,8 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
|
||||
}
|
||||
Method method = findGetterForProperty(name, type, target);
|
||||
if (method != null) {
|
||||
// Treat it like a property
|
||||
// The readerCache will only contain gettable properties (let's not worry about setters for now)
|
||||
// Treat it like a property...
|
||||
// The readerCache will only contain gettable properties (let's not worry about setters for now).
|
||||
Property property = new Property(type, method, null);
|
||||
TypeDescriptor typeDescriptor = new TypeDescriptor(property);
|
||||
this.readerCache.put(cacheKey, new InvokerPair(method, typeDescriptor));
|
||||
@@ -137,8 +139,8 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
|
||||
method = findGetterForProperty(name, type, target);
|
||||
if (method != null) {
|
||||
// TODO remove the duplication here between canRead and read
|
||||
// Treat it like a property
|
||||
// The readerCache will only contain gettable properties (let's not worry about setters for now)
|
||||
// Treat it like a property...
|
||||
// The readerCache will only contain gettable properties (let's not worry about setters for now).
|
||||
Property property = new Property(type, method, null);
|
||||
TypeDescriptor typeDescriptor = new TypeDescriptor(property);
|
||||
invoker = new InvokerPair(method, typeDescriptor);
|
||||
@@ -352,6 +354,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
|
||||
|
||||
private Method findMethodForProperty(String[] methodSuffixes, String prefix, Class<?> clazz,
|
||||
boolean mustBeStatic, int numberOfParams, Set<Class<?>> requiredReturnTypes) {
|
||||
|
||||
Method[] methods = getSortedClassMethods(clazz);
|
||||
for (String methodSuffix : methodSuffixes) {
|
||||
for (Method method : methods) {
|
||||
@@ -407,7 +410,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a field of a certain name on a specified class
|
||||
* Find a field of a certain name on a specified class.
|
||||
*/
|
||||
protected Field findField(String name, Class<?> clazz, boolean mustBeStatic) {
|
||||
Field[] fields = clazz.getFields();
|
||||
|
||||
@@ -1788,7 +1788,7 @@ public class SpelReproTests extends AbstractExpressionTests {
|
||||
SPR11142 rootObject = new SPR11142();
|
||||
Expression expression = parser.parseExpression("something");
|
||||
thrown.expect(SpelEvaluationException.class);
|
||||
thrown.expectMessage("property 'something' cannot be found");
|
||||
thrown.expectMessage("'something' cannot be found");
|
||||
expression.getValue(context, rootObject);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user