Skip to content

Commit e72b523

Browse files
committed
Polish SpEL support
1 parent 99bdc42 commit e72b523

File tree

10 files changed

+66
-75
lines changed

10 files changed

+66
-75
lines changed

spring-expression/src/main/java/org/springframework/expression/spel/CompilablePropertyAccessor.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -21,7 +21,7 @@
2121
import org.springframework.expression.PropertyAccessor;
2222

2323
/**
24-
* A compilable property accessor is able to generate bytecode that represents
24+
* A compilable {@link PropertyAccessor} is able to generate bytecode that represents
2525
* the access operation, facilitating compilation to bytecode of expressions
2626
* that use the accessor.
2727
*
@@ -41,12 +41,13 @@ public interface CompilablePropertyAccessor extends PropertyAccessor, Opcodes {
4141
Class<?> getPropertyType();
4242

4343
/**
44-
* Generate the bytecode the performs the access operation into the specified MethodVisitor
45-
* using context information from the codeflow where necessary.
44+
* Generate the bytecode the performs the access operation into the specified
45+
* {@link MethodVisitor} using context information from the {@link CodeFlow}
46+
* where necessary.
4647
* @param propertyName the name of the property
47-
* @param mv the Asm method visitor into which code should be generated
48-
* @param cf the current state of the expression compiler
48+
* @param methodVisitor the ASM method visitor into which code should be generated
49+
* @param codeFlow the current state of the expression compiler
4950
*/
50-
void generateCode(String propertyName, MethodVisitor mv, CodeFlow cf);
51+
void generateCode(String propertyName, MethodVisitor methodVisitor, CodeFlow codeFlow);
5152

5253
}

spring-expression/src/main/java/org/springframework/expression/spel/support/DataBindingMethodResolver.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -27,7 +27,7 @@
2727
import org.springframework.lang.Nullable;
2828

2929
/**
30-
* A {@link org.springframework.expression.MethodResolver} variant for data binding
30+
* An {@link org.springframework.expression.MethodResolver} variant for data binding
3131
* purposes, using reflection to access instance methods on a given target object.
3232
*
3333
* <p>This accessor does not resolve static methods and also no technical methods

spring-expression/src/main/java/org/springframework/expression/spel/support/DataBindingPropertyAccessor.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,7 +19,7 @@
1919
import java.lang.reflect.Method;
2020

2121
/**
22-
* A {@link org.springframework.expression.PropertyAccessor} variant for data binding
22+
* An {@link org.springframework.expression.PropertyAccessor} variant for data binding
2323
* purposes, using reflection to access properties for reading and possibly writing.
2424
*
2525
* <p>A property can be referenced through a public getter method (when being read)

spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectionHelper.java

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -503,14 +503,10 @@ enum ArgumentsMatchKind {
503503
* and the set that are being supplied at the point of invocation. If the kind
504504
* indicates that conversion is required for some of the arguments then the arguments
505505
* that require conversion are listed in the argsRequiringConversion array.
506+
*
507+
* @param kind the kind of match that was achieved
506508
*/
507-
static class ArgumentsMatchInfo {
508-
509-
private final ArgumentsMatchKind kind;
510-
511-
ArgumentsMatchInfo(ArgumentsMatchKind kind) {
512-
this.kind = kind;
513-
}
509+
record ArgumentsMatchInfo(ArgumentsMatchKind kind) {
514510

515511
public boolean isExactMatch() {
516512
return (this.kind == ArgumentsMatchKind.EXACT);

spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveConstructorResolver.java

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -33,7 +33,8 @@
3333
import org.springframework.lang.Nullable;
3434

3535
/**
36-
* A constructor resolver that uses reflection to locate the constructor that should be invoked.
36+
* A constructor resolver that uses reflection to locate the constructor that
37+
* should be invoked.
3738
*
3839
* @author Andy Clement
3940
* @author Juergen Hoeller
@@ -42,12 +43,15 @@
4243
public class ReflectiveConstructorResolver implements ConstructorResolver {
4344

4445
/**
45-
* Locate a constructor on the type. There are three kinds of match that might occur:
46+
* Locate a constructor on the type.
47+
* <p>There are three kinds of matches that might occur:
4648
* <ol>
47-
* <li>An exact match where the types of the arguments match the types of the constructor
48-
* <li>An in-exact match where the types we are looking for are subtypes of those defined on the constructor
49-
* <li>A match where we are able to convert the arguments into those expected by the constructor, according to the
50-
* registered type converter.
49+
* <li>An exact match where the types of the arguments match the types of the
50+
* constructor.</li>
51+
* <li>An inexact match where the types we are looking for are subtypes of
52+
* those defined on the constructor.</li>
53+
* <li>A match where we are able to convert the arguments into those expected
54+
* by the constructor, according to the registered type converter.</li>
5155
* </ol>
5256
*/
5357
@Override

spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodExecutor.java

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -87,12 +87,15 @@ public final Method getMethod() {
8787
}
8888

8989
/**
90-
* Find the first public class in the methods declaring class hierarchy that declares this method.
91-
* Sometimes the reflective method discovery logic finds a suitable method that can easily be
92-
* called via reflection but cannot be called from generated code when compiling the expression
93-
* because of visibility restrictions. For example if a non-public class overrides toString(),
94-
* this helper method will walk up the type hierarchy to find the first public type that declares
95-
* the method (if there is one!). For toString() it may walk as far as Object.
90+
* Find the first public class in the method's declaring class hierarchy that
91+
* declares this method.
92+
* <p>Sometimes the reflective method discovery logic finds a suitable method
93+
* that can easily be called via reflection but cannot be called from generated
94+
* code when compiling the expression because of visibility restrictions. For
95+
* example, if a non-public class overrides {@code toString()}, this helper
96+
* method will traverse up the type hierarchy to find the first public type that
97+
* declares the method (if there is one). For {@code toString()}, it may traverse
98+
* as far as Object.
9699
*/
97100
@Nullable
98101
public Class<?> getPublicDeclaringClass() {

spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodResolver.java

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -63,7 +63,7 @@ public class ReflectiveMethodResolver implements MethodResolver {
6363

6464

6565
public ReflectiveMethodResolver() {
66-
this.useDistance = true;
66+
this(true);
6767
}
6868

6969
/**
@@ -100,12 +100,15 @@ public void registerMethodFilter(Class<?> type, @Nullable MethodFilter filter) {
100100
}
101101

102102
/**
103-
* Locate a method on a type. There are three kinds of match that might occur:
103+
* Locate a method on the type.
104+
* <p>There are three kinds of matches that might occur:
104105
* <ol>
105-
* <li>an exact match where the types of the arguments match the types of the constructor
106-
* <li>an in-exact match where the types we are looking for are subtypes of those defined on the constructor
107-
* <li>a match where we are able to convert the arguments into those expected by the constructor,
108-
* according to the registered type converter
106+
* <li>An exact match where the types of the arguments match the types of the
107+
* method.</li>
108+
* <li>An inexact match where the types we are looking for are subtypes of
109+
* those defined on the method.</li>
110+
* <li>A match where we are able to convert the arguments into those expected
111+
* by the method, according to the registered type converter.</li>
109112
* </ol>
110113
*/
111114
@Override

spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -579,18 +579,7 @@ private static boolean isKotlinProperty(Method method, String methodSuffix) {
579579
* Captures the member (method/field) to call reflectively to access a property value
580580
* and the type descriptor for the value returned by the reflective call.
581581
*/
582-
private static class InvokerPair {
583-
584-
final Member member;
585-
586-
final TypeDescriptor typeDescriptor;
587-
588-
public InvokerPair(Member member, TypeDescriptor typeDescriptor) {
589-
this.member = member;
590-
this.typeDescriptor = typeDescriptor;
591-
}
592-
}
593-
582+
private record InvokerPair(Member member, TypeDescriptor typeDescriptor) {}
594583

595584
private static final class PropertyCacheKey implements Comparable<PropertyCacheKey> {
596585

spring-expression/src/main/java/org/springframework/expression/spel/support/SimpleEvaluationContext.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -103,9 +103,9 @@ public final class SimpleEvaluationContext implements EvaluationContext {
103103

104104
private final TypeConverter typeConverter;
105105

106-
private final TypeComparator typeComparator = new StandardTypeComparator();
106+
private final TypeComparator typeComparator = StandardTypeComparator.INSTANCE;
107107

108-
private final OperatorOverloader operatorOverloader = new StandardOperatorOverloader();
108+
private final OperatorOverloader operatorOverloader = StandardOperatorOverloader.INSTANCE;
109109

110110
private final Map<String, Object> variables = new HashMap<>();
111111

@@ -168,7 +168,7 @@ public BeanResolver getBeanResolver() {
168168
/**
169169
* {@code SimpleEvaluationContext} does not support use of type references.
170170
* @return {@code TypeLocator} implementation that raises a
171-
* {@link SpelEvaluationException} with {@link SpelMessage#TYPE_NOT_FOUND}.
171+
* {@link SpelEvaluationException} with {@link SpelMessage#TYPE_NOT_FOUND}
172172
*/
173173
@Override
174174
public TypeLocator getTypeLocator() {
@@ -315,7 +315,6 @@ public Builder withInstanceMethods() {
315315
return this;
316316
}
317317

318-
319318
/**
320319
* Register a custom {@link ConversionService}.
321320
* <p>By default a {@link StandardTypeConverter} backed by a
@@ -327,6 +326,7 @@ public Builder withConversionService(ConversionService conversionService) {
327326
this.typeConverter = new StandardTypeConverter(conversionService);
328327
return this;
329328
}
329+
330330
/**
331331
* Register a custom {@link TypeConverter}.
332332
* <p>By default a {@link StandardTypeConverter} backed by a

spring-expression/src/test/java/org/springframework/expression/spel/support/StandardComponentsTests.java

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616

1717
package org.springframework.expression.spel.support;
1818

19-
import java.util.List;
20-
2119
import org.junit.jupiter.api.Test;
2220

2321
import org.springframework.core.convert.TypeDescriptor;
@@ -31,14 +29,14 @@
3129
import static org.assertj.core.api.Assertions.assertThat;
3230
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
3331

34-
public class StandardComponentsTests {
32+
class StandardComponentsTests {
3533

3634
@Test
37-
void testStandardEvaluationContext() {
35+
void standardEvaluationContext() {
3836
StandardEvaluationContext context = new StandardEvaluationContext();
3937
assertThat(context.getTypeComparator()).isNotNull();
4038

41-
TypeComparator tc = new StandardTypeComparator();
39+
TypeComparator tc = StandardTypeComparator.INSTANCE;
4240
context.setTypeComparator(tc);
4341
assertThat(context.getTypeComparator()).isEqualTo(tc);
4442

@@ -48,28 +46,25 @@ void testStandardEvaluationContext() {
4846
}
4947

5048
@Test
51-
void testStandardOperatorOverloader() throws EvaluationException {
52-
OperatorOverloader oo = new StandardOperatorOverloader();
53-
assertThat(oo.overridesOperation(Operation.ADD, null, null)).isFalse();
54-
assertThatExceptionOfType(EvaluationException.class).isThrownBy(() ->
55-
oo.operate(Operation.ADD, 2, 3));
49+
void standardOperatorOverloader() {
50+
OperatorOverloader overloader = new StandardOperatorOverloader();
51+
assertThat(overloader.overridesOperation(Operation.ADD, null, null)).isFalse();
52+
assertThatExceptionOfType(EvaluationException.class)
53+
.isThrownBy(() -> overloader.operate(Operation.ADD, 2, 3));
5654
}
5755

5856
@Test
59-
void testStandardTypeLocator() {
57+
void standardTypeLocator() {
6058
StandardTypeLocator tl = new StandardTypeLocator();
61-
List<String> prefixes = tl.getImportPrefixes();
62-
assertThat(prefixes).hasSize(1);
59+
assertThat(tl.getImportPrefixes()).hasSize(1);
6360
tl.registerImport("java.util");
64-
prefixes = tl.getImportPrefixes();
65-
assertThat(prefixes).hasSize(2);
61+
assertThat(tl.getImportPrefixes()).hasSize(2);
6662
tl.removeImport("java.util");
67-
prefixes = tl.getImportPrefixes();
68-
assertThat(prefixes).hasSize(1);
63+
assertThat(tl.getImportPrefixes()).hasSize(1);
6964
}
7065

7166
@Test
72-
void testStandardTypeConverter() throws EvaluationException {
67+
void standardTypeConverter() {
7368
TypeConverter tc = new StandardTypeConverter();
7469
tc.convertValue(3, TypeDescriptor.forObject(3), TypeDescriptor.valueOf(Double.class));
7570
}

0 commit comments

Comments
 (0)