From e72b523995db89d7de4f3f4a31b1ac9e1f2d0f93 Mon Sep 17 00:00:00 2001 From: Sam Brannen <104798+sbrannen@users.noreply.github.com> Date: Fri, 9 Feb 2024 13:46:44 +0100 Subject: [PATCH] Polish SpEL support --- .../spel/CompilablePropertyAccessor.java | 15 ++++----- .../support/DataBindingMethodResolver.java | 4 +-- .../support/DataBindingPropertyAccessor.java | 4 +-- .../spel/support/ReflectionHelper.java | 12 +++---- .../ReflectiveConstructorResolver.java | 18 ++++++----- .../support/ReflectiveMethodExecutor.java | 17 +++++----- .../support/ReflectiveMethodResolver.java | 17 +++++----- .../support/ReflectivePropertyAccessor.java | 13 +------- .../spel/support/SimpleEvaluationContext.java | 10 +++--- .../spel/support/StandardComponentsTests.java | 31 ++++++++----------- 10 files changed, 66 insertions(+), 75 deletions(-) diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/CompilablePropertyAccessor.java b/spring-expression/src/main/java/org/springframework/expression/spel/CompilablePropertyAccessor.java index 634267d75bc2..6651bd688878 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/CompilablePropertyAccessor.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/CompilablePropertyAccessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,7 +21,7 @@ import org.springframework.expression.PropertyAccessor; /** - * A compilable property accessor is able to generate bytecode that represents + * A compilable {@link PropertyAccessor} is able to generate bytecode that represents * the access operation, facilitating compilation to bytecode of expressions * that use the accessor. * @@ -41,12 +41,13 @@ public interface CompilablePropertyAccessor extends PropertyAccessor, Opcodes { Class> getPropertyType(); /** - * Generate the bytecode the performs the access operation into the specified MethodVisitor - * using context information from the codeflow where necessary. + * Generate the bytecode the performs the access operation into the specified + * {@link MethodVisitor} using context information from the {@link CodeFlow} + * where necessary. * @param propertyName the name of the property - * @param mv the Asm method visitor into which code should be generated - * @param cf the current state of the expression compiler + * @param methodVisitor the ASM method visitor into which code should be generated + * @param codeFlow the current state of the expression compiler */ - void generateCode(String propertyName, MethodVisitor mv, CodeFlow cf); + void generateCode(String propertyName, MethodVisitor methodVisitor, CodeFlow codeFlow); } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/DataBindingMethodResolver.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/DataBindingMethodResolver.java index 36dbeb10e7b4..120bb0806173 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/support/DataBindingMethodResolver.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/DataBindingMethodResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2024 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. @@ -27,7 +27,7 @@ import org.springframework.lang.Nullable; /** - * A {@link org.springframework.expression.MethodResolver} variant for data binding + * An {@link org.springframework.expression.MethodResolver} variant for data binding * purposes, using reflection to access instance methods on a given target object. * *
This accessor does not resolve static methods and also no technical methods diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/DataBindingPropertyAccessor.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/DataBindingPropertyAccessor.java index 6dbe01b6adec..187fb16e7f5b 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/support/DataBindingPropertyAccessor.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/DataBindingPropertyAccessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2024 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,7 +19,7 @@ import java.lang.reflect.Method; /** - * A {@link org.springframework.expression.PropertyAccessor} variant for data binding + * An {@link org.springframework.expression.PropertyAccessor} variant for data binding * purposes, using reflection to access properties for reading and possibly writing. * *
A property can be referenced through a public getter method (when being read) diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectionHelper.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectionHelper.java index c35641f2daa6..24b8934ff55f 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectionHelper.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectionHelper.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 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. @@ -503,14 +503,10 @@ enum ArgumentsMatchKind { * and the set that are being supplied at the point of invocation. If the kind * indicates that conversion is required for some of the arguments then the arguments * that require conversion are listed in the argsRequiringConversion array. + * + * @param kind the kind of match that was achieved */ - static class ArgumentsMatchInfo { - - private final ArgumentsMatchKind kind; - - ArgumentsMatchInfo(ArgumentsMatchKind kind) { - this.kind = kind; - } + record ArgumentsMatchInfo(ArgumentsMatchKind kind) { public boolean isExactMatch() { return (this.kind == ArgumentsMatchKind.EXACT); diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveConstructorResolver.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveConstructorResolver.java index 8ec11fabecb7..ba55a8ae83ef 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveConstructorResolver.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveConstructorResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2024 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,8 @@ import org.springframework.lang.Nullable; /** - * A constructor resolver that uses reflection to locate the constructor that should be invoked. + * A constructor resolver that uses reflection to locate the constructor that + * should be invoked. * * @author Andy Clement * @author Juergen Hoeller @@ -42,12 +43,15 @@ public class ReflectiveConstructorResolver implements ConstructorResolver { /** - * Locate a constructor on the type. There are three kinds of match that might occur: + * Locate a constructor on the type. + *
There are three kinds of matches that might occur: *
Sometimes the reflective method discovery logic finds a suitable method + * that can easily be called via reflection but cannot be called from generated + * code when compiling the expression because of visibility restrictions. For + * example, if a non-public class overrides {@code toString()}, this helper + * method will traverse up the type hierarchy to find the first public type that + * declares the method (if there is one). For {@code toString()}, it may traverse + * as far as Object. */ @Nullable public Class> getPublicDeclaringClass() { diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodResolver.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodResolver.java index c4ce19aa3d78..dbf696c13a2e 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodResolver.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 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. @@ -63,7 +63,7 @@ public class ReflectiveMethodResolver implements MethodResolver { public ReflectiveMethodResolver() { - this.useDistance = true; + this(true); } /** @@ -100,12 +100,15 @@ public void registerMethodFilter(Class> type, @Nullable MethodFilter filter) { } /** - * Locate a method on a type. There are three kinds of match that might occur: + * Locate a method on the type. + *
There are three kinds of matches that might occur: *
By default a {@link StandardTypeConverter} backed by a @@ -327,6 +326,7 @@ public Builder withConversionService(ConversionService conversionService) { this.typeConverter = new StandardTypeConverter(conversionService); return this; } + /** * Register a custom {@link TypeConverter}. *
By default a {@link StandardTypeConverter} backed by a
diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/support/StandardComponentsTests.java b/spring-expression/src/test/java/org/springframework/expression/spel/support/StandardComponentsTests.java
index 9fa206165a1c..aff6b030706c 100644
--- a/spring-expression/src/test/java/org/springframework/expression/spel/support/StandardComponentsTests.java
+++ b/spring-expression/src/test/java/org/springframework/expression/spel/support/StandardComponentsTests.java
@@ -16,8 +16,6 @@
package org.springframework.expression.spel.support;
-import java.util.List;
-
import org.junit.jupiter.api.Test;
import org.springframework.core.convert.TypeDescriptor;
@@ -31,14 +29,14 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
-public class StandardComponentsTests {
+class StandardComponentsTests {
@Test
- void testStandardEvaluationContext() {
+ void standardEvaluationContext() {
StandardEvaluationContext context = new StandardEvaluationContext();
assertThat(context.getTypeComparator()).isNotNull();
- TypeComparator tc = new StandardTypeComparator();
+ TypeComparator tc = StandardTypeComparator.INSTANCE;
context.setTypeComparator(tc);
assertThat(context.getTypeComparator()).isEqualTo(tc);
@@ -48,28 +46,25 @@ void testStandardEvaluationContext() {
}
@Test
- void testStandardOperatorOverloader() throws EvaluationException {
- OperatorOverloader oo = new StandardOperatorOverloader();
- assertThat(oo.overridesOperation(Operation.ADD, null, null)).isFalse();
- assertThatExceptionOfType(EvaluationException.class).isThrownBy(() ->
- oo.operate(Operation.ADD, 2, 3));
+ void standardOperatorOverloader() {
+ OperatorOverloader overloader = new StandardOperatorOverloader();
+ assertThat(overloader.overridesOperation(Operation.ADD, null, null)).isFalse();
+ assertThatExceptionOfType(EvaluationException.class)
+ .isThrownBy(() -> overloader.operate(Operation.ADD, 2, 3));
}
@Test
- void testStandardTypeLocator() {
+ void standardTypeLocator() {
StandardTypeLocator tl = new StandardTypeLocator();
- List