Polish SpEL support
This commit is contained in:
@@ -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.asm.Opcodes;
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
@@ -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.expression.MethodExecutor;
|
||||
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.
|
||||
*
|
||||
* <p>This accessor does not resolve static methods and also no technical methods
|
||||
|
||||
@@ -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 @@ package org.springframework.expression.spel.support;
|
||||
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.
|
||||
*
|
||||
* <p>A property can be referenced through a public getter method (when being read)
|
||||
|
||||
@@ -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 @@ public abstract class ReflectionHelper {
|
||||
* 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);
|
||||
|
||||
@@ -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.expression.TypeConverter;
|
||||
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 @@ import org.springframework.lang.Nullable;
|
||||
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.
|
||||
* <p>There are three kinds of matches that might occur:
|
||||
* <ol>
|
||||
* <li>An exact match where the types of the arguments match the types of the constructor
|
||||
* <li>An in-exact match where the types we are looking for are subtypes of those defined on the constructor
|
||||
* <li>A match where we are able to convert the arguments into those expected by the constructor, according to the
|
||||
* registered type converter.
|
||||
* <li>An exact match where the types of the arguments match the types of the
|
||||
* constructor.</li>
|
||||
* <li>An inexact match where the types we are looking for are subtypes of
|
||||
* those defined on the constructor.</li>
|
||||
* <li>A match where we are able to convert the arguments into those expected
|
||||
* by the constructor, according to the registered type converter.</li>
|
||||
* </ol>
|
||||
*/
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -87,12 +87,15 @@ public class ReflectiveMethodExecutor implements MethodExecutor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the first public class in the methods declaring class hierarchy that declares this method.
|
||||
* 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 toString(),
|
||||
* this helper method will walk up the type hierarchy to find the first public type that declares
|
||||
* the method (if there is one!). For toString() it may walk as far as Object.
|
||||
* Find the first public class in the method's declaring class hierarchy that
|
||||
* declares this method.
|
||||
* <p>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() {
|
||||
|
||||
@@ -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 class ReflectiveMethodResolver implements MethodResolver {
|
||||
}
|
||||
|
||||
/**
|
||||
* Locate a method on a type. There are three kinds of match that might occur:
|
||||
* Locate a method on the type.
|
||||
* <p>There are three kinds of matches that might occur:
|
||||
* <ol>
|
||||
* <li>an exact match where the types of the arguments match the types of the constructor
|
||||
* <li>an in-exact match where the types we are looking for are subtypes of those defined on the constructor
|
||||
* <li>a match where we are able to convert the arguments into those expected by the constructor,
|
||||
* according to the registered type converter
|
||||
* <li>An exact match where the types of the arguments match the types of the
|
||||
* method.</li>
|
||||
* <li>An inexact match where the types we are looking for are subtypes of
|
||||
* those defined on the method.</li>
|
||||
* <li>A match where we are able to convert the arguments into those expected
|
||||
* by the method, according to the registered type converter.</li>
|
||||
* </ol>
|
||||
*/
|
||||
@Override
|
||||
|
||||
@@ -579,18 +579,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
|
||||
* Captures the member (method/field) to call reflectively to access a property value
|
||||
* and the type descriptor for the value returned by the reflective call.
|
||||
*/
|
||||
private static class InvokerPair {
|
||||
|
||||
final Member member;
|
||||
|
||||
final TypeDescriptor typeDescriptor;
|
||||
|
||||
public InvokerPair(Member member, TypeDescriptor typeDescriptor) {
|
||||
this.member = member;
|
||||
this.typeDescriptor = typeDescriptor;
|
||||
}
|
||||
}
|
||||
|
||||
private record InvokerPair(Member member, TypeDescriptor typeDescriptor) {}
|
||||
|
||||
private static final class PropertyCacheKey implements Comparable<PropertyCacheKey> {
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -103,9 +103,9 @@ public final class SimpleEvaluationContext implements EvaluationContext {
|
||||
|
||||
private final TypeConverter typeConverter;
|
||||
|
||||
private final TypeComparator typeComparator = new StandardTypeComparator();
|
||||
private final TypeComparator typeComparator = StandardTypeComparator.INSTANCE;
|
||||
|
||||
private final OperatorOverloader operatorOverloader = new StandardOperatorOverloader();
|
||||
private final OperatorOverloader operatorOverloader = StandardOperatorOverloader.INSTANCE;
|
||||
|
||||
private final Map<String, Object> variables = new HashMap<>();
|
||||
|
||||
@@ -168,7 +168,7 @@ public final class SimpleEvaluationContext implements EvaluationContext {
|
||||
/**
|
||||
* {@code SimpleEvaluationContext} does not support use of type references.
|
||||
* @return {@code TypeLocator} implementation that raises a
|
||||
* {@link SpelEvaluationException} with {@link SpelMessage#TYPE_NOT_FOUND}.
|
||||
* {@link SpelEvaluationException} with {@link SpelMessage#TYPE_NOT_FOUND}
|
||||
*/
|
||||
@Override
|
||||
public TypeLocator getTypeLocator() {
|
||||
@@ -315,7 +315,6 @@ public final class SimpleEvaluationContext implements EvaluationContext {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register a custom {@link ConversionService}.
|
||||
* <p>By default a {@link StandardTypeConverter} backed by a
|
||||
@@ -327,6 +326,7 @@ public final class SimpleEvaluationContext implements EvaluationContext {
|
||||
this.typeConverter = new StandardTypeConverter(conversionService);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a custom {@link TypeConverter}.
|
||||
* <p>By default a {@link StandardTypeConverter} backed by a
|
||||
|
||||
@@ -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 org.springframework.expression.TypeLocator;
|
||||
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 @@ public class StandardComponentsTests {
|
||||
}
|
||||
|
||||
@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<String> prefixes = tl.getImportPrefixes();
|
||||
assertThat(prefixes).hasSize(1);
|
||||
assertThat(tl.getImportPrefixes()).hasSize(1);
|
||||
tl.registerImport("java.util");
|
||||
prefixes = tl.getImportPrefixes();
|
||||
assertThat(prefixes).hasSize(2);
|
||||
assertThat(tl.getImportPrefixes()).hasSize(2);
|
||||
tl.removeImport("java.util");
|
||||
prefixes = tl.getImportPrefixes();
|
||||
assertThat(prefixes).hasSize(1);
|
||||
assertThat(tl.getImportPrefixes()).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStandardTypeConverter() throws EvaluationException {
|
||||
void standardTypeConverter() {
|
||||
TypeConverter tc = new StandardTypeConverter();
|
||||
tc.convertValue(3, TypeDescriptor.forObject(3), TypeDescriptor.valueOf(Double.class));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user