Switch to JSpecify annotations

This commit updates the whole Spring Framework codebase to use JSpecify
annotations instead of Spring null-safety annotations with JSR 305
semantics.

JSpecify provides signficant enhancements such as properly defined
specifications, a canonical dependency with no split-package issue,
better tooling, better Kotlin integration and the capability to specify
generic type, array and varargs element null-safety. Generic type
null-safety is not defined by this commit yet and will be specified
later.

A key difference is that Spring null-safety annotations, following
JSR 305 semantics, apply to fields, parameters and return values,
while JSpecify annotations apply to type usages. That's why this
commit moves nullability annotations closer to the type for fields
and return values.

See gh-28797
This commit is contained in:
Sébastien Deleuze
2024-12-03 15:22:37 +01:00
parent fcb8aed03f
commit bc5d771a06
3459 changed files with 14118 additions and 22059 deletions

View File

@@ -18,8 +18,9 @@ package org.springframework.expression;
import java.util.List;
import org.jspecify.annotations.Nullable;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.lang.Nullable;
/**
* A constructor resolver attempts to locate a constructor and returns a
@@ -50,8 +51,7 @@ public interface ConstructorResolver {
* @return a {@code ConstructorExecutor} that can invoke the constructor,
* or {@code null} if the constructor cannot be found
*/
@Nullable
ConstructorExecutor resolve(EvaluationContext context, String typeName, List<TypeDescriptor> argumentTypes)
@Nullable ConstructorExecutor resolve(EvaluationContext context, String typeName, List<TypeDescriptor> argumentTypes)
throws AccessException;
}

View File

@@ -20,7 +20,7 @@ import java.util.Collections;
import java.util.List;
import java.util.function.Supplier;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* Expressions are executed in an evaluation context. It is in this context that
@@ -89,8 +89,7 @@ public interface EvaluationContext {
/**
* Return a bean resolver that can look up beans by name.
*/
@Nullable
BeanResolver getBeanResolver();
@Nullable BeanResolver getBeanResolver();
/**
* Return a type locator that can be used to find types, either by short or
@@ -150,8 +149,7 @@ public interface EvaluationContext {
* @param name the name of the variable to look up
* @return the value of the variable, or {@code null} if not found
*/
@Nullable
Object lookupVariable(String name);
@Nullable Object lookupVariable(String name);
/**
* Determine if assignment is enabled within expressions evaluated by this evaluation

View File

@@ -16,7 +16,7 @@
package org.springframework.expression;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* Represent an exception that occurs during expression evaluation.

View File

@@ -16,8 +16,9 @@
package org.springframework.expression;
import org.jspecify.annotations.Nullable;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.lang.Nullable;
/**
* An expression capable of evaluating itself against context objects.
@@ -44,8 +45,7 @@ public interface Expression {
* @return the evaluation result
* @throws EvaluationException if there is a problem during evaluation
*/
@Nullable
Object getValue() throws EvaluationException;
@Nullable Object getValue() throws EvaluationException;
/**
* Evaluate this expression in the default context and return the result of evaluation.
@@ -55,8 +55,7 @@ public interface Expression {
* @return the evaluation result
* @throws EvaluationException if there is a problem during evaluation
*/
@Nullable
<T> T getValue(@Nullable Class<T> desiredResultType) throws EvaluationException;
<T> @Nullable T getValue(@Nullable Class<T> desiredResultType) throws EvaluationException;
/**
* Evaluate this expression in the default context against the specified root object
@@ -65,8 +64,7 @@ public interface Expression {
* @return the evaluation result
* @throws EvaluationException if there is a problem during evaluation
*/
@Nullable
Object getValue(@Nullable Object rootObject) throws EvaluationException;
@Nullable Object getValue(@Nullable Object rootObject) throws EvaluationException;
/**
* Evaluate this expression in the default context against the specified root object
@@ -78,8 +76,7 @@ public interface Expression {
* @return the evaluation result
* @throws EvaluationException if there is a problem during evaluation
*/
@Nullable
<T> T getValue(@Nullable Object rootObject, @Nullable Class<T> desiredResultType)
<T> @Nullable T getValue(@Nullable Object rootObject, @Nullable Class<T> desiredResultType)
throws EvaluationException;
/**
@@ -88,8 +85,7 @@ public interface Expression {
* @return the evaluation result
* @throws EvaluationException if there is a problem during evaluation
*/
@Nullable
Object getValue(EvaluationContext context) throws EvaluationException;
@Nullable Object getValue(EvaluationContext context) throws EvaluationException;
/**
* Evaluate this expression in the provided context against the specified root object
@@ -101,8 +97,7 @@ public interface Expression {
* @return the evaluation result
* @throws EvaluationException if there is a problem during evaluation
*/
@Nullable
Object getValue(EvaluationContext context, @Nullable Object rootObject) throws EvaluationException;
@Nullable Object getValue(EvaluationContext context, @Nullable Object rootObject) throws EvaluationException;
/**
* Evaluate this expression in the provided context and return the result of evaluation.
@@ -113,8 +108,7 @@ public interface Expression {
* @return the evaluation result
* @throws EvaluationException if there is a problem during evaluation
*/
@Nullable
<T> T getValue(EvaluationContext context, @Nullable Class<T> desiredResultType)
<T> @Nullable T getValue(EvaluationContext context, @Nullable Class<T> desiredResultType)
throws EvaluationException;
/**
@@ -130,8 +124,7 @@ public interface Expression {
* @return the evaluation result
* @throws EvaluationException if there is a problem during evaluation
*/
@Nullable
<T> T getValue(EvaluationContext context, @Nullable Object rootObject, @Nullable Class<T> desiredResultType)
<T> @Nullable T getValue(EvaluationContext context, @Nullable Object rootObject, @Nullable Class<T> desiredResultType)
throws EvaluationException;
/**
@@ -140,8 +133,7 @@ public interface Expression {
* @return the most general type of value that can be set in this context
* @throws EvaluationException if there is a problem determining the type
*/
@Nullable
Class<?> getValueType() throws EvaluationException;
@Nullable Class<?> getValueType() throws EvaluationException;
/**
* Return the most general type that can be passed to the
@@ -150,8 +142,7 @@ public interface Expression {
* @return the most general type of value that can be set in this context
* @throws EvaluationException if there is a problem determining the type
*/
@Nullable
Class<?> getValueType(@Nullable Object rootObject) throws EvaluationException;
@Nullable Class<?> getValueType(@Nullable Object rootObject) throws EvaluationException;
/**
* Return the most general type that can be passed to the
@@ -160,8 +151,7 @@ public interface Expression {
* @return the most general type of value that can be set in this context
* @throws EvaluationException if there is a problem determining the type
*/
@Nullable
Class<?> getValueType(EvaluationContext context) throws EvaluationException;
@Nullable Class<?> getValueType(EvaluationContext context) throws EvaluationException;
/**
* Return the most general type that can be passed to the
@@ -173,8 +163,7 @@ public interface Expression {
* @return the most general type of value that can be set in this context
* @throws EvaluationException if there is a problem determining the type
*/
@Nullable
Class<?> getValueType(EvaluationContext context, @Nullable Object rootObject) throws EvaluationException;
@Nullable Class<?> getValueType(EvaluationContext context, @Nullable Object rootObject) throws EvaluationException;
/**
* Return a descriptor for the most general type that can be passed to one of
@@ -182,8 +171,7 @@ public interface Expression {
* @return a type descriptor for values that can be set in this context
* @throws EvaluationException if there is a problem determining the type
*/
@Nullable
TypeDescriptor getValueTypeDescriptor() throws EvaluationException;
@Nullable TypeDescriptor getValueTypeDescriptor() throws EvaluationException;
/**
* Return a descriptor for the most general type that can be passed to the
@@ -192,8 +180,7 @@ public interface Expression {
* @return a type descriptor for values that can be set in this context
* @throws EvaluationException if there is a problem determining the type
*/
@Nullable
TypeDescriptor getValueTypeDescriptor(@Nullable Object rootObject) throws EvaluationException;
@Nullable TypeDescriptor getValueTypeDescriptor(@Nullable Object rootObject) throws EvaluationException;
/**
* Return a descriptor for the most general type that can be passed to the
@@ -202,8 +189,7 @@ public interface Expression {
* @return a type descriptor for values that can be set in this context
* @throws EvaluationException if there is a problem determining the type
*/
@Nullable
TypeDescriptor getValueTypeDescriptor(EvaluationContext context) throws EvaluationException;
@Nullable TypeDescriptor getValueTypeDescriptor(EvaluationContext context) throws EvaluationException;
/**
* Return a descriptor for the most general type that can be passed to the
@@ -216,8 +202,7 @@ public interface Expression {
* @return a type descriptor for values that can be set in this context
* @throws EvaluationException if there is a problem determining the type
*/
@Nullable
TypeDescriptor getValueTypeDescriptor(EvaluationContext context, @Nullable Object rootObject)
@Nullable TypeDescriptor getValueTypeDescriptor(EvaluationContext context, @Nullable Object rootObject)
throws EvaluationException;
/**

View File

@@ -16,7 +16,7 @@
package org.springframework.expression;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* Superclass for exceptions that can occur whilst processing expressions.
@@ -28,8 +28,7 @@ import org.springframework.lang.Nullable;
@SuppressWarnings("serial")
public class ExpressionException extends RuntimeException {
@Nullable
protected final String expressionString;
protected final @Nullable String expressionString;
protected int position; // -1 if not known; should be known in all reasonable cases
@@ -105,8 +104,7 @@ public class ExpressionException extends RuntimeException {
/**
* Return the expression string.
*/
@Nullable
public final String getExpressionString() {
public final @Nullable String getExpressionString() {
return this.expressionString;
}

View File

@@ -16,7 +16,7 @@
package org.springframework.expression;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* This exception wraps (as cause) a checked exception thrown by some method that SpEL

View File

@@ -16,7 +16,7 @@
package org.springframework.expression;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* An index accessor is able to read from and possibly write to an indexed

View File

@@ -18,8 +18,9 @@ package org.springframework.expression;
import java.util.List;
import org.jspecify.annotations.Nullable;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.lang.Nullable;
/**
* A method resolver attempts to locate a method and returns a
@@ -50,8 +51,7 @@ public interface MethodResolver {
* @return a {@code MethodExecutor} that can invoke the method, or {@code null}
* if the method cannot be found
*/
@Nullable
MethodExecutor resolve(EvaluationContext context, Object targetObject, String name,
@Nullable MethodExecutor resolve(EvaluationContext context, Object targetObject, String name,
List<TypeDescriptor> argumentTypes) throws AccessException;
}

View File

@@ -16,7 +16,7 @@
package org.springframework.expression;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* By default, the mathematical operators defined in {@link Operation} support simple

View File

@@ -16,7 +16,7 @@
package org.springframework.expression;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* Represent an exception that occurs during expression parsing.

View File

@@ -16,7 +16,7 @@
package org.springframework.expression;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* A property accessor is able to read from (and possibly write to) an object's

View File

@@ -16,7 +16,7 @@
package org.springframework.expression;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* Strategy for types that access elements of specific target classes.
@@ -52,7 +52,6 @@ public interface TargetedAccessor {
* @return an array of classes that this accessor is suitable for
* (or {@code null} or an empty array if a generic accessor)
*/
@Nullable
Class<?>[] getSpecificTargetClasses();
Class<?> @Nullable [] getSpecificTargetClasses();
}

View File

@@ -16,7 +16,7 @@
package org.springframework.expression;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* Instances of a type comparator should be able to compare pairs of objects for equality.

View File

@@ -16,8 +16,9 @@
package org.springframework.expression;
import org.jspecify.annotations.Nullable;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.lang.Nullable;
/**
* A type converter can convert values between different types encountered during
@@ -54,7 +55,6 @@ public interface TypeConverter {
* @return the converted value
* @throws EvaluationException if conversion failed or is not possible to begin with
*/
@Nullable
Object convertValue(@Nullable Object value, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType);
@Nullable Object convertValue(@Nullable Object value, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType);
}

View File

@@ -16,8 +16,9 @@
package org.springframework.expression;
import org.jspecify.annotations.Nullable;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
/**
@@ -38,11 +39,9 @@ public class TypedValue {
public static final TypedValue NULL = new TypedValue(null);
@Nullable
private final Object value;
private final @Nullable Object value;
@Nullable
private TypeDescriptor typeDescriptor;
private @Nullable TypeDescriptor typeDescriptor;
/**
@@ -67,13 +66,11 @@ public class TypedValue {
}
@Nullable
public Object getValue() {
public @Nullable Object getValue() {
return this.value;
}
@Nullable
public TypeDescriptor getTypeDescriptor() {
public @Nullable TypeDescriptor getTypeDescriptor() {
if (this.typeDescriptor == null && this.value != null) {
this.typeDescriptor = TypeDescriptor.forObject(this.value);
}

View File

@@ -16,12 +16,13 @@
package org.springframework.expression.common;
import org.jspecify.annotations.Nullable;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.Expression;
import org.springframework.expression.TypedValue;
import org.springframework.lang.Nullable;
/**
* Represents a template expression broken into pieces.
@@ -78,8 +79,7 @@ public class CompositeStringExpression implements Expression {
}
@Override
@Nullable
public <T> T getValue(@Nullable Class<T> expectedResultType) throws EvaluationException {
public <T> @Nullable T getValue(@Nullable Class<T> expectedResultType) throws EvaluationException {
String value = getValue();
return ExpressionUtils.convertTypedValue(null, new TypedValue(value), expectedResultType);
}
@@ -97,8 +97,7 @@ public class CompositeStringExpression implements Expression {
}
@Override
@Nullable
public <T> T getValue(@Nullable Object rootObject, @Nullable Class<T> desiredResultType) throws EvaluationException {
public <T> @Nullable T getValue(@Nullable Object rootObject, @Nullable Class<T> desiredResultType) throws EvaluationException {
String value = getValue(rootObject);
return ExpressionUtils.convertTypedValue(null, new TypedValue(value), desiredResultType);
}
@@ -116,8 +115,7 @@ public class CompositeStringExpression implements Expression {
}
@Override
@Nullable
public <T> T getValue(EvaluationContext context, @Nullable Class<T> expectedResultType)
public <T> @Nullable T getValue(EvaluationContext context, @Nullable Class<T> expectedResultType)
throws EvaluationException {
String value = getValue(context);
@@ -137,8 +135,7 @@ public class CompositeStringExpression implements Expression {
}
@Override
@Nullable
public <T> T getValue(EvaluationContext context, @Nullable Object rootObject, @Nullable Class<T> desiredResultType)
public <T> @Nullable T getValue(EvaluationContext context, @Nullable Object rootObject, @Nullable Class<T> desiredResultType)
throws EvaluationException {
String value = getValue(context,rootObject);

View File

@@ -16,12 +16,13 @@
package org.springframework.expression.common;
import org.jspecify.annotations.Nullable;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypeConverter;
import org.springframework.expression.TypedValue;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
/**
@@ -45,8 +46,7 @@ public abstract class ExpressionUtils {
* of the value to the specified type is not supported
*/
@SuppressWarnings("unchecked")
@Nullable
public static <T> T convertTypedValue(
public static <T> @Nullable T convertTypedValue(
@Nullable EvaluationContext context, TypedValue typedValue, @Nullable Class<T> targetType) {
Object value = typedValue.getValue();

View File

@@ -16,12 +16,13 @@
package org.springframework.expression.common;
import org.jspecify.annotations.Nullable;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.Expression;
import org.springframework.expression.TypedValue;
import org.springframework.lang.Nullable;
/**
* A very simple, hard-coded implementation of the {@link Expression} interface
@@ -62,8 +63,7 @@ public class LiteralExpression implements Expression {
}
@Override
@Nullable
public <T> T getValue(@Nullable Class<T> expectedResultType) throws EvaluationException {
public <T> @Nullable T getValue(@Nullable Class<T> expectedResultType) throws EvaluationException {
String value = getValue();
return ExpressionUtils.convertTypedValue(null, new TypedValue(value), expectedResultType);
}
@@ -74,8 +74,7 @@ public class LiteralExpression implements Expression {
}
@Override
@Nullable
public <T> T getValue(@Nullable Object rootObject, @Nullable Class<T> desiredResultType) throws EvaluationException {
public <T> @Nullable T getValue(@Nullable Object rootObject, @Nullable Class<T> desiredResultType) throws EvaluationException {
String value = getValue(rootObject);
return ExpressionUtils.convertTypedValue(null, new TypedValue(value), desiredResultType);
}
@@ -86,8 +85,7 @@ public class LiteralExpression implements Expression {
}
@Override
@Nullable
public <T> T getValue(EvaluationContext context, @Nullable Class<T> expectedResultType) throws EvaluationException {
public <T> @Nullable T getValue(EvaluationContext context, @Nullable Class<T> expectedResultType) throws EvaluationException {
String value = getValue(context);
return ExpressionUtils.convertTypedValue(context, new TypedValue(value), expectedResultType);
}
@@ -98,8 +96,7 @@ public class LiteralExpression implements Expression {
}
@Override
@Nullable
public <T> T getValue(EvaluationContext context, @Nullable Object rootObject, @Nullable Class<T> desiredResultType)
public <T> @Nullable T getValue(EvaluationContext context, @Nullable Object rootObject, @Nullable Class<T> desiredResultType)
throws EvaluationException {
String value = getValue(context, rootObject);

View File

@@ -21,11 +21,12 @@ import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
import org.jspecify.annotations.Nullable;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParseException;
import org.springframework.expression.ParserContext;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**

View File

@@ -1,9 +1,7 @@
/**
* Common utility classes behind the <em>Spring Expression Language</em>.
*/
@NonNullApi
@NonNullFields
@NullMarked
package org.springframework.expression.common;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
import org.jspecify.annotations.NullMarked;

View File

@@ -1,9 +1,7 @@
/**
* Core abstractions behind the <em>Spring Expression Language</em>.
*/
@NonNullApi
@NonNullFields
@NullMarked
package org.springframework.expression;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
import org.jspecify.annotations.NullMarked;

View File

@@ -23,11 +23,12 @@ import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
import org.jspecify.annotations.Nullable;
import org.springframework.asm.ClassWriter;
import org.springframework.asm.MethodVisitor;
import org.springframework.asm.Opcodes;
import org.springframework.lang.Contract;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
@@ -69,8 +70,7 @@ public class CodeFlow implements Opcodes {
* they can register to add a field to this class. Any registered FieldAdders
* will be called after the main evaluation function has finished being generated.
*/
@Nullable
private List<FieldAdder> fieldAdders;
private @Nullable List<FieldAdder> fieldAdders;
/**
* As SpEL AST nodes are called to generate code for the main evaluation method
@@ -78,8 +78,7 @@ public class CodeFlow implements Opcodes {
* registered ClinitAdders will be called after the main evaluation function
* has finished being generated.
*/
@Nullable
private List<ClinitAdder> clinitAdders;
private @Nullable List<ClinitAdder> clinitAdders;
/**
* When code generation requires holding a value in a class level field, this
@@ -157,8 +156,7 @@ public class CodeFlow implements Opcodes {
/**
* Return the descriptor for the item currently on top of the stack (in the current scope).
*/
@Nullable
public String lastDescriptor() {
public @Nullable String lastDescriptor() {
return CollectionUtils.lastElement(this.compilationScopes.peek());
}

View File

@@ -16,9 +16,10 @@
package org.springframework.expression.spel;
import org.jspecify.annotations.Nullable;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException;
import org.springframework.lang.Nullable;
/**
* Base superclass for compiled expressions. Each generated compiled expression class

View File

@@ -22,6 +22,8 @@ import java.util.List;
import java.util.NoSuchElementException;
import java.util.function.Supplier;
import org.jspecify.annotations.Nullable;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException;
@@ -31,7 +33,6 @@ import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.TypeComparator;
import org.springframework.expression.TypeConverter;
import org.springframework.expression.TypedValue;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
@@ -59,8 +60,7 @@ public class ExpressionState {
private final SpelParserConfiguration configuration;
@Nullable
private Deque<TypedValue> contextObjects;
private @Nullable Deque<TypedValue> contextObjects;
// When entering a new scope there is a new base object which should be used
// for '#this' references (or to act as a target for unqualified references).
@@ -69,8 +69,7 @@ public class ExpressionState {
// #list1.?[#list2.contains(#this)]
// On entering the selection we enter a new scope, and #this is now the
// element from list1.
@Nullable
private Deque<TypedValue> scopeRootObjects;
private @Nullable Deque<TypedValue> scopeRootObjects;
public ExpressionState(EvaluationContext context) {
@@ -190,8 +189,7 @@ public class ExpressionState {
return result;
}
@Nullable
public Object convertValue(TypedValue value, TypeDescriptor targetTypeDescriptor) throws EvaluationException {
public @Nullable Object convertValue(TypedValue value, TypeDescriptor targetTypeDescriptor) throws EvaluationException {
Object val = value.getValue();
return this.relatedContext.getTypeConverter().convertValue(
val, TypeDescriptor.forObject(val), targetTypeDescriptor);

View File

@@ -16,7 +16,7 @@
package org.springframework.expression.spel;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* Wraps a real parse exception. This exception flows to the top parse method and then
@@ -33,8 +33,7 @@ public class InternalParseException extends RuntimeException {
}
@Override
@Nullable
public SpelParseException getCause() {
public @Nullable SpelParseException getCause() {
return (SpelParseException) super.getCause();
}

View File

@@ -16,8 +16,9 @@
package org.springframework.expression.spel;
import org.jspecify.annotations.Nullable;
import org.springframework.expression.EvaluationException;
import org.springframework.lang.Nullable;
/**
* Root exception for Spring EL related exceptions.
@@ -36,8 +37,7 @@ public class SpelEvaluationException extends EvaluationException {
private final SpelMessage message;
@Nullable
private final Object[] inserts;
private final @Nullable Object[] inserts;
public SpelEvaluationException(SpelMessage message, @Nullable Object... inserts) {
@@ -82,8 +82,7 @@ public class SpelEvaluationException extends EvaluationException {
/**
* Return the message inserts.
*/
@Nullable
public Object[] getInserts() {
public @Nullable Object @Nullable [] getInserts() {
return this.inserts;
}

View File

@@ -18,7 +18,7 @@ package org.springframework.expression.spel;
import java.text.MessageFormat;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* Contains all the messages that can be produced by the Spring Expression Language.

View File

@@ -16,10 +16,11 @@
package org.springframework.expression.spel;
import org.jspecify.annotations.Nullable;
import org.springframework.asm.MethodVisitor;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypedValue;
import org.springframework.lang.Nullable;
/**
* Represents a node in the abstract syntax tree (AST) for a parsed Spring
@@ -38,8 +39,7 @@ public interface SpelNode {
* @return the value of this node evaluated against the specified state
* @throws EvaluationException if any problem occurs evaluating the expression
*/
@Nullable
Object getValue(ExpressionState expressionState) throws EvaluationException;
@Nullable Object getValue(ExpressionState expressionState) throws EvaluationException;
/**
* Evaluate the expression node in the context of the supplied expression state
@@ -96,8 +96,7 @@ public interface SpelNode {
* @return the class of the object if it is not already a class object,
* or {@code null} if the object is {@code null}
*/
@Nullable
Class<?> getObjectClass(@Nullable Object obj);
@Nullable Class<?> getObjectClass(@Nullable Object obj);
/**
* Return the start position of this AST node in the expression string.

View File

@@ -16,8 +16,9 @@
package org.springframework.expression.spel;
import org.jspecify.annotations.Nullable;
import org.springframework.expression.ParseException;
import org.springframework.lang.Nullable;
/**
* Root exception for Spring EL related exceptions. Rather than holding a hard coded

View File

@@ -18,8 +18,9 @@ package org.springframework.expression.spel;
import java.util.Locale;
import org.jspecify.annotations.Nullable;
import org.springframework.core.SpringProperties;
import org.springframework.lang.Nullable;
/**
* Configuration object for the SpEL expression parser.
@@ -54,8 +55,7 @@ public class SpelParserConfiguration {
private final SpelCompilerMode compilerMode;
@Nullable
private final ClassLoader compilerClassLoader;
private final @Nullable ClassLoader compilerClassLoader;
private final boolean autoGrowNullReferences;
@@ -150,8 +150,7 @@ public class SpelParserConfiguration {
/**
* Return the ClassLoader to use as the basis for expression compilation.
*/
@Nullable
public ClassLoader getCompilerClassLoader() {
public @Nullable ClassLoader getCompilerClassLoader() {
return this.compilerClassLoader;
}

View File

@@ -20,8 +20,9 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.jspecify.annotations.Nullable;
import org.springframework.expression.TargetedAccessor;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
/**

View File

@@ -24,6 +24,8 @@ import java.util.ArrayList;
import java.util.List;
import java.util.StringJoiner;
import org.jspecify.annotations.Nullable;
import org.springframework.asm.MethodVisitor;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.AccessException;
@@ -39,7 +41,6 @@ import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.expression.spel.support.ReflectiveConstructorExecutor;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -73,12 +74,10 @@ public class ConstructorReference extends SpelNodeImpl {
private final boolean isArrayConstructor;
@Nullable
private final SpelNodeImpl[] dimensions;
private final SpelNodeImpl @Nullable [] dimensions;
/** The cached executor that may be reused on subsequent evaluations. */
@Nullable
private volatile ConstructorExecutor cachedExecutor;
private volatile @Nullable ConstructorExecutor cachedExecutor;
/**

View File

@@ -19,8 +19,9 @@ package org.springframework.expression.spel.ast;
import java.util.List;
import java.util.StringJoiner;
import org.jspecify.annotations.Nullable;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.lang.Nullable;
/**
* Utility methods (formatters, etc) used during parsing and evaluation.

View File

@@ -23,6 +23,8 @@ import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.StringJoiner;
import org.jspecify.annotations.Nullable;
import org.springframework.asm.MethodVisitor;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.TypeDescriptor;
@@ -34,7 +36,6 @@ import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.expression.spel.support.ReflectionHelper;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
@@ -62,8 +63,7 @@ public class FunctionReference extends SpelNodeImpl {
// Captures the most recently used method for the function invocation *if* the method
// can safely be used for compilation (i.e. no argument conversion is going on)
@Nullable
private volatile Method method;
private volatile @Nullable Method method;
public FunctionReference(String functionName, int startPos, int endPos, SpelNodeImpl... arguments) {
@@ -174,6 +174,7 @@ public class FunctionReference extends SpelNodeImpl {
* @throws EvaluationException if there is any problem invoking the method
* @since 6.1
*/
@SuppressWarnings("NullAway") // TODO Remove when NullAway 0.12.2 is released, see https://github.com/uber/NullAway/pull/1089
private TypedValue executeFunctionViaMethodHandle(ExpressionState state, MethodHandle methodHandle) throws EvaluationException {
Object[] functionArgs = getArguments(state);
MethodType declaredParams = methodHandle.type();

View File

@@ -22,6 +22,8 @@ import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import org.jspecify.annotations.Nullable;
import org.springframework.asm.Label;
import org.springframework.asm.MethodVisitor;
import org.springframework.core.convert.TypeDescriptor;
@@ -39,7 +41,6 @@ import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.expression.spel.support.ReflectivePropertyAccessor;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
@@ -101,26 +102,19 @@ public class Indexer extends SpelNodeImpl {
private final boolean nullSafe;
@Nullable
private IndexedType indexedType;
private @Nullable IndexedType indexedType;
@Nullable
private volatile String originalPrimitiveExitTypeDescriptor;
private volatile @Nullable String originalPrimitiveExitTypeDescriptor;
@Nullable
private volatile String arrayTypeDescriptor;
private volatile @Nullable String arrayTypeDescriptor;
@Nullable
private volatile CachedPropertyState cachedPropertyReadState;
private volatile @Nullable CachedPropertyState cachedPropertyReadState;
@Nullable
private volatile CachedPropertyState cachedPropertyWriteState;
private volatile @Nullable CachedPropertyState cachedPropertyWriteState;
@Nullable
private volatile CachedIndexState cachedIndexReadState;
private volatile @Nullable CachedIndexState cachedIndexReadState;
@Nullable
private volatile CachedIndexState cachedIndexWriteState;
private volatile @Nullable CachedIndexState cachedIndexWriteState;
/**
@@ -669,8 +663,7 @@ public class Indexer extends SpelNodeImpl {
private final Map map;
@Nullable
private final Object key;
private final @Nullable Object key;
private final TypeDescriptor mapEntryDescriptor;
@@ -905,8 +898,7 @@ public class Indexer extends SpelNodeImpl {
return (this.collection instanceof List);
}
@Nullable
private static Constructor<?> getDefaultConstructor(Class<?> type) {
private static @Nullable Constructor<?> getDefaultConstructor(Class<?> type) {
try {
return ReflectionUtils.accessibleConstructor(type);
}

View File

@@ -21,6 +21,8 @@ import java.util.Collections;
import java.util.List;
import java.util.StringJoiner;
import org.jspecify.annotations.Nullable;
import org.springframework.asm.MethodVisitor;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypedValue;
@@ -28,7 +30,6 @@ import org.springframework.expression.spel.CodeFlow;
import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelNode;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -42,8 +43,7 @@ import org.springframework.util.Assert;
*/
public class InlineList extends SpelNodeImpl {
@Nullable
private final TypedValue constant;
private final @Nullable TypedValue constant;
public InlineList(int startPos, int endPos, SpelNodeImpl... args) {
@@ -58,8 +58,7 @@ public class InlineList extends SpelNodeImpl {
* <p>This will speed up later getValue calls and reduce the amount of garbage
* created.
*/
@Nullable
private TypedValue computeConstantValue() {
private @Nullable TypedValue computeConstantValue() {
for (int c = 0, max = getChildCount(); c < max; c++) {
SpelNode child = getChild(c);
if (!(child instanceof Literal)) {
@@ -125,8 +124,7 @@ public class InlineList extends SpelNodeImpl {
}
@SuppressWarnings("unchecked")
@Nullable
public List<Object> getConstantValue() {
public @Nullable List<Object> getConstantValue() {
Assert.state(this.constant != null, "No constant");
return (List<Object>) this.constant.getValue();
}

View File

@@ -20,12 +20,13 @@ import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import org.jspecify.annotations.Nullable;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelNode;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -39,8 +40,7 @@ import org.springframework.util.Assert;
*/
public class InlineMap extends SpelNodeImpl {
@Nullable
private final TypedValue constant;
private final @Nullable TypedValue constant;
public InlineMap(int startPos, int endPos, SpelNodeImpl... args) {
@@ -55,8 +55,7 @@ public class InlineMap extends SpelNodeImpl {
* <p>This will speed up later getValue calls and reduce the amount of garbage
* created.
*/
@Nullable
private TypedValue computeConstantValue() {
private @Nullable TypedValue computeConstantValue() {
for (int c = 0, max = getChildCount(); c < max; c++) {
SpelNode child = getChild(c);
if (!(child instanceof Literal)) {
@@ -163,8 +162,7 @@ public class InlineMap extends SpelNodeImpl {
}
@SuppressWarnings("unchecked")
@Nullable
public Map<Object, Object> getConstantValue() {
public @Nullable Map<Object, Object> getConstantValue() {
Assert.state(this.constant != null, "No constant");
return (Map<Object, Object>) this.constant.getValue();
}

View File

@@ -16,13 +16,14 @@
package org.springframework.expression.spel.ast;
import org.jspecify.annotations.Nullable;
import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.InternalParseException;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.expression.spel.SpelParseException;
import org.springframework.lang.Nullable;
/**
* Common superclass for nodes representing literals (boolean, string, number, etc).
@@ -33,8 +34,7 @@ import org.springframework.lang.Nullable;
*/
public abstract class Literal extends SpelNodeImpl {
@Nullable
private final String originalValue;
private final @Nullable String originalValue;
public Literal(@Nullable String originalValue, int startPos, int endPos) {
@@ -43,8 +43,7 @@ public abstract class Literal extends SpelNodeImpl {
}
@Nullable
public final String getOriginalValue() {
public final @Nullable String getOriginalValue() {
return this.originalValue;
}

View File

@@ -25,6 +25,8 @@ import java.util.Collections;
import java.util.List;
import java.util.StringJoiner;
import org.jspecify.annotations.Nullable;
import org.springframework.asm.Label;
import org.springframework.asm.MethodVisitor;
import org.springframework.core.convert.TypeDescriptor;
@@ -41,7 +43,6 @@ import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.expression.spel.support.ReflectiveMethodExecutor;
import org.springframework.expression.spel.support.ReflectiveMethodResolver;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
@@ -59,11 +60,9 @@ public class MethodReference extends SpelNodeImpl {
private final String name;
@Nullable
private Character originalPrimitiveExitTypeDescriptor;
private @Nullable Character originalPrimitiveExitTypeDescriptor;
@Nullable
private volatile CachedMethodExecutor cachedExecutor;
private volatile @Nullable CachedMethodExecutor cachedExecutor;
public MethodReference(boolean nullSafe, String methodName, int startPos, int endPos, SpelNodeImpl... arguments) {
@@ -191,8 +190,7 @@ public class MethodReference extends SpelNodeImpl {
return Collections.unmodifiableList(descriptors);
}
@Nullable
private MethodExecutor getCachedExecutor(EvaluationContext evaluationContext, Object value,
private @Nullable MethodExecutor getCachedExecutor(EvaluationContext evaluationContext, Object value,
@Nullable TypeDescriptor target, List<TypeDescriptor> argumentTypes) {
List<MethodResolver> methodResolvers = evaluationContext.getMethodResolvers();
@@ -378,11 +376,9 @@ public class MethodReference extends SpelNodeImpl {
private final EvaluationContext evaluationContext;
@Nullable
private final Object value;
private final @Nullable Object value;
@Nullable
private final TypeDescriptor targetType;
private final @Nullable TypeDescriptor targetType;
private final Object[] arguments;
@@ -417,11 +413,9 @@ public class MethodReference extends SpelNodeImpl {
private final MethodExecutor methodExecutor;
@Nullable
private final Class<?> staticClass;
private final @Nullable Class<?> staticClass;
@Nullable
private final TypeDescriptor target;
private final @Nullable TypeDescriptor target;
private final List<TypeDescriptor> argumentTypes;

View File

@@ -16,6 +16,8 @@
package org.springframework.expression.spel.ast;
import org.jspecify.annotations.Nullable;
import org.springframework.asm.Label;
import org.springframework.asm.MethodVisitor;
import org.springframework.expression.EvaluationException;
@@ -26,7 +28,6 @@ import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.expression.spel.support.BooleanTypedValue;
import org.springframework.lang.Contract;
import org.springframework.lang.Nullable;
/**
* Represents the boolean AND operation.

View File

@@ -16,6 +16,8 @@
package org.springframework.expression.spel.ast;
import org.jspecify.annotations.Nullable;
import org.springframework.asm.Label;
import org.springframework.asm.MethodVisitor;
import org.springframework.expression.EvaluationException;
@@ -25,7 +27,6 @@ import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.expression.spel.support.BooleanTypedValue;
import org.springframework.lang.Contract;
import org.springframework.lang.Nullable;
/**
* Represents the boolean OR operation.

View File

@@ -19,6 +19,8 @@ package org.springframework.expression.spel.ast;
import java.math.BigDecimal;
import java.math.BigInteger;
import org.jspecify.annotations.Nullable;
import org.springframework.asm.MethodVisitor;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.EvaluationException;
@@ -29,7 +31,6 @@ import org.springframework.expression.spel.CodeFlow;
import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.NumberUtils;

View File

@@ -19,11 +19,12 @@ package org.springframework.expression.spel.ast;
import java.math.BigDecimal;
import java.math.BigInteger;
import org.jspecify.annotations.Nullable;
import org.springframework.asm.Label;
import org.springframework.asm.MethodVisitor;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.spel.CodeFlow;
import org.springframework.lang.Nullable;
import org.springframework.util.NumberUtils;
import org.springframework.util.ObjectUtils;
@@ -47,11 +48,9 @@ public abstract class Operator extends SpelNodeImpl {
// whose accessors seem to only be returning 'Object' - the actual descriptors may
// indicate 'int')
@Nullable
protected String leftActualDescriptor;
protected @Nullable String leftActualDescriptor;
@Nullable
protected String rightActualDescriptor;
protected @Nullable String rightActualDescriptor;
public Operator(String payload, int startPos, int endPos, SpelNodeImpl... operands) {

View File

@@ -16,6 +16,8 @@
package org.springframework.expression.spel.ast;
import org.jspecify.annotations.Nullable;
import org.springframework.asm.MethodVisitor;
import org.springframework.asm.Type;
import org.springframework.expression.EvaluationException;
@@ -25,7 +27,6 @@ import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.expression.spel.support.BooleanTypedValue;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -37,8 +38,7 @@ import org.springframework.util.Assert;
*/
public class OperatorInstanceof extends Operator {
@Nullable
private Class<?> type;
private @Nullable Class<?> type;
public OperatorInstanceof(int startPos, int endPos, SpelNodeImpl... operands) {

View File

@@ -22,12 +22,13 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.jspecify.annotations.Nullable;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;

View File

@@ -23,6 +23,8 @@ import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import org.jspecify.annotations.Nullable;
import org.springframework.asm.Label;
import org.springframework.asm.MethodVisitor;
import org.springframework.core.convert.TypeDescriptor;
@@ -37,7 +39,6 @@ import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.expression.spel.support.ReflectivePropertyAccessor;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
@@ -56,14 +57,11 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
private final String name;
@Nullable
private String originalPrimitiveExitTypeDescriptor;
private @Nullable String originalPrimitiveExitTypeDescriptor;
@Nullable
private volatile PropertyAccessor cachedReadAccessor;
private volatile @Nullable PropertyAccessor cachedReadAccessor;
@Nullable
private volatile PropertyAccessor cachedWriteAccessor;
private volatile @Nullable PropertyAccessor cachedWriteAccessor;
public PropertyOrFieldReference(boolean nullSafe, String propertyOrFieldName, int startPos, int endPos) {

View File

@@ -16,10 +16,11 @@
package org.springframework.expression.spel.ast;
import org.jspecify.annotations.Nullable;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState;
import org.springframework.lang.Nullable;
/**
* Represents a dot separated sequence of strings that indicate a package qualified type
@@ -32,8 +33,7 @@ import org.springframework.lang.Nullable;
*/
public class QualifiedIdentifier extends SpelNodeImpl {
@Nullable
private TypedValue value;
private @Nullable TypedValue value;
public QualifiedIdentifier(int startPos, int endPos, SpelNodeImpl... operands) {

View File

@@ -20,6 +20,8 @@ import java.lang.reflect.Executable;
import java.lang.reflect.Member;
import java.util.function.Supplier;
import org.jspecify.annotations.Nullable;
import org.springframework.asm.MethodVisitor;
import org.springframework.asm.Opcodes;
import org.springframework.asm.Type;
@@ -31,7 +33,6 @@ import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.expression.spel.SpelNode;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
@@ -57,8 +58,7 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes {
protected SpelNodeImpl[] children = SpelNodeImpl.NO_CHILDREN;
@Nullable
private SpelNodeImpl parent;
private @Nullable SpelNodeImpl parent;
/**
* Indicates the type descriptor for the result of this expression node.
@@ -69,11 +69,10 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes {
* It does not include the trailing semicolon (for non array reference types).
* Some examples: Ljava/lang/String, I, [I
*/
@Nullable
protected volatile String exitTypeDescriptor;
protected volatile @Nullable String exitTypeDescriptor;
public SpelNodeImpl(int startPos, int endPos, @Nullable SpelNodeImpl... operands) {
public SpelNodeImpl(int startPos, int endPos, SpelNodeImpl @Nullable ... operands) {
this.startPos = startPos;
this.endPos = endPos;
if (!ObjectUtils.isEmpty(operands)) {
@@ -111,8 +110,7 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes {
}
@Override
@Nullable
public final Object getValue(ExpressionState expressionState) throws EvaluationException {
public final @Nullable Object getValue(ExpressionState expressionState) throws EvaluationException {
return getValueInternal(expressionState).getValue();
}
@@ -165,8 +163,7 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes {
}
@Override
@Nullable
public Class<?> getObjectClass(@Nullable Object obj) {
public @Nullable Class<?> getObjectClass(@Nullable Object obj) {
if (obj == null) {
return null;
}
@@ -193,13 +190,11 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes {
return false;
}
@Nullable
public String getExitDescriptor() {
public @Nullable String getExitDescriptor() {
return this.exitTypeDescriptor;
}
@Nullable
protected final <T> T getValue(ExpressionState state, Class<T> desiredReturnType) throws EvaluationException {
protected final <T> @Nullable T getValue(ExpressionState state, Class<T> desiredReturnType) throws EvaluationException {
return ExpressionUtils.convertTypedValue(state.getEvaluationContext(), getValueInternal(state), desiredReturnType);
}
@@ -302,8 +297,7 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes {
}
}
@Nullable
private static Class<?> loadClassForExitDescriptor(@Nullable String exitDescriptor, ClassLoader classLoader) {
private static @Nullable Class<?> loadClassForExitDescriptor(@Nullable String exitDescriptor, ClassLoader classLoader) {
if (!StringUtils.hasText(exitDescriptor)) {
return null;
}

View File

@@ -19,13 +19,14 @@ package org.springframework.expression.spel.ast;
import java.lang.reflect.Array;
import java.util.Locale;
import org.jspecify.annotations.Nullable;
import org.springframework.asm.MethodVisitor;
import org.springframework.asm.Type;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.CodeFlow;
import org.springframework.expression.spel.ExpressionState;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -39,8 +40,7 @@ public class TypeReference extends SpelNodeImpl {
private final int dimensions;
@Nullable
private transient Class<?> type;
private transient @Nullable Class<?> type;
public TypeReference(int startPos, int endPos, SpelNodeImpl qualifiedId) {

View File

@@ -16,10 +16,11 @@
package org.springframework.expression.spel.ast;
import org.jspecify.annotations.Nullable;
import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.lang.Nullable;
/**
* Represents a reference to a value. With a reference it is possible to get or set the

View File

@@ -19,6 +19,8 @@ package org.springframework.expression.spel.ast;
import java.lang.reflect.Modifier;
import java.util.function.Supplier;
import org.jspecify.annotations.Nullable;
import org.springframework.asm.MethodVisitor;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException;
@@ -26,7 +28,6 @@ import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.CodeFlow;
import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.lang.Nullable;
/**
* Represents a variable reference &mdash; for example, {@code #root}, {@code #this},

View File

@@ -1,9 +1,7 @@
/**
* SpEL's abstract syntax tree.
*/
@NonNullApi
@NonNullFields
@NullMarked
package org.springframework.expression.spel.ast;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
import org.jspecify.annotations.NullMarked;

View File

@@ -1,9 +1,7 @@
/**
* SpEL's central implementation package.
*/
@NonNullApi
@NonNullFields
@NullMarked
package org.springframework.expression.spel;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
import org.jspecify.annotations.NullMarked;

View File

@@ -26,6 +26,8 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Pattern;
import org.jspecify.annotations.Nullable;
import org.springframework.expression.ParseException;
import org.springframework.expression.ParserContext;
import org.springframework.expression.common.TemplateAwareExpressionParser;
@@ -78,7 +80,6 @@ import org.springframework.expression.spel.ast.Ternary;
import org.springframework.expression.spel.ast.TypeReference;
import org.springframework.expression.spel.ast.VariableReference;
import org.springframework.lang.Contract;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
/**
@@ -165,9 +166,8 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
// | (DEFAULT^ logicalOrExpression)
// | (QMARK^ expression COLON! expression)
// | (ELVIS^ expression))?;
@Nullable
@SuppressWarnings("NullAway")
private SpelNodeImpl eatExpression() {
private @Nullable SpelNodeImpl eatExpression() {
SpelNodeImpl expr = eatLogicalOrExpression();
Token t = peekToken();
if (t != null) {
@@ -205,8 +205,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
}
//logicalOrExpression : logicalAndExpression (OR^ logicalAndExpression)*;
@Nullable
private SpelNodeImpl eatLogicalOrExpression() {
private @Nullable SpelNodeImpl eatLogicalOrExpression() {
SpelNodeImpl expr = eatLogicalAndExpression();
while (peekIdentifierToken("or") || peekToken(TokenKind.SYMBOLIC_OR)) {
Token t = takeToken(); //consume OR
@@ -218,8 +217,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
}
// logicalAndExpression : relationalExpression (AND^ relationalExpression)*;
@Nullable
private SpelNodeImpl eatLogicalAndExpression() {
private @Nullable SpelNodeImpl eatLogicalAndExpression() {
SpelNodeImpl expr = eatRelationalExpression();
while (peekIdentifierToken("and") || peekToken(TokenKind.SYMBOLIC_AND)) {
Token t = takeToken(); // consume 'AND'
@@ -231,8 +229,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
}
// relationalExpression : sumExpression (relationalOperator^ sumExpression)?;
@Nullable
private SpelNodeImpl eatRelationalExpression() {
private @Nullable SpelNodeImpl eatRelationalExpression() {
SpelNodeImpl expr = eatSumExpression();
Token relationalOperatorToken = maybeEatRelationalOperator();
if (relationalOperatorToken != null) {
@@ -276,9 +273,8 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
}
//sumExpression: productExpression ( (PLUS^ | MINUS^) productExpression)*;
@Nullable
@SuppressWarnings("NullAway")
private SpelNodeImpl eatSumExpression() {
private @Nullable SpelNodeImpl eatSumExpression() {
SpelNodeImpl expr = eatProductExpression();
while (peekToken(TokenKind.PLUS, TokenKind.MINUS, TokenKind.INC)) {
Token t = takeToken(); //consume PLUS or MINUS or INC
@@ -295,8 +291,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
}
// productExpression: powerExpr ((STAR^ | DIV^| MOD^) powerExpr)* ;
@Nullable
private SpelNodeImpl eatProductExpression() {
private @Nullable SpelNodeImpl eatProductExpression() {
SpelNodeImpl expr = eatPowerIncDecExpression();
while (peekToken(TokenKind.STAR, TokenKind.DIV, TokenKind.MOD)) {
Token t = takeToken(); // consume STAR/DIV/MOD
@@ -316,9 +311,8 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
}
// powerExpr : unaryExpression (POWER^ unaryExpression)? (INC || DEC) ;
@Nullable
@SuppressWarnings("NullAway")
private SpelNodeImpl eatPowerIncDecExpression() {
private @Nullable SpelNodeImpl eatPowerIncDecExpression() {
SpelNodeImpl expr = eatUnaryExpression();
if (peekToken(TokenKind.POWER)) {
Token t = takeToken(); //consume POWER
@@ -337,9 +331,8 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
}
// unaryExpression: (PLUS^ | MINUS^ | BANG^ | INC^ | DEC^) unaryExpression | primaryExpression ;
@Nullable
@SuppressWarnings("NullAway")
private SpelNodeImpl eatUnaryExpression() {
private @Nullable SpelNodeImpl eatUnaryExpression() {
if (peekToken(TokenKind.NOT, TokenKind.PLUS, TokenKind.MINUS)) {
Token t = takeToken();
SpelNodeImpl expr = eatUnaryExpression();
@@ -370,8 +363,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
}
// primaryExpression : startNode (node)? -> ^(EXPRESSION startNode (node)?);
@Nullable
private SpelNodeImpl eatPrimaryExpression() {
private @Nullable SpelNodeImpl eatPrimaryExpression() {
SpelNodeImpl start = eatStartNode(); // always a start node
List<SpelNodeImpl> nodes = null;
SpelNodeImpl node = eatNode();
@@ -391,14 +383,12 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
}
// node : ((DOT dottedNode) | (SAFE_NAVI dottedNode) | nonDottedNode)+;
@Nullable
private SpelNodeImpl eatNode() {
private @Nullable SpelNodeImpl eatNode() {
return (peekToken(TokenKind.DOT, TokenKind.SAFE_NAVI) ? eatDottedNode() : eatNonDottedNode());
}
// nonDottedNode: indexer;
@Nullable
private SpelNodeImpl eatNonDottedNode() {
private @Nullable SpelNodeImpl eatNonDottedNode() {
if (peekToken(TokenKind.LSQUARE)) {
if (maybeEatIndexer(false)) {
return pop();
@@ -457,8 +447,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
}
// methodArgs : LPAREN! (argument (COMMA! argument)* (COMMA!)?)? RPAREN!;
@Nullable
private SpelNodeImpl[] maybeEatMethodArgs() {
private SpelNodeImpl @Nullable [] maybeEatMethodArgs() {
if (!peekToken(TokenKind.LPAREN)) {
return null;
}
@@ -524,8 +513,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
// | lastSelection
// | indexer
// | constructor
@Nullable
private SpelNodeImpl eatStartNode() {
private @Nullable SpelNodeImpl eatStartNode() {
if (maybeEatLiteral()) {
return pop();
}
@@ -917,8 +905,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
// relationalOperator
// : EQUAL | NOT_EQUAL | LESS_THAN | LESS_THAN_OR_EQUAL | GREATER_THAN
// | GREATER_THAN_OR_EQUAL | INSTANCEOF | BETWEEN | MATCHES
@Nullable
private Token maybeEatRelationalOperator() {
private @Nullable Token maybeEatRelationalOperator() {
Token t = peekToken();
if (t == null) {
return null;
@@ -1022,16 +1009,14 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
return this.tokenStream.get(this.tokenStreamPointer++);
}
@Nullable
private Token nextToken() {
private @Nullable Token nextToken() {
if (this.tokenStreamPointer >= this.tokenStreamLength) {
return null;
}
return this.tokenStream.get(this.tokenStreamPointer++);
}
@Nullable
private Token peekToken() {
private @Nullable Token peekToken() {
if (this.tokenStreamPointer >= this.tokenStreamLength) {
return null;
}

View File

@@ -23,6 +23,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.asm.ClassWriter;
import org.springframework.asm.MethodVisitor;
@@ -32,7 +33,6 @@ import org.springframework.expression.spel.CodeFlow;
import org.springframework.expression.spel.CompiledExpression;
import org.springframework.expression.spel.SpelParserConfiguration;
import org.springframework.expression.spel.ast.SpelNodeImpl;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
import org.springframework.util.ConcurrentReferenceHashMap;
import org.springframework.util.ReflectionUtils;
@@ -98,8 +98,7 @@ public final class SpelCompiler implements Opcodes {
* @return an instance of the class implementing the compiled expression,
* or {@code null} if compilation is not possible
*/
@Nullable
public CompiledExpression compile(SpelNodeImpl expression) {
public @Nullable CompiledExpression compile(SpelNodeImpl expression) {
if (expression.isCompilable()) {
if (logger.isDebugEnabled()) {
logger.debug("SpEL: compiling " + expression.toStringAST());
@@ -133,8 +132,7 @@ public final class SpelCompiler implements Opcodes {
* @return the expression call, or {@code null} if the decision was to opt out of
* compilation during code generation
*/
@Nullable
private Class<? extends CompiledExpression> createExpressionClass(SpelNodeImpl expressionToCompile) {
private @Nullable Class<? extends CompiledExpression> createExpressionClass(SpelNodeImpl expressionToCompile) {
// Create class outline:
// org.springframework.expression.spel.generated.CompiledExpression##### extends org.springframework.expression.spel.CompiledExpression
String className = "org/springframework/expression/spel/generated/CompiledExpression" + getNextSuffix();

View File

@@ -18,6 +18,8 @@ package org.springframework.expression.spel.standard;
import java.util.concurrent.atomic.AtomicInteger;
import org.jspecify.annotations.Nullable;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException;
@@ -33,7 +35,6 @@ import org.springframework.expression.spel.SpelNode;
import org.springframework.expression.spel.SpelParserConfiguration;
import org.springframework.expression.spel.ast.SpelNodeImpl;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -63,12 +64,10 @@ public class SpelExpression implements Expression {
private final SpelParserConfiguration configuration;
// The default context is used if no override is supplied by the user
@Nullable
private EvaluationContext evaluationContext;
private @Nullable EvaluationContext evaluationContext;
// Holds the compiled form of the expression (if it has been compiled)
@Nullable
private volatile CompiledExpression compiledAst;
private volatile @Nullable CompiledExpression compiledAst;
// Count of many times as the expression been interpreted - can trigger compilation
// when certain limit reached
@@ -117,8 +116,7 @@ public class SpelExpression implements Expression {
}
@Override
@Nullable
public Object getValue() throws EvaluationException {
public @Nullable Object getValue() throws EvaluationException {
CompiledExpression compiledAst = this.compiledAst;
if (compiledAst != null) {
try {
@@ -146,8 +144,7 @@ public class SpelExpression implements Expression {
@SuppressWarnings("unchecked")
@Override
@Nullable
public <T> T getValue(@Nullable Class<T> expectedResultType) throws EvaluationException {
public <T> @Nullable T getValue(@Nullable Class<T> expectedResultType) throws EvaluationException {
CompiledExpression compiledAst = this.compiledAst;
if (compiledAst != null) {
try {
@@ -182,8 +179,7 @@ public class SpelExpression implements Expression {
}
@Override
@Nullable
public Object getValue(@Nullable Object rootObject) throws EvaluationException {
public @Nullable Object getValue(@Nullable Object rootObject) throws EvaluationException {
CompiledExpression compiledAst = this.compiledAst;
if (compiledAst != null) {
try {
@@ -211,8 +207,7 @@ public class SpelExpression implements Expression {
@SuppressWarnings("unchecked")
@Override
@Nullable
public <T> T getValue(@Nullable Object rootObject, @Nullable Class<T> expectedResultType) throws EvaluationException {
public <T> @Nullable T getValue(@Nullable Object rootObject, @Nullable Class<T> expectedResultType) throws EvaluationException {
CompiledExpression compiledAst = this.compiledAst;
if (compiledAst != null) {
try {
@@ -247,8 +242,7 @@ public class SpelExpression implements Expression {
}
@Override
@Nullable
public Object getValue(EvaluationContext context) throws EvaluationException {
public @Nullable Object getValue(EvaluationContext context) throws EvaluationException {
Assert.notNull(context, "EvaluationContext must not be null");
CompiledExpression compiledAst = this.compiledAst;
@@ -277,8 +271,7 @@ public class SpelExpression implements Expression {
@SuppressWarnings("unchecked")
@Override
@Nullable
public <T> T getValue(EvaluationContext context, @Nullable Class<T> expectedResultType) throws EvaluationException {
public <T> @Nullable T getValue(EvaluationContext context, @Nullable Class<T> expectedResultType) throws EvaluationException {
Assert.notNull(context, "EvaluationContext must not be null");
CompiledExpression compiledAst = this.compiledAst;
@@ -312,8 +305,7 @@ public class SpelExpression implements Expression {
}
@Override
@Nullable
public Object getValue(EvaluationContext context, @Nullable Object rootObject) throws EvaluationException {
public @Nullable Object getValue(EvaluationContext context, @Nullable Object rootObject) throws EvaluationException {
Assert.notNull(context, "EvaluationContext must not be null");
CompiledExpression compiledAst = this.compiledAst;
@@ -342,8 +334,7 @@ public class SpelExpression implements Expression {
@SuppressWarnings("unchecked")
@Override
@Nullable
public <T> T getValue(EvaluationContext context, @Nullable Object rootObject, @Nullable Class<T> expectedResultType)
public <T> @Nullable T getValue(EvaluationContext context, @Nullable Object rootObject, @Nullable Class<T> expectedResultType)
throws EvaluationException {
Assert.notNull(context, "EvaluationContext must not be null");
@@ -379,20 +370,17 @@ public class SpelExpression implements Expression {
}
@Override
@Nullable
public Class<?> getValueType() throws EvaluationException {
public @Nullable Class<?> getValueType() throws EvaluationException {
return getValueType(getEvaluationContext());
}
@Override
@Nullable
public Class<?> getValueType(@Nullable Object rootObject) throws EvaluationException {
public @Nullable Class<?> getValueType(@Nullable Object rootObject) throws EvaluationException {
return getValueType(getEvaluationContext(), rootObject);
}
@Override
@Nullable
public Class<?> getValueType(EvaluationContext context) throws EvaluationException {
public @Nullable Class<?> getValueType(EvaluationContext context) throws EvaluationException {
Assert.notNull(context, "EvaluationContext must not be null");
ExpressionState expressionState = new ExpressionState(context, this.configuration);
TypeDescriptor typeDescriptor = this.ast.getValueInternal(expressionState).getTypeDescriptor();
@@ -400,38 +388,33 @@ public class SpelExpression implements Expression {
}
@Override
@Nullable
public Class<?> getValueType(EvaluationContext context, @Nullable Object rootObject) throws EvaluationException {
public @Nullable Class<?> getValueType(EvaluationContext context, @Nullable Object rootObject) throws EvaluationException {
ExpressionState expressionState = new ExpressionState(context, toTypedValue(rootObject), this.configuration);
TypeDescriptor typeDescriptor = this.ast.getValueInternal(expressionState).getTypeDescriptor();
return (typeDescriptor != null ? typeDescriptor.getType() : null);
}
@Override
@Nullable
public TypeDescriptor getValueTypeDescriptor() throws EvaluationException {
public @Nullable TypeDescriptor getValueTypeDescriptor() throws EvaluationException {
return getValueTypeDescriptor(getEvaluationContext());
}
@Override
@Nullable
public TypeDescriptor getValueTypeDescriptor(@Nullable Object rootObject) throws EvaluationException {
public @Nullable TypeDescriptor getValueTypeDescriptor(@Nullable Object rootObject) throws EvaluationException {
ExpressionState expressionState =
new ExpressionState(getEvaluationContext(), toTypedValue(rootObject), this.configuration);
return this.ast.getValueInternal(expressionState).getTypeDescriptor();
}
@Override
@Nullable
public TypeDescriptor getValueTypeDescriptor(EvaluationContext context) throws EvaluationException {
public @Nullable TypeDescriptor getValueTypeDescriptor(EvaluationContext context) throws EvaluationException {
Assert.notNull(context, "EvaluationContext must not be null");
ExpressionState expressionState = new ExpressionState(context, this.configuration);
return this.ast.getValueInternal(expressionState).getTypeDescriptor();
}
@Override
@Nullable
public TypeDescriptor getValueTypeDescriptor(EvaluationContext context, @Nullable Object rootObject)
public @Nullable TypeDescriptor getValueTypeDescriptor(EvaluationContext context, @Nullable Object rootObject)
throws EvaluationException {
Assert.notNull(context, "EvaluationContext must not be null");

View File

@@ -16,11 +16,12 @@
package org.springframework.expression.spel.standard;
import org.jspecify.annotations.Nullable;
import org.springframework.expression.ParseException;
import org.springframework.expression.ParserContext;
import org.springframework.expression.common.TemplateAwareExpressionParser;
import org.springframework.expression.spel.SpelParserConfiguration;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**

View File

@@ -16,7 +16,7 @@
package org.springframework.expression.spel.standard;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* Holder for a kind of token, the associated data, and its position in the input
@@ -29,8 +29,7 @@ class Token {
final TokenKind kind;
@Nullable
final String data;
final @Nullable String data;
final int startPos;
@@ -55,7 +54,7 @@ class Token {
* @param startPos the exact start position
* @param endPos the index of the last character
*/
Token(TokenKind tokenKind, @Nullable char[] tokenData, int startPos, int endPos) {
Token(TokenKind tokenKind, char @Nullable [] tokenData, int startPos, int endPos) {
this.kind = tokenKind;
this.data = (tokenData != null ? new String(tokenData) : null);
this.startPos = startPos;

View File

@@ -1,9 +1,7 @@
/**
* SpEL's standard parser implementation.
*/
@NonNullApi
@NonNullFields
@NullMarked
package org.springframework.expression.spel.standard;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
import org.jspecify.annotations.NullMarked;

View File

@@ -20,11 +20,12 @@ import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.List;
import org.jspecify.annotations.Nullable;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.AccessException;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.MethodExecutor;
import org.springframework.lang.Nullable;
/**
* An {@link org.springframework.expression.MethodResolver} variant for data binding
@@ -46,8 +47,7 @@ public final class DataBindingMethodResolver extends ReflectiveMethodResolver {
}
@Override
@Nullable
public MethodExecutor resolve(EvaluationContext context, Object targetObject, String name,
public @Nullable MethodExecutor resolve(EvaluationContext context, Object targetObject, String name,
List<TypeDescriptor> argumentTypes) throws AccessException {
if (targetObject instanceof Class) {

View File

@@ -24,13 +24,14 @@ import java.lang.reflect.Method;
import java.util.List;
import java.util.Optional;
import org.jspecify.annotations.Nullable;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypeConverter;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
@@ -57,8 +58,7 @@ public abstract class ReflectionHelper {
* @return an {@code ArgumentsMatchInfo} object indicating what kind of match it was,
* or {@code null} if it was not a match
*/
@Nullable
static ArgumentsMatchKind compareArguments(
static @Nullable ArgumentsMatchKind compareArguments(
List<TypeDescriptor> expectedArgTypes, List<TypeDescriptor> suppliedArgTypes, TypeConverter typeConverter) {
Assert.isTrue(expectedArgTypes.size() == suppliedArgTypes.size(),
@@ -146,8 +146,7 @@ public abstract class ReflectionHelper {
* @return an {@code ArgumentsMatchKind} object indicating what kind of match it was,
* or {@code null} if it was not a match
*/
@Nullable
static ArgumentsMatchKind compareArgumentsVarargs(
static @Nullable ArgumentsMatchKind compareArgumentsVarargs(
List<TypeDescriptor> expectedArgTypes, List<TypeDescriptor> suppliedArgTypes, TypeConverter typeConverter) {
Assert.isTrue(!CollectionUtils.isEmpty(expectedArgTypes),

View File

@@ -18,11 +18,12 @@ package org.springframework.expression.spel.support;
import java.lang.reflect.Constructor;
import org.jspecify.annotations.Nullable;
import org.springframework.expression.AccessException;
import org.springframework.expression.ConstructorExecutor;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.TypedValue;
import org.springframework.lang.Nullable;
import org.springframework.util.ReflectionUtils;
/**
@@ -37,8 +38,7 @@ public class ReflectiveConstructorExecutor implements ConstructorExecutor {
private final Constructor<?> ctor;
@Nullable
private final Integer varargsPosition;
private final @Nullable Integer varargsPosition;
public ReflectiveConstructorExecutor(Constructor<?> ctor) {

View File

@@ -22,6 +22,8 @@ import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import org.jspecify.annotations.Nullable;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.AccessException;
@@ -31,7 +33,6 @@ import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypeConverter;
import org.springframework.expression.spel.support.ReflectionHelper.ArgumentsMatchKind;
import org.springframework.lang.Nullable;
/**
* A constructor resolver that uses reflection to locate the constructor that
@@ -56,8 +57,7 @@ public class ReflectiveConstructorResolver implements ConstructorResolver {
* </ol>
*/
@Override
@Nullable
public ConstructorExecutor resolve(EvaluationContext context, String typeName, List<TypeDescriptor> argumentTypes)
public @Nullable ConstructorExecutor resolve(EvaluationContext context, String typeName, List<TypeDescriptor> argumentTypes)
throws AccessException {
try {

View File

@@ -19,6 +19,8 @@ package org.springframework.expression.spel.support;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import org.jspecify.annotations.Nullable;
import org.springframework.asm.MethodVisitor;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.IndexAccessor;
@@ -26,7 +28,6 @@ import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.CodeFlow;
import org.springframework.expression.spel.CompilableIndexAccessor;
import org.springframework.expression.spel.SpelNode;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
@@ -114,8 +115,7 @@ public class ReflectiveIndexAccessor implements CompilableIndexAccessor {
private final Method readMethodToInvoke;
@Nullable
private final Method writeMethodToInvoke;
private final @Nullable Method writeMethodToInvoke;
/**

View File

@@ -19,13 +19,14 @@ package org.springframework.expression.spel.support;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import org.jspecify.annotations.Nullable;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.AccessException;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.MethodExecutor;
import org.springframework.expression.TypedValue;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
@@ -46,11 +47,9 @@ public class ReflectiveMethodExecutor implements MethodExecutor {
*/
private final Method methodToInvoke;
@Nullable
private final Integer varargsPosition;
private final @Nullable Integer varargsPosition;
@Nullable
private final Class<?> publicDeclaringClass;
private final @Nullable Class<?> publicDeclaringClass;
private boolean argumentConversionOccurred = false;
@@ -93,8 +92,7 @@ public class ReflectiveMethodExecutor implements MethodExecutor {
* @return the public class or interface that declares the method, or {@code null} if
* no such public type could be found
*/
@Nullable
public Class<?> getPublicDeclaringClass() {
public @Nullable Class<?> getPublicDeclaringClass() {
return this.publicDeclaringClass;
}

View File

@@ -27,6 +27,8 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jspecify.annotations.Nullable;
import org.springframework.core.BridgeMethodResolver;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.TypeDescriptor;
@@ -40,7 +42,6 @@ import org.springframework.expression.TypeConverter;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.expression.spel.support.ReflectionHelper.ArgumentsMatchKind;
import org.springframework.lang.Nullable;
/**
* Reflection-based {@link MethodResolver} used by default in {@link StandardEvaluationContext}
@@ -59,8 +60,7 @@ public class ReflectiveMethodResolver implements MethodResolver {
// more closely following the Java rules.
private final boolean useDistance;
@Nullable
private Map<Class<?>, MethodFilter> filters;
private @Nullable Map<Class<?>, MethodFilter> filters;
public ReflectiveMethodResolver() {
@@ -113,8 +113,7 @@ public class ReflectiveMethodResolver implements MethodResolver {
* </ol>
*/
@Override
@Nullable
public MethodExecutor resolve(EvaluationContext context, Object targetObject, String name,
public @Nullable MethodExecutor resolve(EvaluationContext context, Object targetObject, String name,
List<TypeDescriptor> argumentTypes) throws AccessException {
try {

View File

@@ -33,6 +33,7 @@ import kotlin.reflect.KMutableProperty;
import kotlin.reflect.KProperty;
import kotlin.reflect.full.KClasses;
import kotlin.reflect.jvm.ReflectJvmMapping;
import org.jspecify.annotations.Nullable;
import org.springframework.asm.MethodVisitor;
import org.springframework.core.KotlinDetector;
@@ -46,7 +47,6 @@ import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.CodeFlow;
import org.springframework.expression.spel.CompilablePropertyAccessor;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
@@ -109,8 +109,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
* Returns {@code null} which means this is a general purpose accessor.
*/
@Override
@Nullable
public Class<?>[] getSpecificTargetClasses() {
public Class<?> @Nullable [] getSpecificTargetClasses() {
return null;
}
@@ -329,8 +328,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
}
@Nullable
private TypeDescriptor getTypeDescriptor(EvaluationContext context, Object target, String name) {
private @Nullable TypeDescriptor getTypeDescriptor(EvaluationContext context, Object target, String name) {
Class<?> type = (target instanceof Class<?> clazz ? clazz : target.getClass());
if (type.isArray() && name.equals("length")) {
@@ -352,8 +350,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
return typeDescriptor;
}
@Nullable
private Method findGetterForProperty(String propertyName, Class<?> clazz, Object target) {
private @Nullable Method findGetterForProperty(String propertyName, Class<?> clazz, Object target) {
boolean targetIsAClass = (target instanceof Class);
Method method = findGetterForProperty(propertyName, clazz, targetIsAClass);
if (method == null && targetIsAClass) {
@@ -363,8 +360,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
return method;
}
@Nullable
private Method findSetterForProperty(String propertyName, Class<?> clazz, Object target) {
private @Nullable Method findSetterForProperty(String propertyName, Class<?> clazz, Object target) {
Method method = findSetterForProperty(propertyName, clazz, target instanceof Class);
// In contrast to findGetterForProperty(), we do not look for setters in
// java.lang.Class as a fallback, since Class doesn't have any public setters.
@@ -374,8 +370,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
/**
* Find a getter method for the specified property.
*/
@Nullable
protected Method findGetterForProperty(String propertyName, Class<?> clazz, boolean mustBeStatic) {
protected @Nullable Method findGetterForProperty(String propertyName, Class<?> clazz, boolean mustBeStatic) {
Method method = findMethodForProperty(getPropertyMethodSuffixes(propertyName),
"get", clazz, mustBeStatic, 0, ANY_TYPES);
if (method == null) {
@@ -393,14 +388,12 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
/**
* Find a setter method for the specified property.
*/
@Nullable
protected Method findSetterForProperty(String propertyName, Class<?> clazz, boolean mustBeStatic) {
protected @Nullable Method findSetterForProperty(String propertyName, Class<?> clazz, boolean mustBeStatic) {
return findMethodForProperty(getPropertyMethodSuffixes(propertyName),
"set", clazz, mustBeStatic, 1, ANY_TYPES);
}
@Nullable
private Method findMethodForProperty(String[] methodSuffixes, String prefix, Class<?> clazz,
private @Nullable Method findMethodForProperty(String[] methodSuffixes, String prefix, Class<?> clazz,
boolean mustBeStatic, int numberOfParams, Set<Class<?>> requiredReturnTypes) {
Method[] methods = getSortedMethods(clazz);
@@ -467,8 +460,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
return StringUtils.capitalize(propertyName);
}
@Nullable
private Field findField(String name, Class<?> clazz, Object target) {
private @Nullable Field findField(String name, Class<?> clazz, Object target) {
Field field = findField(name, clazz, target instanceof Class);
if (field == null && target instanceof Class) {
field = findField(name, target.getClass(), false);
@@ -479,8 +471,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
/**
* Find a field of a certain name on a specified class.
*/
@Nullable
protected Field findField(String name, Class<?> clazz, boolean mustBeStatic) {
protected @Nullable Field findField(String name, Class<?> clazz, boolean mustBeStatic) {
Field[] fields = clazz.getFields();
for (Field field : fields) {
if (field.getName().equals(name) && (!mustBeStatic || Modifier.isStatic(field.getModifiers()))) {
@@ -619,8 +610,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
}
@Override
@Nullable
public Class<?>[] getSpecificTargetClasses() {
public Class<?> @Nullable [] getSpecificTargetClasses() {
throw new UnsupportedOperationException("Should not be called on an OptimalPropertyAccessor");
}

View File

@@ -23,6 +23,8 @@ import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import org.jspecify.annotations.Nullable;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.BeanResolver;
@@ -37,7 +39,6 @@ import org.springframework.expression.TypeLocator;
import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.lang.Nullable;
/**
* A basic implementation of {@link EvaluationContext} that focuses on a subset
@@ -178,8 +179,7 @@ public final class SimpleEvaluationContext implements EvaluationContext {
* @return always {@code null}
*/
@Override
@Nullable
public BeanResolver getBeanResolver() {
public @Nullable BeanResolver getBeanResolver() {
return null;
}
@@ -257,8 +257,7 @@ public final class SimpleEvaluationContext implements EvaluationContext {
* @return the value of the variable or function, or {@code null} if not found
*/
@Override
@Nullable
public Object lookupVariable(String name) {
public @Nullable Object lookupVariable(String name) {
return this.variables.get(name);
}
@@ -344,11 +343,9 @@ public final class SimpleEvaluationContext implements EvaluationContext {
private List<MethodResolver> resolvers = Collections.emptyList();
@Nullable
private TypeConverter typeConverter;
private @Nullable TypeConverter typeConverter;
@Nullable
private TypedValue rootObject;
private @Nullable TypedValue rootObject;
private boolean assignmentEnabled = true;

View File

@@ -23,6 +23,8 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.jspecify.annotations.Nullable;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.BeanResolver;
import org.springframework.expression.ConstructorResolver;
@@ -36,7 +38,6 @@ import org.springframework.expression.TypeComparator;
import org.springframework.expression.TypeConverter;
import org.springframework.expression.TypeLocator;
import org.springframework.expression.TypedValue;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -81,29 +82,21 @@ public class StandardEvaluationContext implements EvaluationContext {
private TypedValue rootObject;
@Nullable
private volatile List<PropertyAccessor> propertyAccessors;
private volatile @Nullable List<PropertyAccessor> propertyAccessors;
@Nullable
private volatile List<IndexAccessor> indexAccessors;
private volatile @Nullable List<IndexAccessor> indexAccessors;
@Nullable
private volatile List<ConstructorResolver> constructorResolvers;
private volatile @Nullable List<ConstructorResolver> constructorResolvers;
@Nullable
private volatile List<MethodResolver> methodResolvers;
private volatile @Nullable List<MethodResolver> methodResolvers;
@Nullable
private volatile ReflectiveMethodResolver reflectiveMethodResolver;
private volatile @Nullable ReflectiveMethodResolver reflectiveMethodResolver;
@Nullable
private BeanResolver beanResolver;
private @Nullable BeanResolver beanResolver;
@Nullable
private TypeLocator typeLocator;
private @Nullable TypeLocator typeLocator;
@Nullable
private TypeConverter typeConverter;
private @Nullable TypeConverter typeConverter;
private TypeComparator typeComparator = StandardTypeComparator.INSTANCE;
@@ -248,8 +241,7 @@ public class StandardEvaluationContext implements EvaluationContext {
}
@Override
@Nullable
public BeanResolver getBeanResolver() {
public @Nullable BeanResolver getBeanResolver() {
return this.beanResolver;
}
@@ -400,8 +392,7 @@ public class StandardEvaluationContext implements EvaluationContext {
* @return the value of the variable or function, or {@code null} if not found
*/
@Override
@Nullable
public Object lookupVariable(String name) {
public @Nullable Object lookupVariable(String name) {
return this.variables.get(name);
}

View File

@@ -16,10 +16,11 @@
package org.springframework.expression.spel.support;
import org.jspecify.annotations.Nullable;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.Operation;
import org.springframework.expression.OperatorOverloader;
import org.springframework.lang.Nullable;
/**
* Standard implementation of {@link OperatorOverloader}.

View File

@@ -19,10 +19,11 @@ package org.springframework.expression.spel.support;
import java.math.BigDecimal;
import java.math.BigInteger;
import org.jspecify.annotations.Nullable;
import org.springframework.expression.TypeComparator;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
import org.springframework.util.NumberUtils;

View File

@@ -18,6 +18,8 @@ package org.springframework.expression.spel.support;
import java.util.function.Supplier;
import org.jspecify.annotations.Nullable;
import org.springframework.core.convert.ConversionException;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
@@ -25,7 +27,6 @@ import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.expression.TypeConverter;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -76,8 +77,7 @@ public class StandardTypeConverter implements TypeConverter {
}
@Override
@Nullable
public Object convertValue(@Nullable Object value, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {
public @Nullable Object convertValue(@Nullable Object value, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {
try {
return this.conversionService.get().convert(value, sourceType, targetType);
}

View File

@@ -22,12 +22,13 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.jspecify.annotations.Nullable;
import org.springframework.core.SmartClassLoader;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypeLocator;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
/**
@@ -46,8 +47,7 @@ import org.springframework.util.ClassUtils;
*/
public class StandardTypeLocator implements TypeLocator {
@Nullable
private final ClassLoader classLoader;
private final @Nullable ClassLoader classLoader;
private final List<String> importPrefixes = new ArrayList<>(1);
@@ -129,8 +129,7 @@ public class StandardTypeLocator implements TypeLocator {
throw new SpelEvaluationException(SpelMessage.TYPE_NOT_FOUND, typeName);
}
@Nullable
private Class<?> loadType(String typeName) {
private @Nullable Class<?> loadType(String typeName) {
try {
return ClassUtils.forName(typeName, this.classLoader);
}

View File

@@ -1,9 +1,7 @@
/**
* SpEL's default implementations for various core abstractions.
*/
@NonNullApi
@NonNullFields
@NullMarked
package org.springframework.expression.spel.support;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
import org.jspecify.annotations.NullMarked;

View File

@@ -18,6 +18,7 @@ package org.springframework.expression.spel;
import java.math.BigDecimal;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.Test;
import org.springframework.expression.EvaluationException;
@@ -27,7 +28,6 @@ import org.springframework.expression.TypeComparator;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.expression.spel.support.StandardTypeComparator;
import org.springframework.lang.Nullable;
import static org.assertj.core.api.Assertions.assertThat;

View File

@@ -18,11 +18,12 @@ package org.springframework.expression.spel;
import java.util.Map;
import org.jspecify.annotations.Nullable;
import org.springframework.asm.MethodVisitor;
import org.springframework.expression.AccessException;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.TypedValue;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**

View File

@@ -38,6 +38,7 @@ import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.NullNode;
import com.fasterxml.jackson.databind.node.TextNode;
import example.Color;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
@@ -51,7 +52,6 @@ import org.springframework.expression.spel.support.ReflectiveIndexAccessor;
import org.springframework.expression.spel.support.SimpleEvaluationContext;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.expression.spel.testresources.Person;
import org.springframework.lang.Nullable;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;

View File

@@ -36,6 +36,7 @@ import java.util.stream.Stream;
import example.Color;
import example.FruitMap;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
@@ -60,7 +61,6 @@ import org.springframework.expression.spel.support.ReflectiveIndexAccessor;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.expression.spel.testdata.PersonInOtherPackage;
import org.springframework.expression.spel.testresources.Person;
import org.springframework.lang.Nullable;
import org.springframework.util.ReflectionUtils;
import static java.util.stream.Collectors.joining;

View File

@@ -37,6 +37,7 @@ import java.util.Properties;
import java.util.concurrent.atomic.AtomicInteger;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.Test;
import org.springframework.core.MethodParameter;
@@ -61,7 +62,6 @@ import org.springframework.expression.spel.support.ReflectivePropertyAccessor;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.expression.spel.support.StandardTypeLocator;
import org.springframework.expression.spel.testresources.le.div.mod.reserved.Reserver;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
@@ -1169,7 +1169,6 @@ class SpelReproTests extends AbstractExpressionTests {
TypedValue value = accessor.read(context, target, "property");
assertThat(value.getValue()).isEqualTo(1);
assertThat(value.getTypeDescriptor().getType()).isEqualTo(Integer.class);
assertThat(value.getTypeDescriptor().getAnnotations()).isNotEmpty();
}
@Test
@@ -2158,8 +2157,7 @@ class SpelReproTests extends AbstractExpressionTests {
}
@Override
@Nullable
public Integer getProperty() {
public @Nullable Integer getProperty() {
return this.value;
}
}

View File

@@ -18,10 +18,10 @@ package org.springframework.expression.spel.ast;
import java.util.List;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.Test;
import org.springframework.expression.TargetedAccessor;
import org.springframework.lang.Nullable;
import static org.assertj.core.api.Assertions.assertThat;
@@ -102,8 +102,7 @@ class AccessorUtilsTests {
private record DemoAccessor(String name, Class<?>[] types) implements TargetedAccessor {
@Override
@Nullable
public Class<?>[] getSpecificTargetClasses() {
public Class<?> @Nullable [] getSpecificTargetClasses() {
return this.types;
}

View File

@@ -16,7 +16,7 @@
package org.springframework.expression.spel.testresources;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
public class PlaceOfBirth {

View File

@@ -40,9 +40,9 @@ class SpelReproKotlinTests {
val expr = parser.parseExpression("#key.startsWith('hello')")
context.registerFunction("get", Config::class.java.getMethod("get", String::class.java))
context.setVariable("key", "hello world")
assertThat(expr.getValue(context, Boolean::class.java)).isTrue()
assertThat(expr.getValue(context, Boolean::class.java)!!).isTrue()
context.setVariable("key", "")
assertThat(expr.getValue(context, Boolean::class.java)).isFalse()
assertThat(expr.getValue(context, Boolean::class.java)!!).isFalse()
}
@Test
@@ -50,23 +50,23 @@ class SpelReproKotlinTests {
val expr = parser.parseExpression("#key.startsWith('hello')")
context.registerFunction("suspendingGet", Config::class.java.getMethod("suspendingGet", String::class.java, Continuation::class.java))
context.setVariable("key", "hello world")
assertThat(expr.getValue(context, Boolean::class.java)).isTrue()
assertThat(expr.getValue(context, Boolean::class.java)!!).isTrue()
context.setVariable("key", "")
assertThat(expr.getValue(context, Boolean::class.java)).isFalse()
assertThat(expr.getValue(context, Boolean::class.java)!!).isFalse()
}
@Test
fun `gh-30468 Unmangle Kotlin inlined class getter`() {
context.setVariable("something", Something(UUID(123), "name"))
val expr = parser.parseExpression("#something.id")
assertThat(expr.getValue(context, Int::class.java)).isEqualTo(123)
assertThat(expr.getValue(context, Int::class.java)!!).isEqualTo(123)
}
@Test
fun `gh-30468 Unmangle Kotlin inlined class setter`() {
context.setVariable("something", Something(UUID(123), "name"))
val expr = parser.parseExpression("#something.id = 456")
assertThat(expr.getValue(context, Int::class.java)).isEqualTo(456)
assertThat(expr.getValue(context, Int::class.java)!!).isEqualTo(456)
}
@Suppress("UNUSED_PARAMETER")