Commit Graph

826 Commits

Author SHA1 Message Date
Juergen Hoeller e89218b39a Merge branch '6.1.x' 2024-10-16 13:46:22 +02:00
Juergen Hoeller 11d4272ff4 Use Locale.ROOT consistently for toLower/toUpperCase
Closes gh-33708
2024-10-16 13:36:23 +02:00
Yanming Zhou 8941e2876e Replace 'e.g.' with 'for example' in documentation and comments
Closes gh-33515
2024-09-26 14:11:17 +02:00
Sam Brannen 529f311bd4 Polish and harmonize implementations of SpEL components in spring-context 2024-09-03 17:16:20 +02:00
Sam Brannen 47f88e123f Invoke init/destroy/SpEL methods via public types whenever possible
Prior to this commit, when invoking init methods and destroy methods
for beans as well as methods within Spring Expression Language (SpEL)
expressions via reflection, we invoked them based on the "interface
method" returned from ClassUtils.getInterfaceMethodIfPossible(). That
works well for finding methods defined in an interface, but it does not
find public methods defined in a public superclass.

For example, in a SpEL expression it was previously impossible to
invoke toString() on a non-public type from a different module. This
could be seen when attempting to invoke toString() on an unmodifiable
list created by Collections.unmodifiableList(...). Doing so resulted in
an InaccessibleObjectException.

Although users can address that by adding an appropriate --add-opens
declaration, such as --add-opens java.base/java.util=ALL-UNNAMED, it is
better if applications do not have to add an --add-opens declaration
for such use cases in SpEL. The same applies to init methods and
destroy methods for beans.

This commit therefore introduces a new
getPubliclyAccessibleMethodIfPossible() method in ClassUtils which
serves as a replacement for getInterfaceMethodIfPossible().

This new method finds the first publicly accessible method in the
supplied method's type hierarchy that has a method signature equivalent
to the supplied method. If the supplied method is public and declared
in a public type, the supplied method will be returned. Otherwise, this
method recursively searches the class hierarchy and implemented
interfaces for an equivalent method that is public and declared in a
public type. If a publicly accessible equivalent method cannot be
found, the supplied method will be returned, indicating that no such
equivalent method exists.

All usage of getInterfaceMethodIfPossible() has been replaced with
getPubliclyAccessibleMethodIfPossible() in spring-beans and
spring-expression. In addition, getInterfaceMethodIfPossible() has been
marked as deprecated in favor of the new method.

As a bonus, the introduction of getPubliclyAccessibleMethodIfPossible()
allows us to delete a fair amount of obsolete code within the SpEL
infrastructure.

See gh-29857
Closes gh-33216
2024-08-22 14:35:21 +02:00
Sam Brannen e50383e921 Improve Javadoc for SpEL's Expression API 2024-08-17 15:59:00 +02:00
Sam Brannen d749d2949d Use new features from JUnit Jupiter 5.11
This commit primarily migrates to the new argumentSet() feature but also
applies additional polishing to our use of parameterized tests.

See gh-33395
2024-08-16 13:48:19 +02:00
Sam Brannen 1aea01687a Merge branch '6.1.x' 2024-08-13 17:40:13 +03:00
Sam Brannen e74406afd0 Introduce withAssignmentDisabled() option for SimpleEvaluationContext
To support additional use cases, this commit introduces a
withAssignmentDisabled() method in the Builder for
SimpleEvaluationContext.

Closes gh-33319
2024-08-13 17:26:34 +03:00
Sam Brannen a55207e88f Add tests for read-only IndexAccessors in 6.2 2024-08-07 19:23:06 +03:00
Sam Brannen a698f66c3a Merge branch '6.1.x'
# Conflicts:
#	spring-expression/src/main/java/org/springframework/expression/spel/support/SimpleEvaluationContext.java
2024-08-06 13:56:57 +03:00
Sam Brannen 0127de5a7a Enforce read-only semantics in SpEL's SimpleEvaluationContext
SimpleEvaluationContext.forReadOnlyDataBinding() documents that it
creates a SimpleEvaluationContext for read-only access to public
properties; however, prior to this commit write access was not disabled
for indexed structures when using the assignment operator, the
increment operator, or the decrement operator.

In order to better align with the documented contract for
forReadOnlyDataBinding(), this commit makes it possible to disable
assignment in general in order to enforce read-only semantics for
SpEL's SimpleEvaluationContext when created via the
forReadOnlyDataBinding() factory method. Specifically:

- This commit introduces a new isAssignmentEnabled() "default" method
  in the EvaluationContext API, which returns true by default.

- SimpleEvaluationContext overrides isAssignmentEnabled(), returning
  false if the context was created via the forReadOnlyDataBinding()
  factory method.

- The Assign, OpDec, and OpInc AST nodes -- representing the assignment
  (=), increment (++), and decrement (--) operators, respectively --
  now throw a SpelEvaluationException if assignment is disabled for the
  current EvaluationContext.

Closes gh-33319
2024-08-06 13:54:11 +03:00
Sam Brannen 1e804d8d4f Merge branch '6.1.x' 2024-08-05 16:37:57 +03:00
Sam Brannen fcc99a67b6 Support lists for varargs invocations in SpEL
The changes made in conjunction with gh-33013 resulted in a regression
for varargs support in SpEL expressions. Specifically, before gh-33013
one could supply a list -- for example, an "inline list" -- as the
varargs array when invoking a varargs constructor, method, or function
within a SpEL expression. However, after gh-33013 an inline list (or
collection in general) is no longer converted to an array for varargs
invocations. Instead, the list is supplied as a single argument of the
resulting varargs array which breaks applications that depend on the
previous behavior.

Although it was never intended that one could supply a collection as
the set of varargs, we concede that this is a regression in existing
behavior, and this commit therefore restores support for supplying a
java.util.List as the varargs "array".

In addition, this commit introduces the same "list to array" conversion
support for MethodHandle-based functions that accept varargs.

Note, however, that this commit does not restore support for converting
arbitrary single objects to an array for varargs invocations if the
single object is already an instance of the varargs array's component
type.

See gh-33013
Closes gh-33315
2024-08-05 16:28:11 +03:00
Sam Brannen 8afff3359b Polishing 2024-08-05 15:01:41 +03:00
Sam Brannen f3ab3905b8 Merge branch '6.1.x' 2024-08-05 14:21:27 +03:00
Sam Brannen c57c2272a1 Throw exception for failure to set property as index in SpEL
Prior to this commit, the Indexer in the Spring Expression Language
(SpEL) silently ignored a failure to set a property via the indexed
property syntax (['<property name>'] = <new value>) – for example, if
property write access was disabled in the EvaluationContext.

This commit addresses this issue by properly throwing a
SpelEvaluationException in PropertyIndexingValueRef.setValue(Object) if
the property could not be set.

Closes gh-33310
2024-08-05 14:15:55 +03:00
Sam Brannen 8ec23a0fcc Polishing 2024-08-05 14:15:39 +03:00
Sam Brannen 74b0bb105e Merge branch '6.1.x' 2024-08-05 11:58:49 +03:00
Sam Brannen 8badae9d72 Convert primitive array to Object[] when invoking varargs method in SpEL
Prior to this commit, SpEL incorrectly wrapped a primitive array in an
Object[] array when invoking Object[] varargs methods and constructors.

This commit addresses this by updating the convertArguments(...) method
in ReflectionHelper as follows when the user supplies the varargs
already packaged in a primitive array.

- When deciding whether to convert a single element passed as varargs,
  we now check if the argument is an array that is assignable to the
  varargs array type.

- When converting an array supplied as the varargs, we convert that
  array to the varargs array type.

Closes gh-33317
2024-08-05 11:56:48 +03:00
Sam Brannen 46a4ad4a75 Merge branch '6.1.x' 2024-08-05 11:07:47 +03:00
Sam Brannen 444e7eeb74 Enable test for primitive array to Object[] conversion in SpEL
See gh-33212
2024-08-05 11:05:53 +03:00
Sam Brannen e547313fa6 Sync MapAccessor implementations 2024-07-23 18:27:52 +03:00
Sam Brannen 6ca8fbc2da Merge ArgumentsMatchInfo into ArgumentsMatchKind in SpEL
The internal ArgumentsMatchInfo type seems to have once had additional
methods beyond the functionality provided by the ArgumentsMatchKind
enum; however, that is no longer the case. Consequently, there is no
need to maintain both types.

This commit therefore merges the convenience methods from
ArgumentsMatchInfo into the ArgumentsMatchKind enum and removes the
unnecessary ArgumentsMatchInfo type.
2024-07-13 14:34:24 +02:00
Sam Brannen 59b9404956 Specify nullability @⁠Contract for TypeDescriptor.array() 2024-07-12 18:02:26 +02:00
Sam Brannen 09d8e4458c Merge branch '6.1.x' 2024-07-12 17:37:51 +02:00
Sam Brannen ae5dd54115 Add @⁠Disabled tests for primitive varargs array to Object[] conversion 2024-07-12 17:36:54 +02:00
Sam Brannen e088892fc1 Support MethodHandle invocation with primitive varargs array in SpEL
Prior to this commit, the Spring Expression Language (SpEL) could not
invoke a varargs MethodHandle function with a primitive array
containing the variable arguments, although that is supported for a
varargs Method function. Attempting to do so resulted in the first
element of the primitive array being supplied as a single argument to
the MethodHandle, effectively ignoring any variable arguments after the
first one.

This commit addresses this by updating the
convertAllMethodHandleArguments(...) method in ReflectionHelper as
follows when the user supplies the varargs already packaged in a
primitive array.

- Regarding conversion, use the wrapper type for a primitive varargs
  array, since we eventually need an Object array in order to invoke
  the MethodHandle in FunctionReference#executeFunctionViaMethodHandle().

- When deciding whether to convert a single element passed as varargs,
  we now check if the argument is an array that is assignable to the
  varargs array type.

- When converting an array supplied as the varargs, we now convert that
  array to the varargs array type instead of the varargs component type.

Note, however, that a SpEL expression cannot provide a primitive array
for an Object[] varargs target. This is due to the fact that the
ArrayToArrayConverter used by Spring's ConversionService does not
support conversion from a primitive array to Object[] -- for example,
from int[] to Object[].

See gh-33191
Closes gh-33198
2024-07-12 17:36:54 +02:00
Sam Brannen c93598835c Merge branch '6.1.x' 2024-07-11 18:31:37 +02:00
Sam Brannen 48a6bd6ce7 Polishing 2024-07-11 18:30:52 +02:00
Sam Brannen f7d4742ab8 Merge branch '6.1.x' 2024-07-10 16:52:08 +02:00
Sam Brannen fa2a58b9db Ensure varargs component type for MethodHandle is not null in SpEL
This commit ensures that the varargs component type for a MethodHandle
cannot be null in ReflectionHelper's
convertAllMethodHandleArguments(...) method in SpEL.

Closes gh-33193
2024-07-10 16:46:47 +02:00
Sam Brannen 4de2aadf72 Merge branch '6.1.x' 2024-07-10 16:22:17 +02:00
Sam Brannen 83ca2c0cff Support MethodHandle function invocation with varargs array in SpEL
Prior to this commit, the Spring Expression Language (SpEL) could not
invoke a varargs MethodHandle function with an array containing the
variable arguments, although that is supported for a varargs Method
function. Attempting to do so resulted in the array being supplied as a
single argument to the MethodHandle.

This commit addresses this by updating the
executeFunctionViaMethodHandle(...) method in FunctionReference as
follows when the user supplies the varargs already packaged in an array.

- Creates a new array large enough to hold the non-varargs arguments
  and the unpackaged varargs arguments.

- Adds the non-varargs arguments to the beginning of that array and
  adds the unpackaged varargs arguments to the end of that array.

- Invokes the MethodHandle with the new arguments array.

Closes gh-33191
2024-07-10 16:16:41 +02:00
Sam Brannen dc16f3cffb Polish SpEL function invocation support 2024-07-10 16:16:41 +02:00
Sam Brannen bb64e22266 Merge branch '6.1.x' 2024-07-10 13:51:44 +02:00
Sam Brannen a0f5c16627 Support MethodHandle function invocation with zero varargs in SpEL
Prior to this commit, the Spring Expression Language (SpEL) could not
invoke a varargs MethodHandle function with zero variable arguments,
even though the variable arguments are not required. Attempting to do
so resulted in a SpelEvaluationException with an
INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION message.

This commit addresses this by updating the
executeFunctionViaMethodHandle(...) method in FunctionReference so that
it properly checks the required number of arguments for both varargs
and non-varargs MethodHandle invocations.

This commit also improves the error message for varargs invocations
with too few arguments. For example, if the MethodHandle requires at
least 1 argument plus a variable number of additional arguments and 0
arguments were supplied, the error message now states:

"Incorrect number of arguments for function 'myFunc': 0 supplied but function takes 1 or more"

Instead of:

"Incorrect number of arguments for function 'myFunc': 0 supplied but function takes 2"

Closes gh-33190
2024-07-10 13:39:48 +02:00
Sam Brannen ee6402eeca Merge branch '6.1.x' 2024-07-10 12:04:26 +02:00
Sam Brannen c55c64427c Support single String argument for varargs invocations in SpEL
Prior to this commit, the Spring Expression Language (SpEL) incorrectly
split single String arguments by comma for Object... varargs method and
constructor invocations.

This commit addresses this by checking if the single argument type is
already "assignable" to the varargs component type instead of "equal"
to the varargs component type.

Closes gh-33013
2024-07-10 11:51:55 +02:00
Sam Brannen a4fcd301f2 Polish SpEL's ReflectionHelper 2024-07-10 11:19:36 +02:00
Sam Brannen 028ff9b548 Unwrap InvocationTargetException in SpEL's FunctionReference
FunctionReference in the Spring Expression Language (SpEL) currently
does not unwrap an InvocationTargetException; however,
ConstructorReference and MethodReference do.

For example, currently one may encounter an exception like the
following, where the 'null' comes from the fact that an
InvocationTargetException doesn't always have a message.

SpelEvaluationException: EL1023E: A problem occurred whilst attempting
  to invoke the function 'formatObjectVarargs': 'null'

To address that, and to align with the behavior of ConstructorReference
and MethodReference, this commit modifies FunctionReference so that it
unwraps the InvocationTargetException to use its cause for the
exception message, resulting in an exception message like the following.

SpelEvaluationException: EL1023E: A problem occurred whilst attempting
  to invoke the function 'formatObjectVarargs': 'Format specifier '%s''

Closes gh-33174
2024-07-09 13:32:06 +02:00
Sam Brannen defb6b7a62 Polish documentation and implementation of SpEL's Indexer 2024-05-28 15:29:54 +02:00
Sam Brannen 54c07eddcc Merge branch '6.1.x' 2024-05-28 10:26:56 +02:00
Sam Brannen e9de426eb5 Support compilation of map indexing with primitive in SpEL
Prior to this commit, the Spring Expression Language (SpEL) failed to
compile an expression that indexed into a Map using a primitive literal
(boolean, int, long, float, or double).

This commit adds support for compilation of such expressions by
ensuring that primitive literals are boxed into their corresponding
wrapper types in the compiled bytecode.

Closes gh-32903
2024-05-28 10:19:15 +02:00
Sam Brannen 8871d67298 Merge branch '6.1.x' 2024-05-27 17:13:01 +02:00
Sam Brannen cda577d1aa Support compilation of array and list indexing with Integer in SpEL
Prior to this commit, the Spring Expression Language (SpEL) failed to
compile an expression that indexed into any array or list using an
Integer.

This commit adds support for compilation of such expressions by
ensuring that an Integer is unboxed into an int in the compiled
bytecode.

See gh-32694
Closes gh-32908
2024-05-27 17:06:48 +02:00
Sam Brannen d625b3de27 Document SpEL IndexAccessor support in the reference manual
Closes gh-32735
2024-05-15 11:47:42 +02:00
Sam Brannen 716e7de841 Simplify implementation of SpelNodeImpl.loadClassForExitDescriptor(...) 2024-05-14 17:58:05 +02:00
Sam Brannen fc07946e60 Polishing 2024-05-14 15:03:25 +02:00
Sam Brannen 8fe4493a7d Revise compilation support in SpEL for varargs array subtypes
This commit first reverts changes to SpelNodeImpl from the previous
commit in order to reduce the scope of the overall change set.

This commit then implements a different approach to support type-safe
checks for array subtype compatibility.

In order to support backward compatibility, this commit also
reintroduces generateCodeForArguments(MethodVisitor, CodeFlow, Member,
SpelNodeImpl[]) in deprecated form.

See gh-32804
2024-05-14 14:09:35 +02:00