diff --git a/spring-integration-cassandra/src/main/java/org/springframework/integration/cassandra/outbound/CassandraMessageHandler.java b/spring-integration-cassandra/src/main/java/org/springframework/integration/cassandra/outbound/CassandraMessageHandler.java index 55735df835..1f239ae6fd 100644 --- a/spring-integration-cassandra/src/main/java/org/springframework/integration/cassandra/outbound/CassandraMessageHandler.java +++ b/spring-integration-cassandra/src/main/java/org/springframework/integration/cassandra/outbound/CassandraMessageHandler.java @@ -145,6 +145,7 @@ protected StandardEvaluationContext getEvaluationContext() { setStatementProcessor((ExpressionEvaluatingMessageProcessor>) expressionEvaluatingMessageProcessor); } + @SuppressWarnings("NullAway") // Cassandra driver uses NullAllowingImmutableMap public void setQuery(String query) { Assert.hasText(query, "'query' must not be empty"); this.sessionMessageCallback = diff --git a/spring-integration-core/src/main/java/org/springframework/integration/aop/MessagePublishingInterceptor.java b/spring-integration-core/src/main/java/org/springframework/integration/aop/MessagePublishingInterceptor.java index 44001dd243..84ff01a8c4 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/aop/MessagePublishingInterceptor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/aop/MessagePublishingInterceptor.java @@ -169,7 +169,7 @@ private void publishMessage(Method method, StandardEvaluationContext context) { AbstractIntegrationMessageBuilder builder = (result instanceof Message) ? getMessageBuilderFactory().fromMessage((Message) result) : getMessageBuilderFactory().withPayload(result); - Map headers = evaluateHeaders(method, context); + Map headers = evaluateHeaders(method, context); if (headers != null) { builder.copyHeaders(headers); } @@ -190,7 +190,7 @@ private void publishMessage(Method method, StandardEvaluationContext context) { } } - private @Nullable Map evaluateHeaders(Method method, StandardEvaluationContext context) { + private @Nullable Map evaluateHeaders(Method method, StandardEvaluationContext context) { Map headerExpressionMap = this.metadataSource.getExpressionsForHeaders(method); if (headerExpressionMap != null) { return ExpressionEvalMap.from(headerExpressionMap) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/channel/interceptor/ThreadStatePropagationChannelInterceptor.java b/spring-integration-core/src/main/java/org/springframework/integration/channel/interceptor/ThreadStatePropagationChannelInterceptor.java index ae469494f4..b9ff9224de 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/channel/interceptor/ThreadStatePropagationChannelInterceptor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/channel/interceptor/ThreadStatePropagationChannelInterceptor.java @@ -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; @@ -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); diff --git a/spring-integration-core/src/main/java/org/springframework/integration/expression/DynamicExpression.java b/spring-integration-core/src/main/java/org/springframework/integration/expression/DynamicExpression.java index b21c19f719..8c877db7dd 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/expression/DynamicExpression.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/expression/DynamicExpression.java @@ -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; @@ -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 { @@ -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 getValue(Class desiredResultType) throws EvaluationException { - return this.resolveExpression().getValue(desiredResultType); + public @Nullable T getValue(@Nullable Class desiredResultType) throws EvaluationException { + return getValue((Object) null, desiredResultType); } - public T getValue(Object rootObject, Class desiredResultType) throws EvaluationException { - return this.resolveExpression().getValue(rootObject, desiredResultType); + public @Nullable T getValue(@Nullable Object rootObject, @Nullable Class 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 getValue(EvaluationContext context, Class desiredResultType) throws EvaluationException { - return this.resolveExpression().getValue(context, desiredResultType); + public @Nullable T getValue(EvaluationContext context, @Nullable Class desiredResultType) + throws EvaluationException { + + return resolveExpression().getValue(context, desiredResultType); } - public T getValue(EvaluationContext context, Object rootObject, Class desiredResultType) throws EvaluationException { - return this.resolveExpression().getValue(context, rootObject, desiredResultType); + public @Nullable T getValue(EvaluationContext context, @Nullable Object rootObject, + @Nullable Class 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() { diff --git a/spring-integration-core/src/main/java/org/springframework/integration/expression/ExpressionEvalMap.java b/spring-integration-core/src/main/java/org/springframework/integration/expression/ExpressionEvalMap.java index 2621f25763..234df2bc06 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/expression/ExpressionEvalMap.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/expression/ExpressionEvalMap.java @@ -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; @@ -67,7 +68,7 @@ * * @since 3.0 */ -public final class ExpressionEvalMap extends AbstractMap { +public final class ExpressionEvalMap extends AbstractMap { public static final EvaluationCallback SIMPLE_CALLBACK = Expression::getValue; @@ -85,8 +86,7 @@ private ExpressionEvalMap(Map 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; @@ -107,7 +107,7 @@ else if (value instanceof String) { } @Override - public Set> entrySet() { + public Set> entrySet() { return this.original.keySet() .stream() .map((key) -> new SimpleImmutableEntry<>(key, get(key))) @@ -115,11 +115,11 @@ public Set> entrySet() { } @Override - public Collection 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 @@ -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) { @@ -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); @@ -247,18 +244,15 @@ public static final class ExpressionEvalMapBuilder { private final Map 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(); @@ -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); } } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/expression/ExpressionUtils.java b/spring-integration-core/src/main/java/org/springframework/integration/expression/ExpressionUtils.java index 5ab987bf59..48f8d5f04c 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/expression/ExpressionUtils.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/expression/ExpressionUtils.java @@ -25,7 +25,6 @@ import org.jspecify.annotations.Nullable; import org.springframework.beans.factory.BeanFactory; -import org.springframework.context.expression.BeanFactoryResolver; import org.springframework.context.expression.MapAccessor; import org.springframework.core.convert.ConversionService; import org.springframework.core.io.Resource; @@ -35,11 +34,8 @@ import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.DataBindingPropertyAccessor; import org.springframework.expression.spel.support.SimpleEvaluationContext; -import org.springframework.expression.spel.support.SimpleEvaluationContext.Builder; import org.springframework.expression.spel.support.StandardEvaluationContext; -import org.springframework.expression.spel.support.StandardTypeConverter; import org.springframework.integration.context.IntegrationContextUtils; -import org.springframework.integration.support.utils.IntegrationUtils; import org.springframework.messaging.Message; import org.springframework.util.Assert; import org.springframework.util.ResourceUtils; @@ -107,53 +103,32 @@ public static SimpleEvaluationContext createSimpleEvaluationContext(@Nullable Be } private static EvaluationContext doCreateContext(@Nullable BeanFactory beanFactory, boolean simple) { - ConversionService conversionService = null; - EvaluationContext evaluationContext = null; if (beanFactory != null) { - evaluationContext = - simple - ? IntegrationContextUtils.getSimpleEvaluationContext(beanFactory) - : IntegrationContextUtils.getEvaluationContext(beanFactory); + return simple + ? IntegrationContextUtils.getSimpleEvaluationContext(beanFactory) + : IntegrationContextUtils.getEvaluationContext(beanFactory); } - if (evaluationContext == null) { - if (beanFactory != null) { - conversionService = IntegrationUtils.getConversionService(beanFactory); - } - evaluationContext = createEvaluationContext(conversionService, beanFactory, simple); - } - return evaluationContext; + return createEvaluationContext(simple); } /** * Create a {@link StandardEvaluationContext} with a {@link MapAccessor} in its * property accessor property and the supplied {@link ConversionService} in its * conversionService property. - * @param conversionService the conversion service. - * @param beanFactory the bean factory. * @param simple true if simple. * @return the evaluation context. */ - private static EvaluationContext createEvaluationContext(@Nullable ConversionService conversionService, - @Nullable BeanFactory beanFactory, boolean simple) { - + private static EvaluationContext createEvaluationContext(boolean simple) { if (simple) { - Builder ecBuilder = SimpleEvaluationContext.forPropertyAccessors( - new MapAccessor(), DataBindingPropertyAccessor.forReadOnlyAccess()) - .withInstanceMethods(); - if (conversionService != null) { - ecBuilder.withConversionService(conversionService); - } - return ecBuilder.build(); + return SimpleEvaluationContext.forPropertyAccessors( + new MapAccessor(), + DataBindingPropertyAccessor.forReadOnlyAccess()) + .withInstanceMethods() + .build(); } else { StandardEvaluationContext evaluationContext = new StandardEvaluationContext(); evaluationContext.addPropertyAccessor(new MapAccessor()); - if (conversionService != null) { - evaluationContext.setTypeConverter(new StandardTypeConverter(conversionService)); - } - if (beanFactory != null) { - evaluationContext.setBeanResolver(new BeanFactoryResolver(beanFactory)); - } return evaluationContext; } } @@ -183,8 +158,7 @@ public static File expressionToFile(Expression expression, EvaluationContext eva if (value instanceof File) { return (File) value; } - else if (value instanceof String) { - String path = (String) value; + else if (value instanceof String path) { Assert.hasText(path, String.format("Unable to resolve %s for the provided Expression '%s'.", propertyName, expression.getExpressionString())); try { diff --git a/spring-integration-core/src/main/java/org/springframework/integration/expression/FunctionExpression.java b/spring-integration-core/src/main/java/org/springframework/integration/expression/FunctionExpression.java index 116a326c72..06ef91e963 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/expression/FunctionExpression.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/expression/FunctionExpression.java @@ -54,63 +54,63 @@ */ public class FunctionExpression implements Expression { - private final Function function; + private final Function function; private final EvaluationContext defaultContext = new StandardEvaluationContext(); - public FunctionExpression(Function function) { + public FunctionExpression(Function function) { Assert.notNull(function, "'function' must not be null."); this.function = function; } @Override - @Nullable - public Object getValue() throws EvaluationException { - return this.function.apply(null); + public @Nullable Object getValue() throws EvaluationException { + throw noRootObjectException(); } @Override - @Nullable @SuppressWarnings("unchecked") - public Object getValue(@Nullable Object rootObject) throws EvaluationException { + public @Nullable Object getValue(@Nullable Object rootObject) throws EvaluationException { + if (rootObject == null) { + throw noRootObjectException(); + } return this.function.apply((S) rootObject); } @Override - @Nullable - public T getValue(@Nullable Class desiredResultType) throws EvaluationException { + public @Nullable T getValue(@Nullable Class desiredResultType) throws EvaluationException { return getValue(this.defaultContext, desiredResultType); } @Override - @Nullable - public T getValue(@Nullable Object rootObject, @Nullable Class desiredResultType) + public @Nullable T getValue(@Nullable Object rootObject, @Nullable Class desiredResultType) throws EvaluationException { return getValue(this.defaultContext, rootObject, desiredResultType); } @Override - @Nullable - public Object getValue(EvaluationContext context) throws EvaluationException { + public @Nullable Object getValue(EvaluationContext context) throws EvaluationException { return getValue(context.getRootObject().getValue()); } @Override - @Nullable - public Object getValue(EvaluationContext context, @Nullable Object rootObject) throws EvaluationException { + public @Nullable Object getValue(EvaluationContext context, @Nullable Object rootObject) + throws EvaluationException { + return getValue(rootObject); } @Override - @Nullable - public T getValue(EvaluationContext context, @Nullable Class desiredResultType) throws EvaluationException { + public @Nullable T getValue(EvaluationContext context, @Nullable Class desiredResultType) + throws EvaluationException { + return ExpressionUtils.convertTypedValue(context, new TypedValue(getValue(context)), desiredResultType); } @Override - @Nullable - public T getValue(EvaluationContext context, @Nullable Object rootObject, @Nullable Class desiredResultType) + public @Nullable T getValue(EvaluationContext context, @Nullable Object rootObject, + @Nullable Class desiredResultType) throws EvaluationException { return ExpressionUtils.convertTypedValue(context, @@ -176,11 +176,6 @@ public void setValue(EvaluationContext context, @Nullable Object rootObject, @Nu throw readOnlyException(); } - private EvaluationException readOnlyException() { - return new EvaluationException(getExpressionString(), - "FunctionExpression is a 'read only' Expression implementation"); - } - @Override public boolean isWritable(EvaluationContext context) throws EvaluationException { return false; @@ -201,4 +196,14 @@ public final String getExpressionString() { return this.function.toString(); } + private EvaluationException readOnlyException() { + return new EvaluationException(getExpressionString(), + "FunctionExpression is a 'read-only' Expression implementation"); + } + + private EvaluationException noRootObjectException() { + return new EvaluationException(getExpressionString(), + "FunctionExpression does not support 'getValue()' contract without 'rootObject'"); + } + } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/expression/ReloadableResourceBundleExpressionSource.java b/spring-integration-core/src/main/java/org/springframework/integration/expression/ReloadableResourceBundleExpressionSource.java index 4b87d9a30d..d71a37a2c9 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/expression/ReloadableResourceBundleExpressionSource.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/expression/ReloadableResourceBundleExpressionSource.java @@ -102,9 +102,9 @@ public class ReloadableResourceBundleExpressionSource implements ExpressionSourc private String[] basenames = {}; - private String defaultEncoding; + private @Nullable String defaultEncoding; - private Properties fileEncodings; + private @Nullable Properties fileEncodings; private boolean fallbackToSystemLocale = true; @@ -144,7 +144,7 @@ public void setBasename(String basename) { * @see #setBasename * @see java.util.ResourceBundle */ - public void setBasenames(@Nullable String[] basenames) { + public void setBasenames(String @Nullable [] basenames) { if (basenames != null) { this.basenames = new String[basenames.length]; for (int i = 0; i < basenames.length; i++) { @@ -218,7 +218,7 @@ public void setFallbackToSystemLocale(boolean fallbackToSystemLocale) { * @param cacheSeconds The cache seconds. */ public void setCacheSeconds(int cacheSeconds) { - this.cacheMillis = (cacheSeconds * 1000); // NOSONAR + this.cacheMillis = (cacheSeconds * 1000L); } /** @@ -237,7 +237,7 @@ public void setPropertiesPersister(@Nullable PropertiesPersister propertiesPersi *

The default is a DefaultResourceLoader. Will get overridden by the * ApplicationContext if running in a context, as it implements the * ResourceLoaderAware interface. Can be manually overridden when - * running outside of an ApplicationContext. + * running outside an ApplicationContext. * @see org.springframework.core.io.DefaultResourceLoader * @see org.springframework.context.ResourceLoaderAware */ @@ -250,7 +250,7 @@ public void setResourceLoader(@Nullable ResourceLoader resourceLoader) { * Resolves the given key in the retrieved bundle files to an Expression. */ @Override - public Expression getExpression(String key, Locale locale) { + public @Nullable Expression getExpression(String key, Locale locale) { String expressionString = getExpressionString(key, locale); if (expressionString != null) { return this.parser.parseExpression(expressionString); @@ -258,8 +258,7 @@ public Expression getExpression(String key, Locale locale) { return null; } - @Nullable - private String getExpressionString(String key, Locale locale) { + private @Nullable String getExpressionString(String key, Locale locale) { if (this.cacheMillis < 0) { PropertiesHolder propHolder = getMergedProperties(locale); return propHolder.getProperty(key); @@ -379,18 +378,18 @@ private List calculateFilenamesForLocale(String basename, Locale locale) StringBuilder temp = new StringBuilder(basename); temp.append('_'); - if (language.length() > 0) { + if (!language.isEmpty()) { temp.append(language); result.add(0, temp.toString()); } temp.append('_'); - if (country.length() > 0) { + if (!country.isEmpty()) { temp.append(country); result.add(0, temp.toString()); } - if (variant.length() > 0 && (language.length() > 0 || country.length() > 0)) { + if (!variant.isEmpty() && (!language.isEmpty() || !country.isEmpty())) { temp.append('_').append(variant); result.add(0, temp.toString()); } @@ -454,7 +453,6 @@ private PropertiesHolder refreshProperties(String filename, @Nullable Properties LOGGER.debug(resource + " could not be resolved in the file system - assuming that is hasn't changed", ex); } - fileTimestamp = -1; } } propHolder = load(filename, resource, fileTimestamp); @@ -542,8 +540,7 @@ private void loadFromProperties(Resource resource, String filename, InputStream } else { if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Loading properties [" + (resourceFilename == null ? resource : resourceFilename) - + "]"); + LOGGER.debug("Loading properties [" + (resourceFilename == null ? resource : resourceFilename) + "]"); } this.propertiesPersister.load(props, is); } @@ -585,7 +582,7 @@ public String toString() { */ private static final class PropertiesHolder { - private Properties properties; + private @Nullable Properties properties; private long fileTimestamp = -1; @@ -599,8 +596,7 @@ private static final class PropertiesHolder { this.fileTimestamp = fileTimestamp; } - @Nullable - public Properties getProperties() { + public @Nullable Properties getProperties() { return this.properties; } @@ -616,8 +612,7 @@ public long getRefreshTimestamp() { return this.refreshTimestamp; } - @Nullable - public String getProperty(String code) { + public @Nullable String getProperty(String code) { if (this.properties == null) { return null; } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/expression/SupplierExpression.java b/spring-integration-core/src/main/java/org/springframework/integration/expression/SupplierExpression.java index 865a6efebc..9728b5ddf4 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/expression/SupplierExpression.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/expression/SupplierExpression.java @@ -16,8 +16,11 @@ package org.springframework.integration.expression; +import java.util.Objects; 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; @@ -67,40 +70,43 @@ public Object getValue() throws EvaluationException { } @Override - public Object getValue(Object rootObject) throws EvaluationException { + public Object getValue(@Nullable Object rootObject) throws EvaluationException { return getValue(); } @Override - public C getValue(Class desiredResultType) throws EvaluationException { + public C getValue(@Nullable Class desiredResultType) throws EvaluationException { return getValue(this.defaultContext, desiredResultType); } @Override - public C getValue(Object rootObject, Class desiredResultType) throws EvaluationException { + public C getValue(@Nullable Object rootObject, @Nullable Class desiredResultType) + throws EvaluationException { + return getValue(this.defaultContext, rootObject, desiredResultType); } @Override public Object getValue(EvaluationContext context) throws EvaluationException { - Object root = context.getRootObject().getValue(); - return root == null ? getValue() : getValue(root); + return getValue(); } @Override - public Object getValue(EvaluationContext context, Object rootObject) throws EvaluationException { - return getValue(rootObject); + public Object getValue(EvaluationContext context, @Nullable Object rootObject) throws EvaluationException { + return getValue(); } @Override - public C getValue(EvaluationContext context, Class desiredResultType) throws EvaluationException { - return ExpressionUtils.convertTypedValue(context, new TypedValue(getValue(context)), desiredResultType); + public C getValue(EvaluationContext context, @Nullable Class desiredResultType) throws EvaluationException { + C value = ExpressionUtils.convertTypedValue(context, new TypedValue(getValue()), desiredResultType); + return Objects.requireNonNull(value); } @Override - public C getValue(EvaluationContext context, Object rootObject, Class desiredResultType) + public C getValue(EvaluationContext context, @Nullable Object rootObject, @Nullable Class desiredResultType) throws EvaluationException { - return ExpressionUtils.convertTypedValue(context, new TypedValue(getValue(rootObject)), desiredResultType); + + return getValue(context, desiredResultType); } @Override @@ -109,7 +115,7 @@ public Class getValueType() throws EvaluationException { } @Override - public Class getValueType(Object rootObject) throws EvaluationException { + public Class getValueType(@Nullable Object rootObject) throws EvaluationException { throw readOnlyException(); } @@ -119,7 +125,7 @@ public Class getValueType(EvaluationContext context) throws EvaluationExcepti } @Override - public Class getValueType(EvaluationContext context, Object rootObject) throws EvaluationException { + public Class getValueType(EvaluationContext context, @Nullable Object rootObject) throws EvaluationException { throw readOnlyException(); } @@ -129,7 +135,7 @@ public TypeDescriptor getValueTypeDescriptor() throws EvaluationException { } @Override - public TypeDescriptor getValueTypeDescriptor(Object rootObject) throws EvaluationException { + public TypeDescriptor getValueTypeDescriptor(@Nullable Object rootObject) throws EvaluationException { throw readOnlyException(); } @@ -139,23 +145,26 @@ public TypeDescriptor getValueTypeDescriptor(EvaluationContext context) throws E } @Override - public TypeDescriptor getValueTypeDescriptor(EvaluationContext context, Object rootObject) + public TypeDescriptor getValueTypeDescriptor(EvaluationContext context, @Nullable Object rootObject) throws EvaluationException { + throw readOnlyException(); } @Override - public void setValue(EvaluationContext context, Object value) throws EvaluationException { + public void setValue(EvaluationContext context, @Nullable Object value) throws EvaluationException { throw readOnlyException(); } @Override - public void setValue(Object rootObject, Object value) throws EvaluationException { + public void setValue(@Nullable Object rootObject, @Nullable Object value) throws EvaluationException { throw readOnlyException(); } @Override - public void setValue(EvaluationContext context, Object rootObject, Object value) throws EvaluationException { + public void setValue(EvaluationContext context, @Nullable Object rootObject, @Nullable Object value) + throws EvaluationException { + throw readOnlyException(); } @@ -170,12 +179,12 @@ public boolean isWritable(EvaluationContext context) throws EvaluationException } @Override - public boolean isWritable(EvaluationContext context, Object rootObject) throws EvaluationException { + public boolean isWritable(EvaluationContext context, @Nullable Object rootObject) throws EvaluationException { return false; } @Override - public boolean isWritable(Object rootObject) throws EvaluationException { + public boolean isWritable(@Nullable Object rootObject) throws EvaluationException { return false; } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/expression/ValueExpression.java b/spring-integration-core/src/main/java/org/springframework/integration/expression/ValueExpression.java index 899ca52ac7..21f10844be 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/expression/ValueExpression.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/expression/ValueExpression.java @@ -16,11 +16,16 @@ package org.springframework.integration.expression; +import java.util.Objects; + +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.expression.common.ExpressionUtils; import org.springframework.util.Assert; /** @@ -47,7 +52,7 @@ public class ValueExpression implements Expression { private final TypeDescriptor typeDescriptor; - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "NullAway"}) public ValueExpression(V value) { Assert.notNull(value, "'value' must not be null"); this.value = value; @@ -62,7 +67,7 @@ public V getValue() throws EvaluationException { } @Override - public V getValue(Object rootObject) throws EvaluationException { + public V getValue(@Nullable Object rootObject) throws EvaluationException { return this.value; } @@ -72,30 +77,34 @@ public V getValue(EvaluationContext context) throws EvaluationException { } @Override - public V getValue(EvaluationContext context, Object rootObject) throws EvaluationException { + public V getValue(EvaluationContext context, @Nullable Object rootObject) throws EvaluationException { return this.value; } @Override - public T getValue(Object rootObject, Class desiredResultType) throws EvaluationException { + public T getValue(@Nullable Object rootObject, @Nullable Class desiredResultType) + throws EvaluationException { + return getValue(desiredResultType); } @Override - public T getValue(Class desiredResultType) throws EvaluationException { - return org.springframework.expression.common.ExpressionUtils - .convertTypedValue(null, this.typedResultValue, desiredResultType); + public T getValue(@Nullable Class desiredResultType) throws EvaluationException { + T aValue = ExpressionUtils.convertTypedValue(null, this.typedResultValue, desiredResultType); + return Objects.requireNonNull(aValue); } @Override - public T getValue(EvaluationContext context, Object rootObject, Class desiredResultType) throws EvaluationException { + public T getValue(EvaluationContext context, @Nullable Object rootObject, @Nullable Class desiredResultType) + throws EvaluationException { + return getValue(context, desiredResultType); } @Override - public T getValue(EvaluationContext context, Class desiredResultType) throws EvaluationException { - return org.springframework.expression.common.ExpressionUtils - .convertTypedValue(context, this.typedResultValue, desiredResultType); + public T getValue(EvaluationContext context, @Nullable Class desiredResultType) throws EvaluationException { + T aValue = ExpressionUtils.convertTypedValue(context, this.typedResultValue, desiredResultType); + return Objects.requireNonNull(aValue); } @Override @@ -104,7 +113,7 @@ public Class getValueType() throws EvaluationException { } @Override - public Class getValueType(Object rootObject) throws EvaluationException { + public Class getValueType(@Nullable Object rootObject) throws EvaluationException { return this.aClass; } @@ -114,7 +123,7 @@ public Class getValueType(EvaluationContext context) throws EvaluationExcepti } @Override - public Class getValueType(EvaluationContext context, Object rootObject) throws EvaluationException { + public Class getValueType(EvaluationContext context, @Nullable Object rootObject) throws EvaluationException { return this.aClass; } @@ -124,7 +133,7 @@ public TypeDescriptor getValueTypeDescriptor() throws EvaluationException { } @Override - public TypeDescriptor getValueTypeDescriptor(Object rootObject) throws EvaluationException { + public TypeDescriptor getValueTypeDescriptor(@Nullable Object rootObject) throws EvaluationException { return this.typeDescriptor; } @@ -134,7 +143,9 @@ public TypeDescriptor getValueTypeDescriptor(EvaluationContext context) throws E } @Override - public TypeDescriptor getValueTypeDescriptor(EvaluationContext context, Object rootObject) throws EvaluationException { + public TypeDescriptor getValueTypeDescriptor(EvaluationContext context, @Nullable Object rootObject) + throws EvaluationException { + return this.typeDescriptor; } @@ -144,27 +155,29 @@ public boolean isWritable(EvaluationContext context) throws EvaluationException } @Override - public boolean isWritable(EvaluationContext context, Object rootObject) throws EvaluationException { + public boolean isWritable(EvaluationContext context, @Nullable Object rootObject) throws EvaluationException { return false; } @Override - public boolean isWritable(Object rootObject) throws EvaluationException { + public boolean isWritable(@Nullable Object rootObject) throws EvaluationException { return false; } @Override - public void setValue(EvaluationContext context, Object value) throws EvaluationException { + public void setValue(EvaluationContext context, @Nullable Object value) throws EvaluationException { setValue(context, null, value); } @Override - public void setValue(Object rootObject, Object value) throws EvaluationException { - setValue(null, rootObject, value); + public void setValue(@Nullable Object rootObject, @Nullable Object value) throws EvaluationException { + throw new EvaluationException(this.value.toString(), "Cannot call setValue() on a ValueExpression"); } @Override - public void setValue(EvaluationContext context, Object rootObject, Object value) throws EvaluationException { + public void setValue(EvaluationContext context, @Nullable Object rootObject, @Nullable Object value) + throws EvaluationException { + throw new EvaluationException(this.value.toString(), "Cannot call setValue() on a ValueExpression"); } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/expression/package-info.java b/spring-integration-core/src/main/java/org/springframework/integration/expression/package-info.java index 06cd283d61..ed253249a0 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/expression/package-info.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/expression/package-info.java @@ -1,5 +1,5 @@ /** * Provides classes supporting SpEL expressions. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.integration.expression; diff --git a/spring-integration-graphql/src/main/java/org/springframework/integration/graphql/outbound/GraphQlMessageHandler.java b/spring-integration-graphql/src/main/java/org/springframework/integration/graphql/outbound/GraphQlMessageHandler.java index 3db278a5eb..8c0487b654 100644 --- a/spring-integration-graphql/src/main/java/org/springframework/integration/graphql/outbound/GraphQlMessageHandler.java +++ b/spring-integration-graphql/src/main/java/org/springframework/integration/graphql/outbound/GraphQlMessageHandler.java @@ -30,7 +30,6 @@ import org.springframework.graphql.support.DefaultExecutionGraphQlRequest; import org.springframework.integration.expression.ExpressionUtils; import org.springframework.integration.expression.FunctionExpression; -import org.springframework.integration.expression.SupplierExpression; import org.springframework.integration.handler.AbstractReplyProducingMessageHandler; import org.springframework.messaging.Message; import org.springframework.util.Assert; @@ -52,13 +51,13 @@ public class GraphQlMessageHandler extends AbstractReplyProducingMessageHandler private @Nullable Expression operationExpression; - private Expression operationNameExpression = new SupplierExpression<>(() -> null); + private @Nullable Expression operationNameExpression = null; - private Expression variablesExpression = new SupplierExpression<>(() -> null); + private @Nullable Expression variablesExpression = null; private @Nullable Locale locale; - @SuppressWarnings("NullAway") // In most cases the message really comes with an ID + @SuppressWarnings("NullAway") // Cannot determine that function result could be null private Expression executionIdExpression = new FunctionExpression>(message -> message.getHeaders().getId()); @@ -164,12 +163,20 @@ private String evaluateOperationExpression(Message message) { } private @Nullable String evaluateOperationNameExpression(Message message) { - return this.operationNameExpression.getValue(this.evaluationContext, message, String.class); + if (this.operationNameExpression != null) { + return this.operationNameExpression.getValue(this.evaluationContext, message, String.class); + } + + return null; } @SuppressWarnings("unchecked") private @Nullable Map evaluateVariablesExpression(Message message) { - return this.variablesExpression.getValue(this.evaluationContext, message, Map.class); + if (this.variablesExpression != null) { + return this.variablesExpression.getValue(this.evaluationContext, message, Map.class); + } + + return null; } private @Nullable String evaluateExecutionIdExpression(Message message) { diff --git a/spring-integration-ws/src/main/java/org/springframework/integration/ws/AbstractWebServiceOutboundGateway.java b/spring-integration-ws/src/main/java/org/springframework/integration/ws/AbstractWebServiceOutboundGateway.java index 9232f645e9..34d2cad663 100644 --- a/spring-integration-ws/src/main/java/org/springframework/integration/ws/AbstractWebServiceOutboundGateway.java +++ b/spring-integration-ws/src/main/java/org/springframework/integration/ws/AbstractWebServiceOutboundGateway.java @@ -226,7 +226,7 @@ protected WebServiceTemplate getWebServiceTemplate() { return this.destinationProvider.getDestination(); } - Map uriVariables = + Map uriVariables = ExpressionEvalMap.from(this.uriVariableExpressions) .usingEvaluationContext(this.evaluationContext) .withRoot(requestMessage)