Skip to content

GH-10083: Apply Nullability to Core expression package #10265

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ protected StandardEvaluationContext getEvaluationContext() {
setStatementProcessor((ExpressionEvaluatingMessageProcessor<Statement<?>>) expressionEvaluatingMessageProcessor);
}

@SuppressWarnings("NullAway") // Cassandra driver uses NullAllowingImmutableMap
public void setQuery(String query) {
Assert.hasText(query, "'query' must not be empty");
this.sessionMessageCallback =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ private void publishMessage(Method method, StandardEvaluationContext context) {
AbstractIntegrationMessageBuilder<?> builder = (result instanceof Message<?>)
? getMessageBuilderFactory().fromMessage((Message<?>) result)
: getMessageBuilderFactory().withPayload(result);
Map<String, Object> headers = evaluateHeaders(method, context);
Map<String, @Nullable Object> headers = evaluateHeaders(method, context);
if (headers != null) {
builder.copyHeaders(headers);
}
Expand All @@ -190,7 +190,7 @@ private void publishMessage(Method method, StandardEvaluationContext context) {
}
}

private @Nullable Map<String, Object> evaluateHeaders(Method method, StandardEvaluationContext context) {
private @Nullable Map<String, @Nullable Object> evaluateHeaders(Method method, StandardEvaluationContext context) {
Map<String, Expression> headerExpressionMap = this.metadataSource.getExpressionsForHeaders(method);
if (headerExpressionMap != null) {
return ExpressionEvalMap.from(headerExpressionMap)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;

import io.micrometer.common.lang.Nullable;
import org.jspecify.annotations.Nullable;

import org.springframework.integration.support.MessageDecorator;
import org.springframework.messaging.Message;
Expand Down Expand Up @@ -92,8 +92,7 @@ public final Message<?> beforeHandle(Message<?> message, MessageChannel channel,
return postReceive(message, channel);
}

@Nullable
protected abstract S obtainPropagatingContext(Message<?> message, MessageChannel channel);
protected abstract @Nullable S obtainPropagatingContext(Message<?> message, MessageChannel channel);

protected abstract void populatePropagatedContext(@Nullable S state, Message<?> message, MessageChannel channel);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

import java.util.Locale;

import org.jspecify.annotations.Nullable;

import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.EvaluationContext;
Expand All @@ -30,6 +32,8 @@
* for resolving the actual Expression instance per-invocation at runtime.
*
* @author Mark Fisher
* @author Artem Bilan
*
* @since 2.0
*/
public class DynamicExpression implements Expression {
Expand All @@ -45,96 +49,110 @@ public DynamicExpression(String key, ExpressionSource expressionSource) {
this.expressionSource = expressionSource;
}

public Object getValue() throws EvaluationException {
return this.resolveExpression().getValue();
public @Nullable Object getValue() throws EvaluationException {
return getValue((Object) null);
}

public Object getValue(Object rootObject) throws EvaluationException {
return this.resolveExpression().getValue(rootObject);
public @Nullable Object getValue(@Nullable Object rootObject) throws EvaluationException {
return getValue(rootObject, null);
}

public <T> T getValue(Class<T> desiredResultType) throws EvaluationException {
return this.resolveExpression().getValue(desiredResultType);
public <T> @Nullable T getValue(@Nullable Class<T> desiredResultType) throws EvaluationException {
return getValue((Object) null, desiredResultType);
}

public <T> T getValue(Object rootObject, Class<T> desiredResultType) throws EvaluationException {
return this.resolveExpression().getValue(rootObject, desiredResultType);
public <T> @Nullable T getValue(@Nullable Object rootObject, @Nullable Class<T> desiredResultType)
throws EvaluationException {

return resolveExpression().getValue(rootObject, desiredResultType);
}

public Object getValue(EvaluationContext context) throws EvaluationException {
return this.resolveExpression().getValue(context);
public @Nullable Object getValue(EvaluationContext context) throws EvaluationException {
return resolveExpression().getValue(context);
}

public Object getValue(EvaluationContext context, Object rootObject) throws EvaluationException {
return this.resolveExpression().getValue(context, rootObject);
public @Nullable Object getValue(EvaluationContext context, @Nullable Object rootObject)
throws EvaluationException {

return getValue(context, rootObject, null);
}

public <T> T getValue(EvaluationContext context, Class<T> desiredResultType) throws EvaluationException {
return this.resolveExpression().getValue(context, desiredResultType);
public <T> @Nullable T getValue(EvaluationContext context, @Nullable Class<T> desiredResultType)
throws EvaluationException {

return resolveExpression().getValue(context, desiredResultType);
}

public <T> T getValue(EvaluationContext context, Object rootObject, Class<T> desiredResultType) throws EvaluationException {
return this.resolveExpression().getValue(context, rootObject, desiredResultType);
public <T> @Nullable T getValue(EvaluationContext context, @Nullable Object rootObject,
@Nullable Class<T> desiredResultType) throws EvaluationException {

return resolveExpression().getValue(context, rootObject, desiredResultType);
}

public Class<?> getValueType() throws EvaluationException {
return this.resolveExpression().getValueType();
public @Nullable Class<?> getValueType() throws EvaluationException {
return getValueType((Object) null);
}

public Class<?> getValueType(Object rootObject) throws EvaluationException {
return this.resolveExpression().getValueType(rootObject);
public @Nullable Class<?> getValueType(@Nullable Object rootObject) throws EvaluationException {
return resolveExpression().getValueType(rootObject);
}

public Class<?> getValueType(EvaluationContext context) throws EvaluationException {
return this.resolveExpression().getValueType(context);
public @Nullable Class<?> getValueType(EvaluationContext context) throws EvaluationException {
return resolveExpression().getValueType(context);
}

public Class<?> getValueType(EvaluationContext context, Object rootObject) throws EvaluationException {
return this.resolveExpression().getValueType(context, rootObject);
public @Nullable Class<?> getValueType(EvaluationContext context, @Nullable Object rootObject)
throws EvaluationException {

return resolveExpression().getValueType(context, rootObject);
}

public TypeDescriptor getValueTypeDescriptor() throws EvaluationException {
return this.resolveExpression().getValueTypeDescriptor();
public @Nullable TypeDescriptor getValueTypeDescriptor() throws EvaluationException {
return getValueTypeDescriptor((Object) null);
}

public TypeDescriptor getValueTypeDescriptor(Object rootObject) throws EvaluationException {
public @Nullable TypeDescriptor getValueTypeDescriptor(@Nullable Object rootObject) throws EvaluationException {
return this.resolveExpression().getValueTypeDescriptor(rootObject);
}

public TypeDescriptor getValueTypeDescriptor(EvaluationContext context) throws EvaluationException {
return this.resolveExpression().getValueTypeDescriptor(context);
public @Nullable TypeDescriptor getValueTypeDescriptor(EvaluationContext context) throws EvaluationException {
return resolveExpression().getValueTypeDescriptor(context);
}

public TypeDescriptor getValueTypeDescriptor(EvaluationContext context, Object rootObject) throws EvaluationException {
return this.resolveExpression().getValueTypeDescriptor(context, rootObject);
public @Nullable TypeDescriptor getValueTypeDescriptor(EvaluationContext context, @Nullable Object rootObject)
throws EvaluationException {

return resolveExpression().getValueTypeDescriptor(context, rootObject);
}

public boolean isWritable(EvaluationContext context) throws EvaluationException {
return this.resolveExpression().isWritable(context);
return resolveExpression().isWritable(context);
}

public boolean isWritable(EvaluationContext context, Object rootObject) throws EvaluationException {
return this.resolveExpression().isWritable(context, rootObject);
public boolean isWritable(EvaluationContext context, @Nullable Object rootObject) throws EvaluationException {
return resolveExpression().isWritable(context, rootObject);
}

public boolean isWritable(Object rootObject) throws EvaluationException {
return this.resolveExpression().isWritable(rootObject);
public boolean isWritable(@Nullable Object rootObject) throws EvaluationException {
return resolveExpression().isWritable(rootObject);
}

public void setValue(EvaluationContext context, Object value) throws EvaluationException {
this.resolveExpression().setValue(context, value);
public void setValue(EvaluationContext context, @Nullable Object value) throws EvaluationException {
resolveExpression().setValue(context, value);
}

public void setValue(Object rootObject, Object value) throws EvaluationException {
this.resolveExpression().setValue(rootObject, value);
public void setValue(@Nullable Object rootObject, @Nullable Object value) throws EvaluationException {
resolveExpression().setValue(rootObject, value);
}

public void setValue(EvaluationContext context, Object rootObject, Object value) throws EvaluationException {
this.resolveExpression().setValue(context, rootObject, value);
public void setValue(EvaluationContext context, @Nullable Object rootObject, @Nullable Object value)
throws EvaluationException {

resolveExpression().setValue(context, rootObject, value);
}

public String getExpressionString() {
return this.resolveExpression().getExpressionString();
return resolveExpression().getExpressionString();
}

private Expression resolveExpression() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.springframework.integration.expression;

import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
Expand Down Expand Up @@ -67,7 +68,7 @@
*
* @since 3.0
*/
public final class ExpressionEvalMap extends AbstractMap<String, Object> {
public final class ExpressionEvalMap extends AbstractMap<String, @Nullable Object> {

public static final EvaluationCallback SIMPLE_CALLBACK = Expression::getValue;

Expand All @@ -85,8 +86,7 @@ private ExpressionEvalMap(Map<String, ?> original, EvaluationCallback evaluation
* from {@link #original} and returns the result of evaluation using {@link #evaluationCallback}.
*/
@Override
@Nullable
public Object get(Object key) {
public @Nullable Object get(Object key) {
Object value = this.original.get(key);
if (value != null) {
Expression expression;
Expand All @@ -107,19 +107,19 @@ else if (value instanceof String) {
}

@Override
public Set<Map.Entry<String, Object>> entrySet() {
public Set<Map.Entry<String, @Nullable Object>> entrySet() {
return this.original.keySet()
.stream()
.map((key) -> new SimpleImmutableEntry<>(key, get(key)))
.collect(Collectors.toSet());
}

@Override
public Collection<Object> values() {
public Collection<@Nullable Object> values() {
return this.original.values()
.stream()
.map(this::get)
.collect(Collectors.toList());
.collect(Collectors.toCollection(ArrayList<@Nullable Object>::new));
}

@Override
Expand Down Expand Up @@ -205,16 +205,13 @@ public interface EvaluationCallback {
*/
public static class ComponentsEvaluationCallback implements EvaluationCallback {

@Nullable
private final EvaluationContext context;
private final @Nullable EvaluationContext context;

@Nullable
private final Object root;
private final @Nullable Object root;

private final boolean rootExplicitlySet;

@Nullable
private final Class<?> returnType;
private final @Nullable Class<?> returnType;

public ComponentsEvaluationCallback(@Nullable EvaluationContext context, @Nullable Object root,
boolean rootExplicitlySet, @Nullable Class<?> returnType) {
Expand All @@ -226,7 +223,7 @@ public ComponentsEvaluationCallback(@Nullable EvaluationContext context, @Nullab
}

@Override
public Object evaluate(Expression expression) {
public @Nullable Object evaluate(Expression expression) {
if (this.context != null) {
if (this.rootExplicitlySet) {
return expression.getValue(this.context, this.root, this.returnType);
Expand All @@ -247,18 +244,15 @@ public static final class ExpressionEvalMapBuilder {

private final Map<String, ?> expressions;

private EvaluationCallback evaluationCallback;
private @Nullable EvaluationCallback evaluationCallback;

@Nullable
private EvaluationContext context;
private @Nullable EvaluationContext context;

@Nullable
private Object root;
private @Nullable Object root;

private boolean rootExplicitlySet;

@Nullable
private Class<?> returnType;
private @Nullable Class<?> returnType;

private final ExpressionEvalMapComponentsBuilder evalMapComponentsBuilder =
new ExpressionEvalMapComponentsBuilderImpl();
Expand Down Expand Up @@ -303,16 +297,16 @@ private class ExpressionEvalMapFinalBuilderImpl implements ExpressionEvalMapFina

@Override
public ExpressionEvalMap build() {
if (ExpressionEvalMapBuilder.this.evaluationCallback != null) {
return new ExpressionEvalMap(ExpressionEvalMapBuilder.this.expressions,
ExpressionEvalMapBuilder.this.evaluationCallback);
}
else {
return new ExpressionEvalMap(ExpressionEvalMapBuilder.this.expressions,
EvaluationCallback evaluationCallbackToUse = ExpressionEvalMapBuilder.this.evaluationCallback;
if (evaluationCallbackToUse == null) {
evaluationCallbackToUse =
new ComponentsEvaluationCallback(ExpressionEvalMapBuilder.this.context,
ExpressionEvalMapBuilder.this.root, ExpressionEvalMapBuilder.this.rootExplicitlySet,
ExpressionEvalMapBuilder.this.returnType));
ExpressionEvalMapBuilder.this.root,
ExpressionEvalMapBuilder.this.rootExplicitlySet,
ExpressionEvalMapBuilder.this.returnType);
}

return new ExpressionEvalMap(ExpressionEvalMapBuilder.this.expressions, evaluationCallbackToUse);
}

}
Expand Down
Loading