diff --git a/gradle/plugins/conventions-plugin/build.gradle b/gradle/plugins/conventions-plugin/build.gradle index 04665704..4bfaba73 100644 --- a/gradle/plugins/conventions-plugin/build.gradle +++ b/gradle/plugins/conventions-plugin/build.gradle @@ -15,6 +15,7 @@ dependencies { checkstyle("io.spring.javaformat:spring-javaformat-checkstyle:${javaFormatVersion}") implementation("com.github.ben-manes:gradle-versions-plugin:$gradleVersionsPluginVersion") + implementation("io.spring.gradle.nullability:nullability-plugin:$nullabilityPluginVersion") implementation("io.spring.javaformat:spring-javaformat-gradle-plugin:$javaFormatVersion") testImplementation("org.junit.jupiter:junit-jupiter") diff --git a/gradle/plugins/conventions-plugin/src/main/java/org/springframework/ws/gradle/conventions/ConventionsPlugin.java b/gradle/plugins/conventions-plugin/src/main/java/org/springframework/ws/gradle/conventions/ConventionsPlugin.java index 435ed0a4..3b46bbcf 100644 --- a/gradle/plugins/conventions-plugin/src/main/java/org/springframework/ws/gradle/conventions/ConventionsPlugin.java +++ b/gradle/plugins/conventions-plugin/src/main/java/org/springframework/ws/gradle/conventions/ConventionsPlugin.java @@ -16,6 +16,7 @@ package org.springframework.ws.gradle.conventions; +import io.spring.gradle.nullability.NullabilityPlugin; import org.gradle.api.Plugin; import org.gradle.api.Project; import org.gradle.api.plugins.JavaBasePlugin; @@ -37,7 +38,10 @@ public class ConventionsPlugin implements Plugin { new JavaBasePluginConventions().apply(project); new CheckstyleConventions().apply(project); }); - project.getPlugins().withType(JavaPlugin.class).all((plugin) -> new JavaPluginConventions().apply(project)); + project.getPlugins().withType(JavaPlugin.class).all((plugin) -> { + project.getPlugins().apply(NullabilityPlugin.class); + new JavaPluginConventions().apply(project); + }); project.getPlugins() .withType(MavenPublishPlugin.class) .all((plugin) -> new MavenPublishPluginConventions().apply(project)); diff --git a/gradle/plugins/gradle.properties b/gradle/plugins/gradle.properties index b80bde94..6fa81f89 100644 --- a/gradle/plugins/gradle.properties +++ b/gradle/plugins/gradle.properties @@ -1,4 +1,5 @@ assertJVersion=3.25.3 gradleVersionsPluginVersion=0.52.0 -javaFormatVersion=0.0.45 +javaFormatVersion=0.0.46 junitVersion=5.11.0 +nullabilityPluginVersion=0.0.1 \ No newline at end of file diff --git a/spring-ws-core/src/main/java/org/springframework/ws/FaultAwareWebServiceMessage.java b/spring-ws-core/src/main/java/org/springframework/ws/FaultAwareWebServiceMessage.java index bbea7534..0c909beb 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/FaultAwareWebServiceMessage.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/FaultAwareWebServiceMessage.java @@ -18,6 +18,8 @@ package org.springframework.ws; import javax.xml.namespace.QName; +import org.jspecify.annotations.Nullable; + /** * Sub-interface of {@link WebServiceMessage} that can contain special Fault messages. * Fault messages (such as {@link org.springframework.ws.soap.SoapFault} SOAP Faults) @@ -39,7 +41,7 @@ public interface FaultAwareWebServiceMessage extends WebServiceMessage { /** * Returns the fault code, if any. */ - QName getFaultCode(); + @Nullable QName getFaultCode(); /** * Returns the fault reason message. @@ -47,6 +49,6 @@ public interface FaultAwareWebServiceMessage extends WebServiceMessage { * present. * @see #hasFault() */ - String getFaultReason(); + @Nullable String getFaultReason(); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/WebServiceException.java b/spring-ws-core/src/main/java/org/springframework/ws/WebServiceException.java index 33d432db..c32f460f 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/WebServiceException.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/WebServiceException.java @@ -16,6 +16,8 @@ package org.springframework.ws; +import org.jspecify.annotations.Nullable; + import org.springframework.core.NestedRuntimeException; /** @@ -31,7 +33,7 @@ public abstract class WebServiceException extends NestedRuntimeException { * Create a new instance of the {@code WebServiceException} class. * @param msg the detail message */ - public WebServiceException(String msg) { + public WebServiceException(@Nullable String msg) { super(msg); } @@ -40,7 +42,7 @@ public abstract class WebServiceException extends NestedRuntimeException { * @param msg the detail message * @param ex the root {@link Throwable exception} */ - public WebServiceException(String msg, Throwable ex) { + public WebServiceException(@Nullable String msg, Throwable ex) { super(msg, ex); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/WebServiceMessage.java b/spring-ws-core/src/main/java/org/springframework/ws/WebServiceMessage.java index c575ee52..f8985867 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/WebServiceMessage.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/WebServiceMessage.java @@ -22,6 +22,8 @@ import java.io.OutputStream; import javax.xml.transform.Result; import javax.xml.transform.Source; +import org.jspecify.annotations.Nullable; + /** * Represents a protocol-agnostic XML message. *

@@ -41,7 +43,7 @@ public interface WebServiceMessage { * single time. * @return the message contents */ - Source getPayloadSource(); + @Nullable Source getPayloadSource(); /** * Returns the contents of the message as a {@link Result}. diff --git a/spring-ws-core/src/main/java/org/springframework/ws/client/WebServiceClientException.java b/spring-ws-core/src/main/java/org/springframework/ws/client/WebServiceClientException.java index 39a77bf5..dca9ea87 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/client/WebServiceClientException.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/client/WebServiceClientException.java @@ -16,6 +16,8 @@ package org.springframework.ws.client; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.WebServiceException; /** @@ -31,7 +33,7 @@ public abstract class WebServiceClientException extends WebServiceException { * Create a new instance of the {@code WebServiceClientException} class. * @param msg the detail message */ - public WebServiceClientException(String msg) { + public WebServiceClientException(@Nullable String msg) { super(msg); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/client/WebServiceFaultException.java b/spring-ws-core/src/main/java/org/springframework/ws/client/WebServiceFaultException.java index dcd14ed8..b079d345 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/client/WebServiceFaultException.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/client/WebServiceFaultException.java @@ -16,6 +16,8 @@ package org.springframework.ws.client; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.FaultAwareWebServiceMessage; /** @@ -27,7 +29,7 @@ import org.springframework.ws.FaultAwareWebServiceMessage; @SuppressWarnings("serial") public class WebServiceFaultException extends WebServiceClientException { - private final FaultAwareWebServiceMessage faultMessage; + private final @Nullable FaultAwareWebServiceMessage faultMessage; /** Create a new instance of the {@code WebServiceFaultException} class. */ public WebServiceFaultException(String msg) { @@ -45,7 +47,7 @@ public class WebServiceFaultException extends WebServiceClientException { } /** Returns the fault message. */ - public FaultAwareWebServiceMessage getWebServiceMessage() { + public @Nullable FaultAwareWebServiceMessage getWebServiceMessage() { return this.faultMessage; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/client/WebServiceIOException.java b/spring-ws-core/src/main/java/org/springframework/ws/client/WebServiceIOException.java index 5003d62e..eb29d66e 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/client/WebServiceIOException.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/client/WebServiceIOException.java @@ -18,6 +18,8 @@ package org.springframework.ws.client; import java.io.IOException; +import org.jspecify.annotations.Nullable; + /** * Exception thrown whenever an I/O error occurs on the client-side. * @@ -31,7 +33,7 @@ public class WebServiceIOException extends WebServiceClientException { * Create a new instance of the {@code WebServiceIOException} class. * @param msg the detail message */ - public WebServiceIOException(String msg) { + public WebServiceIOException(@Nullable String msg) { super(msg); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/client/WebServiceTransportException.java b/spring-ws-core/src/main/java/org/springframework/ws/client/WebServiceTransportException.java index 891d95de..297760aa 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/client/WebServiceTransportException.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/client/WebServiceTransportException.java @@ -16,6 +16,8 @@ package org.springframework.ws.client; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.transport.TransportException; /** @@ -31,7 +33,7 @@ public class WebServiceTransportException extends WebServiceIOException { * Create a new instance of the {@code WebServiceTransportException} class. * @param msg the detail message */ - public WebServiceTransportException(String msg) { + public WebServiceTransportException(@Nullable String msg) { super(msg); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/client/core/SourceExtractor.java b/spring-ws-core/src/main/java/org/springframework/ws/client/core/SourceExtractor.java index 9a6f4cc3..0c18fa9b 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/client/core/SourceExtractor.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/client/core/SourceExtractor.java @@ -21,6 +21,8 @@ import java.io.IOException; import javax.xml.transform.Source; import javax.xml.transform.TransformerException; +import org.jspecify.annotations.Nullable; + /** * Callback interface for extracting a result object from a * {@link javax.xml.transform.Source} instance. @@ -49,6 +51,6 @@ public interface SourceExtractor { * typically be stateful in the latter case) * @throws IOException in case of I/O errors */ - T extractData(Source source) throws IOException, TransformerException; + @Nullable T extractData(@Nullable Source source) throws IOException, TransformerException; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/client/core/WebServiceMessageExtractor.java b/spring-ws-core/src/main/java/org/springframework/ws/client/core/WebServiceMessageExtractor.java index 2a70f452..1a7feee1 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/client/core/WebServiceMessageExtractor.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/client/core/WebServiceMessageExtractor.java @@ -20,6 +20,8 @@ import java.io.IOException; import javax.xml.transform.TransformerException; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.WebServiceMessage; /** @@ -50,6 +52,6 @@ public interface WebServiceMessageExtractor { * @throws IOException in case of I/O errors * @throws TransformerException in case of transformation errors */ - T extractData(WebServiceMessage message) throws IOException, TransformerException; + @Nullable T extractData(WebServiceMessage message) throws IOException, TransformerException; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/client/core/WebServiceOperations.java b/spring-ws-core/src/main/java/org/springframework/ws/client/core/WebServiceOperations.java index bb51dcf2..946a16a3 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/client/core/WebServiceOperations.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/client/core/WebServiceOperations.java @@ -19,6 +19,8 @@ package org.springframework.ws.client.core; import javax.xml.transform.Result; import javax.xml.transform.Source; +import org.jspecify.annotations.Nullable; + import org.springframework.oxm.XmlMappingException; import org.springframework.ws.client.WebServiceClientException; @@ -46,8 +48,8 @@ public interface WebServiceOperations { * @throws WebServiceClientException if there is a problem sending or receiving the * message */ - T sendAndReceive(WebServiceMessageCallback requestCallback, WebServiceMessageExtractor responseExtractor) - throws WebServiceClientException; + @Nullable T sendAndReceive(WebServiceMessageCallback requestCallback, + WebServiceMessageExtractor responseExtractor) throws WebServiceClientException; /** * Sends a web service message that can be manipulated with the given callback, @@ -61,7 +63,7 @@ public interface WebServiceOperations { * @throws WebServiceClientException if there is a problem sending or receiving the * message */ - T sendAndReceive(String uri, WebServiceMessageCallback requestCallback, + @Nullable T sendAndReceive(String uri, WebServiceMessageCallback requestCallback, WebServiceMessageExtractor responseExtractor) throws WebServiceClientException; /** @@ -112,7 +114,7 @@ public interface WebServiceOperations { * @see WebServiceTemplate#setMarshaller(org.springframework.oxm.Marshaller) * @see WebServiceTemplate#setUnmarshaller(org.springframework.oxm.Unmarshaller) */ - Object marshalSendAndReceive(Object requestPayload) throws XmlMappingException, WebServiceClientException; + @Nullable Object marshalSendAndReceive(Object requestPayload) throws XmlMappingException, WebServiceClientException; /** * Sends a web service message that contains the given payload, marshalled by the @@ -128,7 +130,7 @@ public interface WebServiceOperations { * @see WebServiceTemplate#setMarshaller(org.springframework.oxm.Marshaller) * @see WebServiceTemplate#setUnmarshaller(org.springframework.oxm.Unmarshaller) */ - Object marshalSendAndReceive(String uri, Object requestPayload) + @Nullable Object marshalSendAndReceive(String uri, Object requestPayload) throws XmlMappingException, WebServiceClientException; /** @@ -148,7 +150,7 @@ public interface WebServiceOperations { * @see WebServiceTemplate#setMarshaller(org.springframework.oxm.Marshaller) * @see WebServiceTemplate#setUnmarshaller(org.springframework.oxm.Unmarshaller) */ - Object marshalSendAndReceive(Object requestPayload, WebServiceMessageCallback requestCallback) + @Nullable Object marshalSendAndReceive(Object requestPayload, @Nullable WebServiceMessageCallback requestCallback) throws XmlMappingException, WebServiceClientException; /** @@ -167,8 +169,8 @@ public interface WebServiceOperations { * @see WebServiceTemplate#setMarshaller(org.springframework.oxm.Marshaller) * @see WebServiceTemplate#setUnmarshaller(org.springframework.oxm.Unmarshaller) */ - Object marshalSendAndReceive(String uri, Object requestPayload, WebServiceMessageCallback requestCallback) - throws XmlMappingException, WebServiceClientException; + @Nullable Object marshalSendAndReceive(String uri, @Nullable Object requestPayload, + @Nullable WebServiceMessageCallback requestCallback) throws XmlMappingException, WebServiceClientException; // ----------------------------------------------------------------------------------------------------------------- // Convenience methods for sending Sources @@ -185,7 +187,7 @@ public interface WebServiceOperations { * @throws WebServiceClientException if there is a problem sending or receiving the * message */ - T sendSourceAndReceive(Source requestPayload, SourceExtractor responseExtractor) + @Nullable T sendSourceAndReceive(Source requestPayload, SourceExtractor responseExtractor) throws WebServiceClientException; /** @@ -198,7 +200,7 @@ public interface WebServiceOperations { * @throws WebServiceClientException if there is a problem sending or receiving the * message */ - T sendSourceAndReceive(String uri, Source requestPayload, SourceExtractor responseExtractor) + @Nullable T sendSourceAndReceive(String uri, Source requestPayload, SourceExtractor responseExtractor) throws WebServiceClientException; /** @@ -216,7 +218,7 @@ public interface WebServiceOperations { * @throws WebServiceClientException if there is a problem sending or receiving the * message */ - T sendSourceAndReceive(Source requestPayload, WebServiceMessageCallback requestCallback, + @Nullable T sendSourceAndReceive(Source requestPayload, WebServiceMessageCallback requestCallback, SourceExtractor responseExtractor) throws WebServiceClientException; /** @@ -233,8 +235,9 @@ public interface WebServiceOperations { * @throws WebServiceClientException if there is a problem sending or receiving the * message */ - T sendSourceAndReceive(String uri, Source requestPayload, WebServiceMessageCallback requestCallback, - SourceExtractor responseExtractor) throws WebServiceClientException; + @Nullable T sendSourceAndReceive(String uri, Source requestPayload, + @Nullable WebServiceMessageCallback requestCallback, SourceExtractor responseExtractor) + throws WebServiceClientException; // ----------------------------------------------------------------------------------------------------------------- // Convenience methods for sending Sources and receiving to Results diff --git a/spring-ws-core/src/main/java/org/springframework/ws/client/core/WebServiceTemplate.java b/spring-ws-core/src/main/java/org/springframework/ws/client/core/WebServiceTemplate.java index 29c0f996..cb4928c1 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/client/core/WebServiceTemplate.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/client/core/WebServiceTemplate.java @@ -30,6 +30,7 @@ import javax.xml.transform.TransformerException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.beans.factory.BeanInitializationException; import org.springframework.oxm.Marshaller; @@ -133,19 +134,19 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService protected static final Log receivedMessageTracingLogger = LogFactory .getLog(WebServiceTemplate.MESSAGE_TRACING_LOG_CATEGORY + ".received"); - private Marshaller marshaller; + private @Nullable Marshaller marshaller; - private Unmarshaller unmarshaller; + private @Nullable Unmarshaller unmarshaller; - private FaultMessageResolver faultMessageResolver; + private @Nullable FaultMessageResolver faultMessageResolver; private boolean checkConnectionForError = true; private boolean checkConnectionForFault = true; - private ClientInterceptor[] interceptors; + private ClientInterceptor @Nullable [] interceptors; - private DestinationProvider destinationProvider; + private @Nullable DestinationProvider destinationProvider; /** Creates a new {@code WebServiceTemplate} using default settings. */ public WebServiceTemplate() { @@ -205,7 +206,7 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService /** * Returns the default URI to be used on operations that do not have a URI parameter. */ - public String getDefaultUri() { + public @Nullable String getDefaultUri() { if (this.destinationProvider != null) { URI uri = this.destinationProvider.getDestination(); return (uri != null) ? uri.toString() : null; @@ -241,7 +242,7 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService * Returns the destination provider used on operations that do not have a URI * parameter. */ - public DestinationProvider getDestinationProvider() { + public @Nullable DestinationProvider getDestinationProvider() { return this.destinationProvider; } @@ -264,7 +265,7 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService } /** Returns the marshaller for this template. */ - public Marshaller getMarshaller() { + public @Nullable Marshaller getMarshaller() { return this.marshaller; } @@ -274,7 +275,7 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService } /** Returns the unmarshaller for this template. */ - public Unmarshaller getUnmarshaller() { + public @Nullable Unmarshaller getUnmarshaller() { return this.unmarshaller; } @@ -284,7 +285,7 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService } /** Returns the fault message resolver for this template. */ - public FaultMessageResolver getFaultMessageResolver() { + public @Nullable FaultMessageResolver getFaultMessageResolver() { return this.faultMessageResolver; } @@ -346,7 +347,7 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService * this template. * @return array of endpoint interceptors, or {@code null} if none */ - public ClientInterceptor[] getInterceptors() { + public ClientInterceptor @Nullable [] getInterceptors() { return this.interceptors; } @@ -402,23 +403,26 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService // @Override - public Object marshalSendAndReceive(final Object requestPayload) { + public @Nullable Object marshalSendAndReceive(final Object requestPayload) { return marshalSendAndReceive(requestPayload, null); } @Override - public Object marshalSendAndReceive(String uri, final Object requestPayload) { + public @Nullable Object marshalSendAndReceive(String uri, final Object requestPayload) { return marshalSendAndReceive(uri, requestPayload, null); } @Override - public Object marshalSendAndReceive(final Object requestPayload, final WebServiceMessageCallback requestCallback) { - return marshalSendAndReceive(getDefaultUri(), requestPayload, requestCallback); + public @Nullable Object marshalSendAndReceive(final Object requestPayload, + final @Nullable WebServiceMessageCallback requestCallback) { + String defaultUri = getDefaultUri(); + Assert.notNull(defaultUri, "'defaultUri' must not be null"); + return marshalSendAndReceive(defaultUri, requestPayload, requestCallback); } @Override - public Object marshalSendAndReceive(String uri, final Object requestPayload, - final WebServiceMessageCallback requestCallback) { + public @Nullable Object marshalSendAndReceive(String uri, final @Nullable Object requestPayload, + final @Nullable WebServiceMessageCallback requestCallback) { return sendAndReceive(uri, new WebServiceMessageCallback() { public void doWithMessage(WebServiceMessage request) throws IOException, TransformerException { @@ -436,7 +440,7 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService } }, new WebServiceMessageExtractor<>() { - public Object extractData(WebServiceMessage response) throws IOException { + public @Nullable Object extractData(WebServiceMessage response) throws IOException { Unmarshaller unmarshaller = getUnmarshaller(); if (unmarshaller == null) { throw new IllegalStateException( @@ -462,20 +466,22 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService } @Override - public boolean sendSourceAndReceiveToResult(Source requestPayload, WebServiceMessageCallback requestCallback, - final Result responseResult) { - return sendSourceAndReceiveToResult(getDefaultUri(), requestPayload, requestCallback, responseResult); + public boolean sendSourceAndReceiveToResult(Source requestPayload, + @Nullable WebServiceMessageCallback requestCallback, final Result responseResult) { + String defaultUri = getDefaultUri(); + Assert.notNull(defaultUri, "'defaultUri' must not be null"); + return sendSourceAndReceiveToResult(defaultUri, requestPayload, requestCallback, responseResult); } @Override public boolean sendSourceAndReceiveToResult(String uri, Source requestPayload, - WebServiceMessageCallback requestCallback, final Result responseResult) { + @Nullable WebServiceMessageCallback requestCallback, final Result responseResult) { try { final Transformer transformer = createTransformer(); Boolean retVal = doSendAndReceive(uri, transformer, requestPayload, requestCallback, new SourceExtractor<>() { - public Boolean extractData(Source source) throws IOException, TransformerException { + public Boolean extractData(@Nullable Source source) throws IOException, TransformerException { if (source != null) { transformer.transform(source, responseResult); } @@ -494,25 +500,28 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService // @Override - public T sendSourceAndReceive(final Source requestPayload, final SourceExtractor responseExtractor) { + public @Nullable T sendSourceAndReceive(final Source requestPayload, + final SourceExtractor responseExtractor) { return sendSourceAndReceive(requestPayload, null, responseExtractor); } @Override - public T sendSourceAndReceive(String uri, final Source requestPayload, + public @Nullable T sendSourceAndReceive(String uri, final Source requestPayload, final SourceExtractor responseExtractor) { return sendSourceAndReceive(uri, requestPayload, null, responseExtractor); } @Override - public T sendSourceAndReceive(final Source requestPayload, final WebServiceMessageCallback requestCallback, - final SourceExtractor responseExtractor) { - return sendSourceAndReceive(getDefaultUri(), requestPayload, requestCallback, responseExtractor); + public @Nullable T sendSourceAndReceive(final Source requestPayload, + final @Nullable WebServiceMessageCallback requestCallback, final SourceExtractor responseExtractor) { + String defaultUri = getDefaultUri(); + Assert.notNull(defaultUri, "'defaultUri' must not be null"); + return sendSourceAndReceive(defaultUri, requestPayload, requestCallback, responseExtractor); } @Override - public T sendSourceAndReceive(String uri, final Source requestPayload, - final WebServiceMessageCallback requestCallback, final SourceExtractor responseExtractor) { + public @Nullable T sendSourceAndReceive(String uri, final Source requestPayload, + final @Nullable WebServiceMessageCallback requestCallback, final SourceExtractor responseExtractor) { try { return doSendAndReceive(uri, createTransformer(), requestPayload, requestCallback, responseExtractor); @@ -522,8 +531,8 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService } } - private T doSendAndReceive(String uri, final Transformer transformer, final Source requestPayload, - final WebServiceMessageCallback requestCallback, final SourceExtractor responseExtractor) { + private @Nullable T doSendAndReceive(String uri, final Transformer transformer, final Source requestPayload, + final @Nullable WebServiceMessageCallback requestCallback, final SourceExtractor responseExtractor) { Assert.notNull(responseExtractor, "responseExtractor must not be null"); return sendAndReceive(uri, new WebServiceMessageCallback() { public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException { @@ -542,7 +551,9 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService @Override public boolean sendAndReceive(WebServiceMessageCallback requestCallback, WebServiceMessageCallback responseCallback) { - return sendAndReceive(getDefaultUri(), requestCallback, responseCallback); + String defaultUri = getDefaultUri(); + Assert.notNull(defaultUri, "'defaultUri' must not be null"); + return sendAndReceive(defaultUri, requestCallback, responseCallback); } @Override @@ -555,13 +566,15 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService } @Override - public T sendAndReceive(WebServiceMessageCallback requestCallback, + public @Nullable T sendAndReceive(WebServiceMessageCallback requestCallback, WebServiceMessageExtractor responseExtractor) { - return sendAndReceive(getDefaultUri(), requestCallback, responseExtractor); + String defaultUri = getDefaultUri(); + Assert.notNull(defaultUri, "'defaultUri' must not be null"); + return sendAndReceive(defaultUri, requestCallback, responseExtractor); } @Override - public T sendAndReceive(String uriString, WebServiceMessageCallback requestCallback, + public @Nullable T sendAndReceive(String uriString, WebServiceMessageCallback requestCallback, WebServiceMessageExtractor responseExtractor) { Assert.notNull(responseExtractor, "'responseExtractor' must not be null"); Assert.hasLength(uriString, "'uri' must not be empty"); @@ -581,7 +594,9 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService throw new WebServiceIOException("I/O error: " + ex.getMessage(), ex); } finally { - TransportUtils.closeConnection(connection); + if (connection != null) { + TransportUtils.closeConnection(connection); + } TransportContextHolder.setTransportContext(previousTransportContext); } } @@ -603,8 +618,8 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService * @throws IOException in case of I/O errors */ @SuppressWarnings("unchecked") - protected T doSendAndReceive(MessageContext messageContext, WebServiceConnection connection, - WebServiceMessageCallback requestCallback, WebServiceMessageExtractor responseExtractor) + protected @Nullable T doSendAndReceive(MessageContext messageContext, WebServiceConnection connection, + @Nullable WebServiceMessageCallback requestCallback, WebServiceMessageExtractor responseExtractor) throws IOException { int interceptorIndex = -1; try { @@ -819,7 +834,7 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService * @param ex exception thrown on handler execution, or {@code null} if none * @see ClientInterceptor#afterCompletion */ - private void triggerAfterCompletion(int interceptorIndex, MessageContext messageContext, Exception ex) + private void triggerAfterCompletion(int interceptorIndex, MessageContext messageContext, @Nullable Exception ex) throws WebServiceClientException { if (this.interceptors != null) { for (int i = interceptorIndex; i >= 0; i--) { @@ -843,7 +858,8 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService * {@link #sendAndReceive(String,WebServiceMessageCallback, WebServiceMessageExtractor)}, * if any */ - protected Object handleFault(WebServiceConnection connection, MessageContext messageContext) throws IOException { + protected @Nullable Object handleFault(WebServiceConnection connection, MessageContext messageContext) + throws IOException { if (this.logger.isDebugEnabled()) { this.logger.debug("Received Fault message for request [" + messageContext.getRequest() + "]"); } @@ -887,7 +903,7 @@ public class WebServiceTemplate extends WebServiceAccessor implements WebService } @Override - public T extractData(WebServiceMessage message) throws IOException, TransformerException { + public @Nullable T extractData(WebServiceMessage message) throws IOException, TransformerException { return this.sourceExtractor.extractData(message.getPayloadSource()); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/client/core/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/client/core/package-info.java index db6f8122..a44a049d 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/client/core/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/client/core/package-info.java @@ -18,4 +18,7 @@ * Core package of the Spring-WS client-side support. Provides a WebServiceTemplate class * and various callback interfaces. */ +@NullMarked package org.springframework.ws.client.core; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/client/core/support/WebServiceGatewaySupport.java b/spring-ws-core/src/main/java/org/springframework/ws/client/core/support/WebServiceGatewaySupport.java index f8fa0a37..33e7ead7 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/client/core/support/WebServiceGatewaySupport.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/client/core/support/WebServiceGatewaySupport.java @@ -18,6 +18,7 @@ package org.springframework.ws.client.core.support; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.beans.factory.InitializingBean; import org.springframework.oxm.Marshaller; @@ -90,7 +91,7 @@ public abstract class WebServiceGatewaySupport implements InitializingBean { } /** Returns the default URI used by the gateway. */ - public final String getDefaultUri() { + public final @Nullable String getDefaultUri() { return this.webServiceTemplate.getDefaultUri(); } @@ -100,7 +101,7 @@ public abstract class WebServiceGatewaySupport implements InitializingBean { } /** Returns the destination provider used by the gateway. */ - public final DestinationProvider getDestinationProvider() { + public final @Nullable DestinationProvider getDestinationProvider() { return this.webServiceTemplate.getDestinationProvider(); } @@ -145,7 +146,7 @@ public abstract class WebServiceGatewaySupport implements InitializingBean { } /** Returns the {@code Marshaller} used by the gateway. */ - public final Marshaller getMarshaller() { + public final @Nullable Marshaller getMarshaller() { return this.webServiceTemplate.getMarshaller(); } @@ -160,7 +161,7 @@ public abstract class WebServiceGatewaySupport implements InitializingBean { } /** Returns the {@code Unmarshaller} used by the gateway. */ - public final Unmarshaller getUnmarshaller() { + public final @Nullable Unmarshaller getUnmarshaller() { return this.webServiceTemplate.getUnmarshaller(); } @@ -175,7 +176,7 @@ public abstract class WebServiceGatewaySupport implements InitializingBean { } /** Returns the {@code ClientInterceptors} used by the template. */ - public final ClientInterceptor[] getInterceptors() { + public final ClientInterceptor @Nullable [] getInterceptors() { return this.webServiceTemplate.getInterceptors(); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/client/core/support/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/client/core/support/package-info.java index 91451b8a..d8509d67 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/client/core/support/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/client/core/support/package-info.java @@ -18,4 +18,7 @@ * Convenient super class for application classes that need Web service access. Contains a * base class for WebServiceTemplate usage. */ +@NullMarked package org.springframework.ws.client.core.support; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/client/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/client/package-info.java index 71d7c5af..3bec2e36 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/client/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/client/package-info.java @@ -18,4 +18,7 @@ * Contains classes for client-side Spring-WS support, allowing for Spring-style Web * service access. */ +@NullMarked package org.springframework.ws.client; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/client/support/WebServiceAccessor.java b/spring-ws-core/src/main/java/org/springframework/ws/client/support/WebServiceAccessor.java index dc3883dd..0bf6327c 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/client/support/WebServiceAccessor.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/client/support/WebServiceAccessor.java @@ -41,8 +41,10 @@ import org.springframework.xml.transform.TransformerObjectSupport; */ public abstract class WebServiceAccessor extends TransformerObjectSupport implements InitializingBean { + @SuppressWarnings("NullAway.Init") private WebServiceMessageFactory messageFactory; + @SuppressWarnings("NullAway.Init") private WebServiceMessageSender[] messageSenders; /** Returns the message factory used for creating messages. */ diff --git a/spring-ws-core/src/main/java/org/springframework/ws/client/support/destination/AbstractCachingDestinationProvider.java b/spring-ws-core/src/main/java/org/springframework/ws/client/support/destination/AbstractCachingDestinationProvider.java index 0de3d113..a034a28d 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/client/support/destination/AbstractCachingDestinationProvider.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/client/support/destination/AbstractCachingDestinationProvider.java @@ -20,6 +20,7 @@ import java.net.URI; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; /** * Abstract base class for {@link DestinationProvider} implementations that cache @@ -36,7 +37,7 @@ public abstract class AbstractCachingDestinationProvider implements DestinationP /** Logger available to subclasses. */ protected final Log logger = LogFactory.getLog(getClass()); - private URI cachedUri; + private @Nullable URI cachedUri; private boolean cache = true; @@ -50,7 +51,7 @@ public abstract class AbstractCachingDestinationProvider implements DestinationP } @Override - public final URI getDestination() { + public final @Nullable URI getDestination() { if (this.cache) { if (this.cachedUri == null) { this.cachedUri = lookupDestination(); @@ -69,6 +70,6 @@ public abstract class AbstractCachingDestinationProvider implements DestinationP * called once. * @return the destination URI */ - protected abstract URI lookupDestination(); + protected abstract @Nullable URI lookupDestination(); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/client/support/destination/DestinationProvider.java b/spring-ws-core/src/main/java/org/springframework/ws/client/support/destination/DestinationProvider.java index dcb69dd0..a626fd50 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/client/support/destination/DestinationProvider.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/client/support/destination/DestinationProvider.java @@ -18,6 +18,8 @@ package org.springframework.ws.client.support.destination; import java.net.URI; +import org.jspecify.annotations.Nullable; + /** * Strategy interface for providing a * {@link org.springframework.ws.client.core.WebServiceTemplate} destination URI at @@ -36,6 +38,6 @@ public interface DestinationProvider { * Return the destination URI. * @return the destination URI */ - URI getDestination(); + @Nullable URI getDestination(); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/client/support/destination/Wsdl11DestinationProvider.java b/spring-ws-core/src/main/java/org/springframework/ws/client/support/destination/Wsdl11DestinationProvider.java index 4660cd4f..91486fe0 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/client/support/destination/Wsdl11DestinationProvider.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/client/support/destination/Wsdl11DestinationProvider.java @@ -26,6 +26,7 @@ import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMResult; +import org.jspecify.annotations.Nullable; import org.w3c.dom.Document; import org.springframework.core.io.Resource; @@ -64,7 +65,7 @@ public class Wsdl11DestinationProvider extends AbstractCachingDestinationProvide private XPathExpression locationXPathExpression; - private Resource wsdlResource; + private @Nullable Resource wsdlResource; public Wsdl11DestinationProvider() { this.expressionNamespaces.put("wsdl", "http://schemas.xmlsoap.org/wsdl/"); @@ -120,7 +121,8 @@ public class Wsdl11DestinationProvider extends AbstractCachingDestinationProvide } @Override - protected URI lookupDestination() { + protected @Nullable URI lookupDestination() { + Assert.notNull(this.wsdlResource, "'wsdlResource' must not be null"); try { DOMResult result = new DOMResult(); Transformer transformer = transformerFactory.newTransformer(); diff --git a/spring-ws-core/src/main/java/org/springframework/ws/client/support/destination/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/client/support/destination/package-info.java index 512eae58..7a521316 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/client/support/destination/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/client/support/destination/package-info.java @@ -17,4 +17,7 @@ /** * Provides the {@code DestinationProvider} interface. */ +@NullMarked package org.springframework.ws.client.support.destination; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/client/support/interceptor/AbstractValidatingInterceptor.java b/spring-ws-core/src/main/java/org/springframework/ws/client/support/interceptor/AbstractValidatingInterceptor.java index 60f71f29..36100744 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/client/support/interceptor/AbstractValidatingInterceptor.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/client/support/interceptor/AbstractValidatingInterceptor.java @@ -20,6 +20,7 @@ import java.io.IOException; import javax.xml.transform.Source; +import org.jspecify.annotations.Nullable; import org.xml.sax.SAXParseException; import org.springframework.beans.factory.InitializingBean; @@ -56,12 +57,14 @@ public abstract class AbstractValidatingInterceptor extends TransformerObjectSup private String schemaLanguage = XmlValidatorFactory.SCHEMA_W3C_XML; + @SuppressWarnings("NullAway.Init") private Resource[] schemas; private boolean validateRequest = true; private boolean validateResponse = false; + @SuppressWarnings("NullAway.Init") private XmlValidator validator; public String getSchemaLanguage() { @@ -275,7 +278,8 @@ public abstract class AbstractValidatingInterceptor extends TransformerObjectSup /** Does nothing by default. */ @Override - public void afterCompletion(MessageContext messageContext, Exception ex) throws WebServiceClientException { + public void afterCompletion(MessageContext messageContext, @Nullable Exception ex) + throws WebServiceClientException { } /** @@ -285,7 +289,7 @@ public abstract class AbstractValidatingInterceptor extends TransformerObjectSup * @return the part of the message that is to validated, or {@code null} not to * validate anything */ - protected abstract Source getValidationRequestSource(WebServiceMessage request); + protected abstract @Nullable Source getValidationRequestSource(WebServiceMessage request); /** * Abstract template method that returns the part of the response message that is to @@ -294,6 +298,6 @@ public abstract class AbstractValidatingInterceptor extends TransformerObjectSup * @return the part of the message that is to validated, or {@code null} not to * validate anything */ - protected abstract Source getValidationResponseSource(WebServiceMessage response); + protected abstract @Nullable Source getValidationResponseSource(WebServiceMessage response); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/client/support/interceptor/ClientInterceptor.java b/spring-ws-core/src/main/java/org/springframework/ws/client/support/interceptor/ClientInterceptor.java index 77648a64..4e1532b4 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/client/support/interceptor/ClientInterceptor.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/client/support/interceptor/ClientInterceptor.java @@ -16,6 +16,8 @@ package org.springframework.ws.client.support.interceptor; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.client.WebServiceClientException; import org.springframework.ws.context.MessageContext; import org.springframework.ws.soap.SoapHeader; @@ -102,6 +104,6 @@ public interface ClientInterceptor { * @throws WebServiceClientException in case of errors * @since 2.2 */ - void afterCompletion(MessageContext messageContext, Exception ex) throws WebServiceClientException; + void afterCompletion(MessageContext messageContext, @Nullable Exception ex) throws WebServiceClientException; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/client/support/interceptor/ClientInterceptorAdapter.java b/spring-ws-core/src/main/java/org/springframework/ws/client/support/interceptor/ClientInterceptorAdapter.java index 3ed06cf1..c0cb2a45 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/client/support/interceptor/ClientInterceptorAdapter.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/client/support/interceptor/ClientInterceptorAdapter.java @@ -18,6 +18,7 @@ package org.springframework.ws.client.support.interceptor; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.ws.client.WebServiceClientException; import org.springframework.ws.context.MessageContext; @@ -55,7 +56,8 @@ public abstract class ClientInterceptorAdapter implements ClientInterceptor { * Does nothing by default. */ @Override - public void afterCompletion(MessageContext messageContext, Exception ex) throws WebServiceClientException { + public void afterCompletion(MessageContext messageContext, @Nullable Exception ex) + throws WebServiceClientException { } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/client/support/interceptor/PayloadValidatingInterceptor.java b/spring-ws-core/src/main/java/org/springframework/ws/client/support/interceptor/PayloadValidatingInterceptor.java index f909c890..a96788c3 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/client/support/interceptor/PayloadValidatingInterceptor.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/client/support/interceptor/PayloadValidatingInterceptor.java @@ -18,6 +18,8 @@ package org.springframework.ws.client.support.interceptor; import javax.xml.transform.Source; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.WebServiceMessage; /** @@ -49,7 +51,7 @@ public class PayloadValidatingInterceptor extends AbstractValidatingInterceptor * validate anything */ @Override - protected Source getValidationRequestSource(WebServiceMessage request) { + protected @Nullable Source getValidationRequestSource(WebServiceMessage request) { return request.getPayloadSource(); } @@ -60,7 +62,7 @@ public class PayloadValidatingInterceptor extends AbstractValidatingInterceptor * validate anything */ @Override - protected Source getValidationResponseSource(WebServiceMessage response) { + protected @Nullable Source getValidationResponseSource(WebServiceMessage response) { return response.getPayloadSource(); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/client/support/interceptor/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/client/support/interceptor/package-info.java index 4e41ed0d..1f8c2c15 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/client/support/interceptor/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/client/support/interceptor/package-info.java @@ -17,4 +17,7 @@ /** * Provides the {@code ClientInterceptor} interface, and validating interceptors. */ +@NullMarked package org.springframework.ws.client.support.interceptor; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/client/support/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/client/support/package-info.java index b3e998ad..c61c19f1 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/client/support/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/client/support/package-info.java @@ -18,4 +18,7 @@ * Classes supporting the org.springframework.ws.client.core package. Contains a base * class for WebServiceTemplate usage. */ +@NullMarked package org.springframework.ws.client.support; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/config/AnnotationDrivenBeanDefinitionParser.java b/spring-ws-core/src/main/java/org/springframework/ws/config/AnnotationDrivenBeanDefinitionParser.java index 4e51b716..efbeb98b 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/config/AnnotationDrivenBeanDefinitionParser.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/config/AnnotationDrivenBeanDefinitionParser.java @@ -16,6 +16,7 @@ package org.springframework.ws.config; +import org.jspecify.annotations.Nullable; import org.w3c.dom.Element; import org.springframework.beans.BeanMetadataElement; @@ -74,24 +75,24 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser { AnnotationDrivenBeanDefinitionParser.class.getClassLoader()); @Override - public BeanDefinition parse(Element element, ParserContext parserContext) { + public @Nullable BeanDefinition parse(Element element, ParserContext parserContext) { Object source = parserContext.extractSource(element); CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source); parserContext.pushContainingComponent(compDefinition); - registerEndpointMappings(source, parserContext); + registerEndpointMappings(parserContext, source); - registerEndpointAdapters(element, source, parserContext); + registerEndpointAdapters(parserContext, element, source); - registerEndpointExceptionResolvers(source, parserContext); + registerEndpointExceptionResolvers(parserContext, source); parserContext.popAndRegisterContainingComponent(); return null; } - private void registerEndpointMappings(Object source, ParserContext parserContext) { + private void registerEndpointMappings(ParserContext parserContext, @Nullable Object source) { RootBeanDefinition payloadRootMappingDef = createBeanDefinition( PayloadRootAnnotationMethodEndpointMapping.class, source); payloadRootMappingDef.getPropertyValues().add("order", 0); @@ -107,7 +108,7 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser { parserContext.getReaderContext().registerWithGeneratedName(annActionMappingDef); } - private void registerEndpointAdapters(Element element, Object source, ParserContext parserContext) { + private void registerEndpointAdapters(ParserContext parserContext, Element element, @Nullable Object source) { RootBeanDefinition adapterDef = createBeanDefinition(DefaultMethodEndpointAdapter.class, source); ManagedList argumentResolvers = new ManagedList<>(); @@ -121,35 +122,35 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser { argumentResolvers.add(createBeanDefinition(SoapMethodArgumentResolver.class, source)); argumentResolvers.add(createBeanDefinition(SoapHeaderElementMethodArgumentResolver.class, source)); - RuntimeBeanReference domProcessor = createBeanReference(DomPayloadMethodProcessor.class, source, parserContext); + RuntimeBeanReference domProcessor = createBeanReference(parserContext, DomPayloadMethodProcessor.class, source); argumentResolvers.add(domProcessor); returnValueHandlers.add(domProcessor); - RuntimeBeanReference sourceProcessor = createBeanReference(SourcePayloadMethodProcessor.class, source, - parserContext); + RuntimeBeanReference sourceProcessor = createBeanReference(parserContext, SourcePayloadMethodProcessor.class, + source); argumentResolvers.add(sourceProcessor); returnValueHandlers.add(sourceProcessor); if (dom4jPresent) { - RuntimeBeanReference dom4jProcessor = createBeanReference(Dom4jPayloadMethodProcessor.class, source, - parserContext); + RuntimeBeanReference dom4jProcessor = createBeanReference(parserContext, Dom4jPayloadMethodProcessor.class, + source); argumentResolvers.add(dom4jProcessor); returnValueHandlers.add(dom4jProcessor); } if (jaxb2Present) { - RuntimeBeanReference xmlRootElementProcessor = createBeanReference( - XmlRootElementPayloadMethodProcessor.class, source, parserContext); + RuntimeBeanReference xmlRootElementProcessor = createBeanReference(parserContext, + XmlRootElementPayloadMethodProcessor.class, source); argumentResolvers.add(xmlRootElementProcessor); returnValueHandlers.add(xmlRootElementProcessor); - RuntimeBeanReference jaxbElementProcessor = createBeanReference(JaxbElementPayloadMethodProcessor.class, - source, parserContext); + RuntimeBeanReference jaxbElementProcessor = createBeanReference(parserContext, + JaxbElementPayloadMethodProcessor.class, source); argumentResolvers.add(jaxbElementProcessor); returnValueHandlers.add(jaxbElementProcessor); } if (jdomPresent) { - RuntimeBeanReference jdomProcessor = createBeanReference(JDomPayloadMethodProcessor.class, source, - parserContext); + RuntimeBeanReference jdomProcessor = createBeanReference(parserContext, JDomPayloadMethodProcessor.class, + source); argumentResolvers.add(jdomProcessor); returnValueHandlers.add(jdomProcessor); } @@ -157,8 +158,8 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser { argumentResolvers.add(createBeanDefinition(StaxPayloadMethodArgumentResolver.class, source)); } if (xomPresent) { - RuntimeBeanReference xomProcessor = createBeanReference(XomPayloadMethodProcessor.class, source, - parserContext); + RuntimeBeanReference xomProcessor = createBeanReference(parserContext, XomPayloadMethodProcessor.class, + source); argumentResolvers.add(xomProcessor); returnValueHandlers.add(xomProcessor); } @@ -186,7 +187,7 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser { parserContext.getReaderContext().registerWithGeneratedName(adapterDef); } - private void registerEndpointExceptionResolvers(Object source, ParserContext parserContext) { + private void registerEndpointExceptionResolvers(ParserContext parserContext, @Nullable Object source) { RootBeanDefinition annotationResolverDef = createBeanDefinition(SoapFaultAnnotationExceptionResolver.class, source); annotationResolverDef.getPropertyValues().add("order", 0); @@ -197,14 +198,15 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser { parserContext.getReaderContext().registerWithGeneratedName(simpleResolverDef); } - private RuntimeBeanReference createBeanReference(Class beanClass, Object source, ParserContext parserContext) { + private RuntimeBeanReference createBeanReference(ParserContext parserContext, Class beanClass, + @Nullable Object source) { RootBeanDefinition beanDefinition = createBeanDefinition(beanClass, source); String beanName = parserContext.getReaderContext().registerWithGeneratedName(beanDefinition); parserContext.registerComponent(new BeanComponentDefinition(beanDefinition, beanName)); return new RuntimeBeanReference(beanName); } - private RootBeanDefinition createBeanDefinition(Class beanClass, Object source) { + private RootBeanDefinition createBeanDefinition(Class beanClass, @Nullable Object source) { RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass); beanDefinition.setSource(source); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); diff --git a/spring-ws-core/src/main/java/org/springframework/ws/config/DynamicWsdlBeanDefinitionParser.java b/spring-ws-core/src/main/java/org/springframework/ws/config/DynamicWsdlBeanDefinitionParser.java index 769dcd7e..fde19019 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/config/DynamicWsdlBeanDefinitionParser.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/config/DynamicWsdlBeanDefinitionParser.java @@ -18,6 +18,7 @@ package org.springframework.ws.config; import java.util.List; +import org.jspecify.annotations.Nullable; import org.w3c.dom.Element; import org.springframework.beans.factory.config.BeanDefinition; @@ -98,7 +99,7 @@ class DynamicWsdlBeanDefinitionParser extends AbstractBeanDefinitionParser { } } - private RootBeanDefinition createBeanDefinition(Class beanClass, Object source) { + private RootBeanDefinition createBeanDefinition(Class beanClass, @Nullable Object source) { RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass); beanDefinition.setSource(source); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); diff --git a/spring-ws-core/src/main/java/org/springframework/ws/config/InterceptorsBeanDefinitionParser.java b/spring-ws-core/src/main/java/org/springframework/ws/config/InterceptorsBeanDefinitionParser.java index 0f34c7a8..21d107ce 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/config/InterceptorsBeanDefinitionParser.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/config/InterceptorsBeanDefinitionParser.java @@ -18,6 +18,7 @@ package org.springframework.ws.config; import java.util.List; +import org.jspecify.annotations.Nullable; import org.w3c.dom.Element; import org.springframework.beans.factory.config.BeanDefinition; @@ -29,6 +30,7 @@ import org.springframework.beans.factory.parsing.CompositeComponentDefinition; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.util.xml.DomUtils; import org.springframework.ws.server.SmartEndpointInterceptor; @@ -45,7 +47,7 @@ import org.springframework.ws.soap.server.endpoint.interceptor.SoapActionSmartEn class InterceptorsBeanDefinitionParser implements BeanDefinitionParser { @Override - public BeanDefinition parse(Element element, ParserContext parserContext) { + public @Nullable BeanDefinition parse(Element element, ParserContext parserContext) { CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element)); parserContext.pushContainingComponent(compDefinition); @@ -149,11 +151,12 @@ class InterceptorsBeanDefinitionParser implements BeanDefinitionParser { private BeanDefinitionHolder createInterceptorDefinition(ParserContext parserContext, Element element) { BeanDefinitionHolder interceptorDef = parserContext.getDelegate().parseBeanDefinitionElement(element); + Assert.notNull(interceptorDef, "No interceptor definition found for element [" + element + "]"); interceptorDef = parserContext.getDelegate().decorateBeanDefinitionIfRequired(element, interceptorDef); return interceptorDef; } - private BeanReference createInterceptorReference(ParserContext parserContext, Element element) { + private @Nullable BeanReference createInterceptorReference(ParserContext parserContext, Element element) { // A generic reference to any name of any bean. String refName = element.getAttribute("bean"); if (!StringUtils.hasLength(refName)) { diff --git a/spring-ws-core/src/main/java/org/springframework/ws/config/annotation/WsConfigurationSupport.java b/spring-ws-core/src/main/java/org/springframework/ws/config/annotation/WsConfigurationSupport.java index 3861b800..97fd686b 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/config/annotation/WsConfigurationSupport.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/config/annotation/WsConfigurationSupport.java @@ -20,6 +20,8 @@ import java.util.ArrayList; import java.util.LinkedList; import java.util.List; +import org.jspecify.annotations.Nullable; + import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; @@ -79,7 +81,7 @@ import org.springframework.ws.soap.server.endpoint.mapping.SoapActionAnnotationM */ public class WsConfigurationSupport { - private List interceptors; + private @Nullable List interceptors; /** * Returns a {@link PayloadRootAnnotationMethodEndpointMapping} ordered at 0 for diff --git a/spring-ws-core/src/main/java/org/springframework/ws/config/annotation/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/config/annotation/package-info.java index 45416085..5d39ed9a 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/config/annotation/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/config/annotation/package-info.java @@ -17,4 +17,7 @@ /** * Annotations and supporting classes for declarative configuration. */ +@NullMarked package org.springframework.ws.config.annotation; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/config/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/config/package-info.java index 41d8c3da..d0a544c5 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/config/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/config/package-info.java @@ -17,4 +17,7 @@ /** * Provide a namespace handler for the Spring Web Services namespace. */ +@NullMarked package org.springframework.ws.config; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/context/AbstractMessageContext.java b/spring-ws-core/src/main/java/org/springframework/ws/context/AbstractMessageContext.java index 704c4c25..70ee0ab8 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/context/AbstractMessageContext.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/context/AbstractMessageContext.java @@ -19,6 +19,8 @@ package org.springframework.ws.context; import java.util.HashMap; import java.util.Map; +import org.jspecify.annotations.Nullable; + import org.springframework.util.StringUtils; /** @@ -33,7 +35,7 @@ public abstract class AbstractMessageContext implements MessageContext { * Keys are {@code Strings}, values are {@code Objects}. Lazily initialized by * {@code getProperties()}. */ - private Map properties; + private @Nullable Map properties; @Override public boolean containsProperty(String name) { @@ -41,7 +43,7 @@ public abstract class AbstractMessageContext implements MessageContext { } @Override - public Object getProperty(String name) { + public @Nullable Object getProperty(String name) { return getProperties().get(name); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/context/DefaultMessageContext.java b/spring-ws-core/src/main/java/org/springframework/ws/context/DefaultMessageContext.java index 3c3dfab5..3b27e187 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/context/DefaultMessageContext.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/context/DefaultMessageContext.java @@ -19,6 +19,8 @@ package org.springframework.ws.context; import java.io.IOException; import java.io.InputStream; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; import org.springframework.ws.WebServiceMessage; import org.springframework.ws.WebServiceMessageFactory; @@ -35,7 +37,7 @@ public class DefaultMessageContext extends AbstractMessageContext { private final WebServiceMessage request; - private WebServiceMessage response; + private @Nullable WebServiceMessage response; /** * Construct a new, empty instance of the {@code DefaultMessageContext} with the given @@ -75,7 +77,7 @@ public class DefaultMessageContext extends AbstractMessageContext { } @Override - public void setResponse(WebServiceMessage response) { + public void setResponse(@Nullable WebServiceMessage response) { checkForResponse(); this.response = response; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/context/MessageContext.java b/spring-ws-core/src/main/java/org/springframework/ws/context/MessageContext.java index ce506a30..505a72bc 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/context/MessageContext.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/context/MessageContext.java @@ -19,6 +19,8 @@ package org.springframework.ws.context; import java.io.IOException; import java.io.InputStream; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.WebServiceMessage; import org.springframework.ws.server.EndpointInterceptor; @@ -61,7 +63,7 @@ public interface MessageContext { * @throws IllegalStateException if a response has already been created * @since 1.5.0 */ - void setResponse(WebServiceMessage response); + void setResponse(@Nullable WebServiceMessage response); /** * Removes the response message, if any. @@ -91,7 +93,7 @@ public interface MessageContext { * @param name name of the property whose value is to be retrieved * @return value of the property */ - Object getProperty(String name); + @Nullable Object getProperty(String name); /** * Removes a property from the {@code MessageContext}. diff --git a/spring-ws-core/src/main/java/org/springframework/ws/context/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/context/package-info.java index 12e0f138..84534d27 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/context/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/context/package-info.java @@ -17,4 +17,7 @@ /** * Contains the {@code MessageContext} interface and implementations thereof. */ +@NullMarked package org.springframework.ws.context; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/mime/AbstractMimeMessage.java b/spring-ws-core/src/main/java/org/springframework/ws/mime/AbstractMimeMessage.java index b9a10204..1e257059 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/mime/AbstractMimeMessage.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/mime/AbstractMimeMessage.java @@ -93,7 +93,7 @@ public abstract class AbstractMimeMessage implements MimeMessage { @Override public String getName() { - if (this.inputStreamSource instanceof Resource resource) { + if (this.inputStreamSource instanceof Resource resource && resource.getFilename() != null) { return resource.getFilename(); } else { diff --git a/spring-ws-core/src/main/java/org/springframework/ws/mime/MimeMessage.java b/spring-ws-core/src/main/java/org/springframework/ws/mime/MimeMessage.java index f3df5c26..1aad3f8c 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/mime/MimeMessage.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/mime/MimeMessage.java @@ -20,6 +20,7 @@ import java.io.File; import java.util.Iterator; import jakarta.activation.DataHandler; +import org.jspecify.annotations.Nullable; import org.springframework.core.io.InputStreamSource; import org.springframework.ws.WebServiceMessage; @@ -58,7 +59,7 @@ public interface MimeMessage extends WebServiceMessage { * be found * @throws AttachmentException in case of errors */ - Attachment getAttachment(String contentId) throws AttachmentException; + @Nullable Attachment getAttachment(String contentId) throws AttachmentException; /** * Returns an {@code Iterator} over all {@link Attachment} objects that are part of diff --git a/spring-ws-core/src/main/java/org/springframework/ws/mime/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/mime/package-info.java index df27a310..a1e7679f 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/mime/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/mime/package-info.java @@ -18,4 +18,7 @@ * Provides MIME functionality for use the Spring Web Services framework. Contains the * Attachment and MimeMessage and related interfaces. */ +@NullMarked package org.springframework.ws.mime; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/package-info.java index 5b922498..5b5e2a91 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/package-info.java @@ -17,4 +17,7 @@ /** * Provides the core functionality of the Spring Web Services framework. */ +@NullMarked package org.springframework.ws; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/pox/dom/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/pox/dom/package-info.java index 9e84ff02..f830e639 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/pox/dom/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/pox/dom/package-info.java @@ -17,4 +17,7 @@ /** * Contains an implementation of the POX interfaces that is based on DOM. */ +@NullMarked package org.springframework.ws.pox.dom; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/pox/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/pox/package-info.java index 05ed69fd..ac967299 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/pox/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/pox/package-info.java @@ -18,4 +18,7 @@ * Provides the Plain Old XML (POX) functionality of the Spring Web Services framework. * Contains the PoxMessage and related interfaces. */ +@NullMarked package org.springframework.ws.pox; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/EndpointExceptionResolver.java b/spring-ws-core/src/main/java/org/springframework/ws/server/EndpointExceptionResolver.java index a63879b6..9363279a 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/EndpointExceptionResolver.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/EndpointExceptionResolver.java @@ -16,6 +16,8 @@ package org.springframework.ws.server; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.context.MessageContext; /** @@ -35,6 +37,6 @@ public interface EndpointExceptionResolver { * @param ex the exception that got thrown during endpoint execution * @return {@code true} if resolved; {@code false} otherwise */ - boolean resolveException(MessageContext messageContext, Object endpoint, Exception ex); + boolean resolveException(MessageContext messageContext, @Nullable Object endpoint, Exception ex); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/EndpointInterceptor.java b/spring-ws-core/src/main/java/org/springframework/ws/server/EndpointInterceptor.java index 380dcaf4..c5894451 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/EndpointInterceptor.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/EndpointInterceptor.java @@ -16,6 +16,8 @@ package org.springframework.ws.server; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.context.MessageContext; /** @@ -125,6 +127,6 @@ public interface EndpointInterceptor { * @throws Exception in case of errors * @since 2.0.2 */ - void afterCompletion(MessageContext messageContext, Object endpoint, Exception ex) throws Exception; + void afterCompletion(MessageContext messageContext, Object endpoint, @Nullable Exception ex) throws Exception; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/EndpointInvocationChain.java b/spring-ws-core/src/main/java/org/springframework/ws/server/EndpointInvocationChain.java index 71db24bd..95709219 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/EndpointInvocationChain.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/EndpointInvocationChain.java @@ -16,6 +16,8 @@ package org.springframework.ws.server; +import org.jspecify.annotations.Nullable; + /** * Endpoint invocation chain, consisting of an endpoint object and any preprocessing * interceptors. @@ -28,7 +30,7 @@ public class EndpointInvocationChain { private final Object endpoint; - private EndpointInterceptor[] interceptors; + private EndpointInterceptor @Nullable [] interceptors; /** * Create new {@code EndpointInvocationChain}. @@ -43,7 +45,7 @@ public class EndpointInvocationChain { * @param endpoint the endpoint object to invoke * @param interceptors the array of interceptors to apply */ - public EndpointInvocationChain(Object endpoint, EndpointInterceptor[] interceptors) { + public EndpointInvocationChain(Object endpoint, EndpointInterceptor @Nullable [] interceptors) { this.endpoint = endpoint; this.interceptors = interceptors; } @@ -60,7 +62,7 @@ public class EndpointInvocationChain { * Returns the array of interceptors to apply before the handler executes. * @return the array of interceptors */ - public EndpointInterceptor[] getInterceptors() { + public EndpointInterceptor @Nullable [] getInterceptors() { return this.interceptors; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/EndpointMapping.java b/spring-ws-core/src/main/java/org/springframework/ws/server/EndpointMapping.java index 1aa66949..03dd716a 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/EndpointMapping.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/EndpointMapping.java @@ -16,6 +16,8 @@ package org.springframework.ws.server; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.context.MessageContext; /** @@ -57,6 +59,6 @@ public interface EndpointMapping { * interceptors, or {@code null} if no mapping is found * @throws Exception if there is an internal error */ - EndpointInvocationChain getEndpoint(MessageContext messageContext) throws Exception; + @Nullable EndpointInvocationChain getEndpoint(MessageContext messageContext) throws Exception; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/MessageDispatcher.java b/spring-ws-core/src/main/java/org/springframework/ws/server/MessageDispatcher.java index 1e2e34c2..4e900d1b 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/MessageDispatcher.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/MessageDispatcher.java @@ -25,6 +25,7 @@ import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactoryUtils; @@ -103,15 +104,19 @@ public class MessageDispatcher implements WebServiceMessageReceiver, BeanNameAwa private final DefaultStrategiesHelper defaultStrategiesHelper; /** The registered bean name for this dispatcher. */ + @SuppressWarnings("NullAway.Init") private String beanName; /** List of EndpointAdapters used in this dispatcher. */ + @SuppressWarnings("NullAway.Init") private List endpointAdapters; /** List of EndpointExceptionResolvers used in this dispatcher. */ + @SuppressWarnings("NullAway.Init") private List endpointExceptionResolvers; /** List of EndpointMappings used in this dispatcher. */ + @SuppressWarnings("NullAway.Init") private List endpointMappings; /** Initializes a new instance of the {@code MessageDispatcher}. */ @@ -231,8 +236,8 @@ public class MessageDispatcher implements WebServiceMessageReceiver, BeanNameAwa EndpointInterceptor interceptor = mappedEndpoint.getInterceptors()[i]; interceptorIndex = i; if (!interceptor.handleRequest(messageContext, mappedEndpoint.getEndpoint())) { - triggerHandleResponse(mappedEndpoint, interceptorIndex, messageContext); - triggerAfterCompletion(mappedEndpoint, interceptorIndex, messageContext, null); + triggerHandleResponse(messageContext, mappedEndpoint, interceptorIndex); + triggerAfterCompletion(messageContext, mappedEndpoint, interceptorIndex, null); return; } } @@ -242,7 +247,7 @@ public class MessageDispatcher implements WebServiceMessageReceiver, BeanNameAwa endpointAdapter.invoke(messageContext, mappedEndpoint.getEndpoint()); // Apply handleResponse methods of registered interceptors - triggerHandleResponse(mappedEndpoint, interceptorIndex, messageContext); + triggerHandleResponse(messageContext, mappedEndpoint, interceptorIndex); } catch (NoEndpointFoundException ex) { // No triggering of interceptors if no endpoint is found @@ -254,16 +259,16 @@ public class MessageDispatcher implements WebServiceMessageReceiver, BeanNameAwa catch (Exception ex) { Object endpoint = (mappedEndpoint != null) ? mappedEndpoint.getEndpoint() : null; processEndpointException(messageContext, endpoint, ex); - triggerHandleResponse(mappedEndpoint, interceptorIndex, messageContext); + triggerHandleResponse(messageContext, mappedEndpoint, interceptorIndex); } - triggerAfterCompletion(mappedEndpoint, interceptorIndex, messageContext, null); + triggerAfterCompletion(messageContext, mappedEndpoint, interceptorIndex, null); } catch (NoEndpointFoundException ex) { throw ex; } catch (Exception ex) { // Trigger after-completion for thrown exception. - triggerAfterCompletion(mappedEndpoint, interceptorIndex, messageContext, ex); + triggerAfterCompletion(messageContext, mappedEndpoint, interceptorIndex, ex); throw ex; } } @@ -273,7 +278,7 @@ public class MessageDispatcher implements WebServiceMessageReceiver, BeanNameAwa * @return the {@code EndpointInvocationChain}, or {@code null} if no endpoint could * be found. */ - protected EndpointInvocationChain getEndpoint(MessageContext messageContext) throws Exception { + protected @Nullable EndpointInvocationChain getEndpoint(MessageContext messageContext) throws Exception { for (EndpointMapping endpointMapping : getEndpointMappings()) { EndpointInvocationChain endpoint = endpointMapping.getEndpoint(messageContext); if (endpoint != null) { @@ -331,7 +336,7 @@ public class MessageDispatcher implements WebServiceMessageReceiver, BeanNameAwa * @param ex the exception that got thrown during handler execution * @throws Exception if no suitable resolver is found */ - protected void processEndpointException(MessageContext messageContext, Object endpoint, Exception ex) + protected void processEndpointException(MessageContext messageContext, @Nullable Object endpoint, Exception ex) throws Exception { if (!CollectionUtils.isEmpty(getEndpointExceptionResolvers())) { for (EndpointExceptionResolver resolver : getEndpointExceptionResolvers()) { @@ -351,14 +356,14 @@ public class MessageDispatcher implements WebServiceMessageReceiver, BeanNameAwa * Trigger handleResponse or handleFault on the mapped EndpointInterceptors. Will just * invoke said method on all interceptors whose handleRequest invocation returned * {@code true}, in addition to the last interceptor who returned {@code false}. + * @param messageContext the message context, whose request and response are filled * @param mappedEndpoint the mapped EndpointInvocationChain * @param interceptorIndex index of last interceptor that was called - * @param messageContext the message context, whose request and response are filled - * @see EndpointInterceptor#handleResponse(MessageContext,Object) + * @see EndpointInterceptor#handleResponse(MessageContext, Object) * @see EndpointInterceptor#handleFault(MessageContext, Object) */ - private void triggerHandleResponse(EndpointInvocationChain mappedEndpoint, int interceptorIndex, - MessageContext messageContext) throws Exception { + private void triggerHandleResponse(MessageContext messageContext, @Nullable EndpointInvocationChain mappedEndpoint, + int interceptorIndex) throws Exception { if (mappedEndpoint != null && messageContext.hasResponse() && !ObjectUtils.isEmpty(mappedEndpoint.getInterceptors())) { boolean hasFault = false; @@ -389,8 +394,8 @@ public class MessageDispatcher implements WebServiceMessageReceiver, BeanNameAwa * @param ex exception thrown on handler execution, or {@code null} if none * @see EndpointInterceptor#afterCompletion */ - private void triggerAfterCompletion(EndpointInvocationChain mappedEndpoint, int interceptorIndex, - MessageContext messageContext, Exception ex) throws Exception { + private void triggerAfterCompletion(MessageContext messageContext, @Nullable EndpointInvocationChain mappedEndpoint, + int interceptorIndex, @Nullable Exception ex) throws Exception { // Apply afterCompletion methods of registered interceptors. if (mappedEndpoint != null) { diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/AbstractEndpointExceptionResolver.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/AbstractEndpointExceptionResolver.java index 13a197a2..e36d2f8e 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/AbstractEndpointExceptionResolver.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/AbstractEndpointExceptionResolver.java @@ -20,6 +20,7 @@ import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.core.Ordered; import org.springframework.ws.context.MessageContext; @@ -41,9 +42,9 @@ public abstract class AbstractEndpointExceptionResolver implements EndpointExcep private int order = Integer.MAX_VALUE; // default: same as non-Ordered - private Set mappedEndpoints; + private @Nullable Set mappedEndpoints; - private Log warnLogger; + private @Nullable Log warnLogger; /** * Specify the set of endpoints that this exception resolver should map. @@ -94,7 +95,7 @@ public abstract class AbstractEndpointExceptionResolver implements EndpointExcep * @see #resolveExceptionInternal(MessageContext, Object, Exception) */ @Override - public final boolean resolveException(MessageContext messageContext, Object endpoint, Exception ex) { + public final boolean resolveException(MessageContext messageContext, @Nullable Object endpoint, Exception ex) { Object mappedEndpoint = (endpoint instanceof MethodEndpoint methodEndpoint) ? methodEndpoint.getBean() : endpoint; if (this.mappedEndpoints != null && !this.mappedEndpoints.contains(mappedEndpoint)) { @@ -105,7 +106,7 @@ public abstract class AbstractEndpointExceptionResolver implements EndpointExcep } boolean resolved = resolveExceptionInternal(messageContext, endpoint, ex); if (resolved) { - logException(ex, messageContext); + logException(messageContext, ex); } return resolved; } @@ -116,39 +117,40 @@ public abstract class AbstractEndpointExceptionResolver implements EndpointExcep *

* Calls {@link #buildLogMessage} in order to determine the concrete message to log. * Always passes the full exception to the logger. - * @param ex the exception that got thrown during handler execution * @param messageContext current message context request + * @param ex the exception that got thrown during handler execution * @see #setWarnLogCategory * @see #buildLogMessage * @see org.apache.commons.logging.Log#warn(Object, Throwable) */ - protected void logException(Exception ex, MessageContext messageContext) { + protected void logException(MessageContext messageContext, Exception ex) { if (this.warnLogger != null && this.warnLogger.isWarnEnabled()) { - this.warnLogger.warn(buildLogMessage(ex, messageContext), ex); + this.warnLogger.warn(buildLogMessage(messageContext, ex), ex); } } /** * Build a log message for the given exception, occured during processing the given * message context. - * @param ex the exception that got thrown during handler execution * @param messageContext the message context + * @param ex the exception that got thrown during handler execution * @return the log message to use */ - protected String buildLogMessage(Exception ex, MessageContext messageContext) { + protected String buildLogMessage(MessageContext messageContext, Exception ex) { return "Endpoint execution resulted in exception"; } /** * Template method for resolving exceptions that is called by - * {@link #resolveException}. + * {@link EndpointExceptionResolver#resolveException}. * @param messageContext current message context * @param endpoint the executed endpoint, or {@code null} if none chosen at the time * of the exception * @param ex the exception that got thrown during endpoint execution * @return {@code true} if resolved; {@code false} otherwise - * @see #resolveException(MessageContext, Object, Exception) + * @see EndpointExceptionResolver#resolveException(MessageContext, Object, Exception) */ - protected abstract boolean resolveExceptionInternal(MessageContext messageContext, Object endpoint, Exception ex); + protected abstract boolean resolveExceptionInternal(MessageContext messageContext, @Nullable Object endpoint, + Exception ex); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/AbstractLoggingInterceptor.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/AbstractLoggingInterceptor.java index 9913e7e5..849f1f8d 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/AbstractLoggingInterceptor.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/AbstractLoggingInterceptor.java @@ -27,6 +27,7 @@ import javax.xml.transform.stream.StreamResult; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.ws.WebServiceMessage; import org.springframework.ws.context.MessageContext; @@ -116,7 +117,7 @@ public abstract class AbstractLoggingInterceptor extends TransformerObjectSuppor * Does nothing by default. */ @Override - public void afterCompletion(MessageContext messageContext, Object endpoint, Exception ex) { + public void afterCompletion(MessageContext messageContext, Object endpoint, @Nullable Exception ex) { } /** @@ -146,7 +147,7 @@ public abstract class AbstractLoggingInterceptor extends TransformerObjectSuppor * @param source the source to be logged * @throws TransformerException in case of errors */ - protected void logMessageSource(String logMessage, Source source) throws TransformerException { + protected void logMessageSource(String logMessage, @Nullable Source source) throws TransformerException { if (source != null) { Transformer transformer = createNonIndentingTransformer(); StringWriter writer = new StringWriter(); @@ -173,6 +174,6 @@ public abstract class AbstractLoggingInterceptor extends TransformerObjectSuppor * @param message the message * @return the source of the message */ - protected abstract Source getSource(WebServiceMessage message); + protected abstract @Nullable Source getSource(WebServiceMessage message); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/CompositeEndpointExceptionResolver.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/CompositeEndpointExceptionResolver.java index 61048874..6371e3ae 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/CompositeEndpointExceptionResolver.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/CompositeEndpointExceptionResolver.java @@ -16,6 +16,8 @@ package org.springframework.ws.server.endpoint; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.context.MessageContext; import org.springframework.ws.server.EndpointExceptionResolver; @@ -35,7 +37,7 @@ public class CompositeEndpointExceptionResolver implements EndpointExceptionReso } @Override - public final boolean resolveException(MessageContext messageContext, Object endpoint, Exception ex) { + public final boolean resolveException(MessageContext messageContext, @Nullable Object endpoint, Exception ex) { AbstractEndpointExceptionResolver currentResolver = null; for (AbstractEndpointExceptionResolver resolver : this.resolvers) { currentResolver = resolver; @@ -44,7 +46,7 @@ public class CompositeEndpointExceptionResolver implements EndpointExceptionReso } } if (currentResolver != null) { - currentResolver.logException(ex, messageContext); + currentResolver.logException(messageContext, ex); } return false; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/MethodEndpoint.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/MethodEndpoint.java index c3620557..1b1fd62e 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/MethodEndpoint.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/MethodEndpoint.java @@ -19,6 +19,8 @@ package org.springframework.ws.server.endpoint; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.BeanFactory; import org.springframework.core.MethodParameter; import org.springframework.util.Assert; @@ -39,7 +41,7 @@ public final class MethodEndpoint { private final Method method; - private final BeanFactory beanFactory; + private final @Nullable BeanFactory beanFactory; /** * Constructs a new method endpoint with the given bean and method. diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/PayloadEndpoint.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/PayloadEndpoint.java index 4def1d43..e8e69dee 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/PayloadEndpoint.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/PayloadEndpoint.java @@ -18,6 +18,8 @@ package org.springframework.ws.server.endpoint; import javax.xml.transform.Source; +import org.jspecify.annotations.Nullable; + /** * Defines the basic contract for Web Services interested in just the message payload. *

@@ -37,6 +39,6 @@ public interface PayloadEndpoint { * response * @throws Exception if an exception occurs */ - Source invoke(Source request) throws Exception; + @Nullable Source invoke(@Nullable Source request) throws Exception; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/DefaultMethodEndpointAdapter.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/DefaultMethodEndpointAdapter.java index 717b7b7c..d9c06ca1 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/DefaultMethodEndpointAdapter.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/DefaultMethodEndpointAdapter.java @@ -20,6 +20,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.InitializingBean; @@ -66,11 +68,13 @@ public class DefaultMethodEndpointAdapter extends AbstractMethodEndpointAdapter private static final String SOAP_HEADER_ELEMENT_ARGUMENT_RESOLVER_CLASS_NAME = "org.springframework.ws.soap.server.endpoint.adapter.method.SoapHeaderElementMethodArgumentResolver"; + @SuppressWarnings("NullAway.Init") private List methodArgumentResolvers; + @SuppressWarnings("NullAway.Init") private List methodReturnValueHandlers; - private ClassLoader classLoader; + private @Nullable ClassLoader classLoader; /** * Create a new instance with default method argument and return value resolvers. @@ -247,7 +251,7 @@ public class DefaultMethodEndpointAdapter extends AbstractMethodEndpointAdapter @Override protected final void invokeInternal(MessageContext messageContext, MethodEndpoint methodEndpoint) throws Exception { - Object[] args = getMethodArguments(messageContext, methodEndpoint); + @Nullable Object[] args = getMethodArguments(messageContext, methodEndpoint); if (this.logger.isTraceEnabled()) { this.logger.trace("Invoking [" + methodEndpoint + "] with arguments " + Arrays.asList(args)); @@ -276,10 +280,10 @@ public class DefaultMethodEndpointAdapter extends AbstractMethodEndpointAdapter * @return the arguments * @throws Exception in case of errors */ - protected Object[] getMethodArguments(MessageContext messageContext, MethodEndpoint methodEndpoint) + protected @Nullable Object[] getMethodArguments(MessageContext messageContext, MethodEndpoint methodEndpoint) throws Exception { MethodParameter[] parameters = methodEndpoint.getMethodParameters(); - Object[] args = new Object[parameters.length]; + @Nullable Object[] args = new Object[parameters.length]; for (int i = 0; i < parameters.length; i++) { for (MethodArgumentResolver methodArgumentResolver : this.methodArgumentResolvers) { if (methodArgumentResolver.supportsParameter(parameters[i])) { diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/AbstractPayloadSourceMethodProcessor.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/AbstractPayloadSourceMethodProcessor.java index 69b7e6a7..892effe8 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/AbstractPayloadSourceMethodProcessor.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/AbstractPayloadSourceMethodProcessor.java @@ -18,6 +18,8 @@ package org.springframework.ws.server.endpoint.adapter.method; import javax.xml.transform.Source; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; import org.springframework.ws.WebServiceMessage; import org.springframework.ws.context.MessageContext; @@ -35,15 +37,15 @@ public abstract class AbstractPayloadSourceMethodProcessor extends AbstractPaylo // MethodArgumentResolver @Override - public final Object resolveArgument(MessageContext messageContext, MethodParameter parameter) throws Exception { + public final @Nullable Object resolveArgument(MessageContext messageContext, MethodParameter parameter) + throws Exception { Source requestPayload = getRequestPayload(messageContext); return (requestPayload != null) ? resolveRequestPayloadArgument(parameter, requestPayload) : null; } /** Returns the request payload as {@code Source}. */ - private Source getRequestPayload(MessageContext messageContext) { - WebServiceMessage request = messageContext.getRequest(); - return (request != null) ? request.getPayloadSource() : null; + private @Nullable Source getRequestPayload(MessageContext messageContext) { + return messageContext.getRequest().getPayloadSource(); } /** @@ -60,14 +62,12 @@ public abstract class AbstractPayloadSourceMethodProcessor extends AbstractPaylo // MethodReturnValueHandler @Override - public final void handleReturnValue(MessageContext messageContext, MethodParameter returnType, Object returnValue) - throws Exception { + public final void handleReturnValue(MessageContext messageContext, MethodParameter returnType, + @Nullable Object returnValue) throws Exception { if (returnValue != null) { Source responsePayload = createResponsePayload(returnType, returnValue); - if (responsePayload != null) { - WebServiceMessage response = messageContext.getResponse(); - transform(responsePayload, response.getPayloadResult()); - } + WebServiceMessage response = messageContext.getResponse(); + transform(responsePayload, response.getPayloadResult()); } } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/MarshallingPayloadMethodProcessor.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/MarshallingPayloadMethodProcessor.java index 267823e3..14eb8ad8 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/MarshallingPayloadMethodProcessor.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/MarshallingPayloadMethodProcessor.java @@ -16,6 +16,8 @@ package org.springframework.ws.server.endpoint.adapter.method; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; import org.springframework.oxm.GenericMarshaller; import org.springframework.oxm.GenericUnmarshaller; @@ -35,9 +37,9 @@ import org.springframework.ws.support.MarshallingUtils; */ public class MarshallingPayloadMethodProcessor extends AbstractPayloadMethodProcessor { - private Marshaller marshaller; + private @Nullable Marshaller marshaller; - private Unmarshaller unmarshaller; + private @Nullable Unmarshaller unmarshaller; /** * Creates a new {@code MarshallingPayloadMethodProcessor}. The {@link Marshaller} and @@ -83,7 +85,7 @@ public class MarshallingPayloadMethodProcessor extends AbstractPayloadMethodProc /** * Returns the marshaller used for transforming objects into XML. */ - public Marshaller getMarshaller() { + public @Nullable Marshaller getMarshaller() { return this.marshaller; } @@ -97,7 +99,7 @@ public class MarshallingPayloadMethodProcessor extends AbstractPayloadMethodProc /** * Returns the unmarshaller used for transforming XML into objects. */ - public Unmarshaller getUnmarshaller() { + public @Nullable Unmarshaller getUnmarshaller() { return this.unmarshaller; } @@ -123,7 +125,7 @@ public class MarshallingPayloadMethodProcessor extends AbstractPayloadMethodProc } @Override - public Object resolveArgument(MessageContext messageContext, MethodParameter parameter) throws Exception { + public @Nullable Object resolveArgument(MessageContext messageContext, MethodParameter parameter) throws Exception { Unmarshaller unmarshaller = getUnmarshaller(); Assert.state(unmarshaller != null, "unmarshaller must not be null"); @@ -150,8 +152,8 @@ public class MarshallingPayloadMethodProcessor extends AbstractPayloadMethodProc } @Override - public void handleReturnValue(MessageContext messageContext, MethodParameter returnType, Object returnValue) - throws Exception { + public void handleReturnValue(MessageContext messageContext, MethodParameter returnType, + @Nullable Object returnValue) throws Exception { if (returnValue == null) { return; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/MethodArgumentResolver.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/MethodArgumentResolver.java index f245b006..69372ea9 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/MethodArgumentResolver.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/MethodArgumentResolver.java @@ -16,6 +16,8 @@ package org.springframework.ws.server.endpoint.adapter.method; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; import org.springframework.ws.context.MessageContext; @@ -48,6 +50,6 @@ public interface MethodArgumentResolver { * @return the resolved argument. May be {@code null}. * @throws Exception in case of errors */ - Object resolveArgument(MessageContext messageContext, MethodParameter parameter) throws Exception; + @Nullable Object resolveArgument(MessageContext messageContext, MethodParameter parameter) throws Exception; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/MethodReturnValueHandler.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/MethodReturnValueHandler.java index 3f108c8f..ace6af09 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/MethodReturnValueHandler.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/MethodReturnValueHandler.java @@ -16,6 +16,8 @@ package org.springframework.ws.server.endpoint.adapter.method; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; import org.springframework.ws.context.MessageContext; @@ -47,7 +49,7 @@ public interface MethodReturnValueHandler { * @param returnValue the return value to handle * @throws Exception in case of errors */ - void handleReturnValue(MessageContext messageContext, MethodParameter returnType, Object returnValue) + void handleReturnValue(MessageContext messageContext, MethodParameter returnType, @Nullable Object returnValue) throws Exception; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/SourcePayloadMethodProcessor.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/SourcePayloadMethodProcessor.java index 23da7836..cc2ae019 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/SourcePayloadMethodProcessor.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/SourcePayloadMethodProcessor.java @@ -30,6 +30,7 @@ import javax.xml.transform.sax.SAXSource; import javax.xml.transform.stax.StAXSource; import javax.xml.transform.stream.StreamSource; +import org.jspecify.annotations.Nullable; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.xml.sax.InputSource; @@ -166,7 +167,7 @@ public class SourcePayloadMethodProcessor extends AbstractPayloadSourceMethodPro return (parentLocation != null) ? parentLocation.getLineNumber() : -1; } - public String getPublicId() { + public @Nullable String getPublicId() { return (parentLocation != null) ? parentLocation.getPublicId() : null; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/StaxPayloadMethodArgumentResolver.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/StaxPayloadMethodArgumentResolver.java index 7b6f31a8..5586183d 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/StaxPayloadMethodArgumentResolver.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/StaxPayloadMethodArgumentResolver.java @@ -27,6 +27,8 @@ import javax.xml.transform.Source; import javax.xml.transform.TransformerException; import javax.xml.transform.stream.StreamResult; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; import org.springframework.util.xml.StaxUtils; import org.springframework.ws.context.MessageContext; @@ -57,7 +59,7 @@ public class StaxPayloadMethodArgumentResolver extends TransformerObjectSupport } @Override - public Object resolveArgument(MessageContext messageContext, MethodParameter parameter) + public @Nullable Object resolveArgument(MessageContext messageContext, MethodParameter parameter) throws TransformerException, XMLStreamException { Source source = messageContext.getRequest().getPayloadSource(); if (source == null) { diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/XPathParamMethodArgumentResolver.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/XPathParamMethodArgumentResolver.java index 909430a2..1be1cfc4 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/XPathParamMethodArgumentResolver.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/XPathParamMethodArgumentResolver.java @@ -16,6 +16,8 @@ package org.springframework.ws.server.endpoint.adapter.method; +import java.lang.reflect.Method; + import javax.xml.namespace.QName; import javax.xml.transform.Source; import javax.xml.transform.TransformerException; @@ -25,6 +27,7 @@ import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; +import org.jspecify.annotations.Nullable; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; @@ -33,6 +36,7 @@ import org.w3c.dom.NodeList; import org.springframework.core.MethodParameter; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.support.DefaultConversionService; +import org.springframework.util.Assert; import org.springframework.ws.context.MessageContext; import org.springframework.ws.server.endpoint.annotation.XPathParam; import org.springframework.ws.server.endpoint.support.NamespaceUtils; @@ -91,8 +95,10 @@ public class XPathParamMethodArgumentResolver implements MethodArgumentResolver } @Override - public Object resolveArgument(MessageContext messageContext, MethodParameter parameter) + public @Nullable Object resolveArgument(MessageContext messageContext, MethodParameter parameter) throws TransformerException, XPathExpressionException { + Method method = parameter.getMethod(); + Assert.notNull(method, "Method must not be null"); Class parameterType = parameter.getParameterType(); QName evaluationReturnType = getReturnType(parameterType); boolean useConversionService = false; @@ -100,17 +106,20 @@ public class XPathParamMethodArgumentResolver implements MethodArgumentResolver evaluationReturnType = XPathConstants.STRING; useConversionService = true; } - XPath xpath = createXPath(); - xpath.setNamespaceContext(NamespaceUtils.getNamespaceContext(parameter.getMethod())); + xpath.setNamespaceContext(NamespaceUtils.getNamespaceContext(method)); - Element rootElement = getRootElement(messageContext.getRequest().getPayloadSource()); - String expression = parameter.getParameterAnnotation(XPathParam.class).value(); + Source payloadSource = messageContext.getRequest().getPayloadSource(); + Assert.notNull(payloadSource, "No payload source available"); + Element rootElement = getRootElement(payloadSource); + XPathParam annotation = parameter.getParameterAnnotation(XPathParam.class); + Assert.state(annotation != null, "No @XPathParam annotation found"); + String expression = annotation.value(); Object result = xpath.evaluate(expression, rootElement, evaluationReturnType); return (useConversionService) ? this.conversionService.convert(result, parameterType) : result; } - private QName getReturnType(Class parameterType) { + private @Nullable QName getReturnType(Class parameterType) { if (Boolean.class.equals(parameterType) || Boolean.TYPE.equals(parameterType)) { return XPathConstants.BOOLEAN; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/dom/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/dom/package-info.java index 63fd94dd..ddc38b6d 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/dom/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/dom/package-info.java @@ -18,4 +18,7 @@ * Provides DOM-based implementations of the {@code MethodArgumentResolver} and * {@code MethodReturnValueHandler} interfaces. */ +@NullMarked package org.springframework.ws.server.endpoint.adapter.method.dom; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/jaxb/AbstractJaxb2PayloadMethodProcessor.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/jaxb/AbstractJaxb2PayloadMethodProcessor.java index b4e3211c..91d53ecc 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/jaxb/AbstractJaxb2PayloadMethodProcessor.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/jaxb/AbstractJaxb2PayloadMethodProcessor.java @@ -44,6 +44,7 @@ import jakarta.xml.bind.JAXBIntrospector; import jakarta.xml.bind.Marshaller; import jakarta.xml.bind.Unmarshaller; import jakarta.xml.bind.UnmarshallerHandler; +import org.jspecify.annotations.Nullable; import org.w3c.dom.Node; import org.xml.sax.ContentHandler; import org.xml.sax.InputSource; @@ -79,8 +80,8 @@ public abstract class AbstractJaxb2PayloadMethodProcessor extends AbstractPayloa private final ConcurrentMap, JAXBContext> jaxbContexts = new ConcurrentHashMap<>(); @Override - public final void handleReturnValue(MessageContext messageContext, MethodParameter returnType, Object returnValue) - throws Exception { + public final void handleReturnValue(MessageContext messageContext, MethodParameter returnType, + @Nullable Object returnValue) throws Exception { if (returnValue != null) { handleReturnValueInternal(messageContext, returnType, returnValue); } @@ -130,7 +131,7 @@ public abstract class AbstractJaxb2PayloadMethodProcessor extends AbstractPayloa * @return the unmarshalled object, or {@code null} if the request has no payload * @throws JAXBException in case of JAXB2 errors */ - protected final Object unmarshalFromRequestPayload(MessageContext messageContext, Class clazz) + protected final @Nullable Object unmarshalFromRequestPayload(MessageContext messageContext, Class clazz) throws JAXBException { Source requestPayload = getRequestPayload(messageContext); if (requestPayload == null) { @@ -156,8 +157,8 @@ public abstract class AbstractJaxb2PayloadMethodProcessor extends AbstractPayloa * @return the unmarshalled element, or {@code null} if the request has no payload * @throws JAXBException in case of JAXB2 errors */ - protected final JAXBElement unmarshalElementFromRequestPayload(MessageContext messageContext, Class clazz) - throws JAXBException { + protected final @Nullable JAXBElement unmarshalElementFromRequestPayload(MessageContext messageContext, + Class clazz) throws JAXBException { Source requestPayload = getRequestPayload(messageContext); if (requestPayload == null) { return null; @@ -175,9 +176,8 @@ public abstract class AbstractJaxb2PayloadMethodProcessor extends AbstractPayloa } } - private Source getRequestPayload(MessageContext messageContext) { - WebServiceMessage request = messageContext.getRequest(); - return (request != null) ? request.getPayloadSource() : null; + private @Nullable Source getRequestPayload(MessageContext messageContext) { + return messageContext.getRequest().getPayloadSource(); } private JAXBException convertToJaxbException(Exception ex) { @@ -237,7 +237,7 @@ public abstract class AbstractJaxb2PayloadMethodProcessor extends AbstractPayloa private final Unmarshaller unmarshaller; - private Object result; + private @Nullable Object result; Jaxb2SourceCallback(Class clazz) throws JAXBException { this.unmarshaller = createUnmarshaller(clazz); @@ -307,7 +307,7 @@ public abstract class AbstractJaxb2PayloadMethodProcessor extends AbstractPayloa private final Class declaredType; - private JAXBElement result; + private @Nullable JAXBElement result; JaxbElementSourceCallback(Class declaredType) throws JAXBException { this.unmarshaller = createUnmarshaller(declaredType); diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/jaxb/JaxbElementPayloadMethodProcessor.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/jaxb/JaxbElementPayloadMethodProcessor.java index 4ad127da..8af0f8ec 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/jaxb/JaxbElementPayloadMethodProcessor.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/jaxb/JaxbElementPayloadMethodProcessor.java @@ -21,6 +21,7 @@ import java.lang.reflect.Type; import jakarta.xml.bind.JAXBElement; import jakarta.xml.bind.JAXBException; +import org.jspecify.annotations.Nullable; import org.springframework.core.MethodParameter; import org.springframework.ws.context.MessageContext; @@ -45,7 +46,7 @@ public class JaxbElementPayloadMethodProcessor extends AbstractJaxb2PayloadMetho } @Override - public JAXBElement resolveArgument(MessageContext messageContext, MethodParameter parameter) + public @Nullable JAXBElement resolveArgument(MessageContext messageContext, MethodParameter parameter) throws JAXBException { ParameterizedType parameterizedType = (ParameterizedType) parameter.getGenericParameterType(); Class clazz = (Class) parameterizedType.getActualTypeArguments()[0]; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/jaxb/XmlRootElementPayloadMethodProcessor.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/jaxb/XmlRootElementPayloadMethodProcessor.java index 78f36ad2..dc816153 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/jaxb/XmlRootElementPayloadMethodProcessor.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/jaxb/XmlRootElementPayloadMethodProcessor.java @@ -20,6 +20,7 @@ import jakarta.xml.bind.JAXBElement; import jakarta.xml.bind.JAXBException; import jakarta.xml.bind.annotation.XmlRootElement; import jakarta.xml.bind.annotation.XmlType; +import org.jspecify.annotations.Nullable; import org.springframework.core.MethodParameter; import org.springframework.ws.context.MessageContext; @@ -46,7 +47,8 @@ public class XmlRootElementPayloadMethodProcessor extends AbstractJaxb2PayloadMe } @Override - public Object resolveArgument(MessageContext messageContext, MethodParameter parameter) throws JAXBException { + public @Nullable Object resolveArgument(MessageContext messageContext, MethodParameter parameter) + throws JAXBException { Class parameterType = parameter.getParameterType(); if (parameterType.isAnnotationPresent(XmlRootElement.class)) { diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/jaxb/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/jaxb/package-info.java index ec70b2c0..55bc9e53 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/jaxb/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/jaxb/package-info.java @@ -18,4 +18,7 @@ * Provides JAXB2-based implementations of the {@code MethodArgumentResolver} and * {@code MethodReturnValueHandler} interfaces. */ +@NullMarked package org.springframework.ws.server.endpoint.adapter.method.jaxb; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/package-info.java index c5bfb586..c36641db 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/package-info.java @@ -18,4 +18,7 @@ * Provides the {@code MethodArgumentResolver} and {@code MethodReturnValueHandler} * abstractions, and various implementations thereof. */ +@NullMarked package org.springframework.ws.server.endpoint.adapter.method; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/package-info.java index a0959439..db1604e4 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/adapter/package-info.java @@ -17,4 +17,7 @@ /** * Provides miscellaneous {@code EndpointAdapter} implementations. */ +@NullMarked package org.springframework.ws.server.endpoint.adapter; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/annotation/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/annotation/package-info.java index 8ab9aff4..4dfeae60 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/annotation/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/annotation/package-info.java @@ -17,4 +17,7 @@ /** * JDK 1.5+ annotations for Spring-WS endpoints. */ +@NullMarked package org.springframework.ws.server.endpoint.annotation; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/interceptor/AbstractValidatingInterceptor.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/interceptor/AbstractValidatingInterceptor.java index e397c30a..5205f098 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/interceptor/AbstractValidatingInterceptor.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/interceptor/AbstractValidatingInterceptor.java @@ -21,6 +21,7 @@ import java.io.IOException; import javax.xml.transform.Source; import javax.xml.transform.TransformerException; +import org.jspecify.annotations.Nullable; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; @@ -60,15 +61,16 @@ public abstract class AbstractValidatingInterceptor extends TransformerObjectSup private String schemaLanguage = XmlValidatorFactory.SCHEMA_W3C_XML; - private Resource[] schemas; + private Resource @Nullable [] schemas; private boolean validateRequest = true; private boolean validateResponse = false; + @SuppressWarnings("NullAway.Init") private XmlValidator validator; - private ValidationErrorHandler errorHandler; + private @Nullable ValidationErrorHandler errorHandler; public String getSchemaLanguage() { return this.schemaLanguage; @@ -87,7 +89,7 @@ public abstract class AbstractValidatingInterceptor extends TransformerObjectSup /** * Returns the schema resources to use for validation. */ - public Resource[] getSchemas() { + public Resource @Nullable [] getSchemas() { return this.schemas; } @@ -275,7 +277,7 @@ public abstract class AbstractValidatingInterceptor extends TransformerObjectSup /** Does nothing by default. */ @Override - public void afterCompletion(MessageContext messageContext, Object endpoint, Exception ex) { + public void afterCompletion(MessageContext messageContext, Object endpoint, @Nullable Exception ex) { } /** @@ -285,7 +287,7 @@ public abstract class AbstractValidatingInterceptor extends TransformerObjectSup * @return the part of the message that is to validated, or {@code null} not to * validate anything */ - protected abstract Source getValidationRequestSource(WebServiceMessage request); + protected abstract @Nullable Source getValidationRequestSource(WebServiceMessage request); /** * Abstract template method that returns the part of the response message that is to @@ -294,6 +296,6 @@ public abstract class AbstractValidatingInterceptor extends TransformerObjectSup * @return the part of the message that is to validated, or {@code null} not to * validate anything */ - protected abstract Source getValidationResponseSource(WebServiceMessage response); + protected abstract @Nullable Source getValidationResponseSource(WebServiceMessage response); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/interceptor/DelegatingSmartEndpointInterceptor.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/interceptor/DelegatingSmartEndpointInterceptor.java index e1de2499..a9805dc4 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/interceptor/DelegatingSmartEndpointInterceptor.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/interceptor/DelegatingSmartEndpointInterceptor.java @@ -16,6 +16,8 @@ package org.springframework.ws.server.endpoint.interceptor; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; import org.springframework.ws.WebServiceMessage; import org.springframework.ws.context.MessageContext; @@ -92,7 +94,8 @@ public class DelegatingSmartEndpointInterceptor implements SmartEndpointIntercep } @Override - public void afterCompletion(MessageContext messageContext, Object endpoint, Exception ex) throws Exception { + public void afterCompletion(MessageContext messageContext, Object endpoint, @Nullable Exception ex) + throws Exception { getDelegate().afterCompletion(messageContext, endpoint, ex); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/interceptor/EndpointInterceptorAdapter.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/interceptor/EndpointInterceptorAdapter.java index 5dfaa3c1..b1cd81c8 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/interceptor/EndpointInterceptorAdapter.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/interceptor/EndpointInterceptorAdapter.java @@ -18,6 +18,7 @@ package org.springframework.ws.server.endpoint.interceptor; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.w3c.dom.Element; import org.springframework.ws.context.MessageContext; @@ -75,7 +76,8 @@ public class EndpointInterceptorAdapter implements EndpointInterceptor { * Does nothing by default. */ @Override - public void afterCompletion(MessageContext messageContext, Object endpoint, Exception ex) throws Exception { + public void afterCompletion(MessageContext messageContext, Object endpoint, @Nullable Exception ex) + throws Exception { } } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/interceptor/PayloadLoggingInterceptor.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/interceptor/PayloadLoggingInterceptor.java index 15b0e851..ef074f09 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/interceptor/PayloadLoggingInterceptor.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/interceptor/PayloadLoggingInterceptor.java @@ -18,6 +18,8 @@ package org.springframework.ws.server.endpoint.interceptor; import javax.xml.transform.Source; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.WebServiceMessage; import org.springframework.ws.server.endpoint.AbstractLoggingInterceptor; @@ -37,7 +39,7 @@ import org.springframework.ws.server.endpoint.AbstractLoggingInterceptor; public class PayloadLoggingInterceptor extends AbstractLoggingInterceptor { @Override - protected Source getSource(WebServiceMessage message) { + protected @Nullable Source getSource(WebServiceMessage message) { return message.getPayloadSource(); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/interceptor/PayloadTransformingInterceptor.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/interceptor/PayloadTransformingInterceptor.java index 80a805b7..26997f55 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/interceptor/PayloadTransformingInterceptor.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/interceptor/PayloadTransformingInterceptor.java @@ -29,6 +29,7 @@ import javax.xml.transform.stream.StreamSource; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.xml.sax.XMLReader; import org.springframework.beans.factory.InitializingBean; @@ -61,13 +62,13 @@ public class PayloadTransformingInterceptor extends TransformerObjectSupport private static final Log logger = LogFactory.getLog(PayloadTransformingInterceptor.class); - private Resource requestXslt; + private @Nullable Resource requestXslt; - private Resource responseXslt; + private @Nullable Resource responseXslt; - private Templates requestTemplates; + private @Nullable Templates requestTemplates; - private Templates responseTemplates; + private @Nullable Templates responseTemplates; /** Sets the XSLT stylesheet to use for transforming incoming request. */ public void setRequestXslt(Resource requestXslt) { @@ -130,7 +131,7 @@ public class PayloadTransformingInterceptor extends TransformerObjectSupport /** Does nothing by default. */ @Override - public void afterCompletion(MessageContext messageContext, Object endpoint, Exception ex) { + public void afterCompletion(MessageContext messageContext, Object endpoint, @Nullable Exception ex) { } @Override diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/interceptor/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/interceptor/package-info.java index 524c9869..147e51a8 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/interceptor/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/interceptor/package-info.java @@ -17,4 +17,7 @@ /** * Provides miscellaneous endpoints {@code EndpointInterceptor} implementations. */ +@NullMarked package org.springframework.ws.server.endpoint.interceptor; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/AbstractAnnotationMethodEndpointMapping.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/AbstractAnnotationMethodEndpointMapping.java index ab41e70f..96eaaafc 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/AbstractAnnotationMethodEndpointMapping.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/AbstractAnnotationMethodEndpointMapping.java @@ -20,7 +20,9 @@ import java.lang.annotation.Annotation; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactoryUtils; +import org.springframework.context.ApplicationContext; import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.util.Assert; import org.springframework.ws.server.endpoint.annotation.Endpoint; /** @@ -61,15 +63,17 @@ public abstract class AbstractAnnotationMethodEndpointMapping extends Abstrac @Override protected void initApplicationContext() throws BeansException { super.initApplicationContext(); + ApplicationContext applicationContext = getApplicationContext(); + Assert.notNull(applicationContext, "No ApplicationContext found"); if (this.logger.isDebugEnabled()) { - this.logger.debug("Looking for endpoints in application context: " + getApplicationContext()); + this.logger.debug("Looking for endpoints in application context: " + applicationContext); } String[] beanNames = (this.detectEndpointsInAncestorContexts - ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) - : getApplicationContext().getBeanNamesForType(Object.class)); + ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class) + : applicationContext.getBeanNamesForType(Object.class)); for (String beanName : beanNames) { - Class endpointClass = getApplicationContext().getType(beanName); + Class endpointClass = applicationContext.getType(beanName); if (endpointClass != null && AnnotationUtils.findAnnotation(endpointClass, getEndpointAnnotationType()) != null) { registerMethods(beanName); diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/AbstractEndpointMapping.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/AbstractEndpointMapping.java index ff005c88..302e0d11 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/AbstractEndpointMapping.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/AbstractEndpointMapping.java @@ -21,8 +21,11 @@ import java.util.Arrays; import java.util.List; import java.util.Map; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactoryUtils; +import org.springframework.context.ApplicationContext; import org.springframework.context.support.ApplicationObjectSupport; import org.springframework.core.Ordered; import org.springframework.ws.context.MessageContext; @@ -44,18 +47,18 @@ public abstract class AbstractEndpointMapping extends ApplicationObjectSupport i private int order = Integer.MAX_VALUE; // default: same as non-Ordered - private Object defaultEndpoint; + private @Nullable Object defaultEndpoint; - private EndpointInterceptor[] interceptors; + private EndpointInterceptor @Nullable [] interceptors; - private SmartEndpointInterceptor[] smartInterceptors; + private SmartEndpointInterceptor @Nullable [] smartInterceptors; /** * Returns the endpoint interceptors to apply to all endpoints mapped by this endpoint * mapping. * @return array of endpoint interceptors, or {@code null} if none */ - public EndpointInterceptor[] getInterceptors() { + public EndpointInterceptor @Nullable [] getInterceptors() { return this.interceptors; } @@ -98,7 +101,7 @@ public abstract class AbstractEndpointMapping extends ApplicationObjectSupport i */ protected void initInterceptors() { Map smartInterceptors = BeanFactoryUtils - .beansOfTypeIncludingAncestors(getApplicationContext(), SmartEndpointInterceptor.class, true, false); + .beansOfTypeIncludingAncestors(obtainApplicationContext(), SmartEndpointInterceptor.class, true, false); if (!smartInterceptors.isEmpty()) { this.smartInterceptors = smartInterceptors.values().toArray(new SmartEndpointInterceptor[0]); } @@ -111,7 +114,7 @@ public abstract class AbstractEndpointMapping extends ApplicationObjectSupport i * @see #getEndpointInternal(org.springframework.ws.context.MessageContext) */ @Override - public final EndpointInvocationChain getEndpoint(MessageContext messageContext) throws Exception { + public final @Nullable EndpointInvocationChain getEndpoint(MessageContext messageContext) throws Exception { Object endpoint = resoleEndpoint(messageContext); if (endpoint == null) { return null; @@ -131,7 +134,7 @@ public abstract class AbstractEndpointMapping extends ApplicationObjectSupport i interceptors.toArray(new EndpointInterceptor[0])); } - private Object resoleEndpoint(MessageContext messageContext) throws Exception { + private @Nullable Object resoleEndpoint(MessageContext messageContext) throws Exception { Object endpoint = getEndpointInternal(messageContext); if (endpoint == null) { endpoint = this.defaultEndpoint; @@ -141,9 +144,6 @@ public abstract class AbstractEndpointMapping extends ApplicationObjectSupport i } if (endpoint instanceof String endpointName) { endpoint = resolveStringEndpoint(endpointName); - if (endpoint == null) { - return null; - } } return endpoint; } @@ -173,7 +173,7 @@ public abstract class AbstractEndpointMapping extends ApplicationObjectSupport i * Returns the default endpoint for this endpoint mapping. * @return the default endpoint mapping, or null if none */ - protected final Object getDefaultEndpoint() { + protected final @Nullable Object getDefaultEndpoint() { return this.defaultEndpoint; } @@ -194,9 +194,10 @@ public abstract class AbstractEndpointMapping extends ApplicationObjectSupport i * @param endpointName the endpoint name * @return the resolved endpoint, or {@code null} if the name could not be resolved */ - protected Object resolveStringEndpoint(String endpointName) { - if (getApplicationContext().containsBean(endpointName)) { - return getApplicationContext().getBean(endpointName); + protected @Nullable Object resolveStringEndpoint(String endpointName) { + ApplicationContext applicationContext = obtainApplicationContext(); + if (applicationContext.containsBean(endpointName)) { + return applicationContext.getBean(endpointName); } else { return null; @@ -214,6 +215,6 @@ public abstract class AbstractEndpointMapping extends ApplicationObjectSupport i * @return the looked up endpoint instance, or null * @throws Exception if there is an error */ - protected abstract Object getEndpointInternal(MessageContext messageContext) throws Exception; + protected abstract @Nullable Object getEndpointInternal(MessageContext messageContext) throws Exception; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/AbstractMapBasedEndpointMapping.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/AbstractMapBasedEndpointMapping.java index 0ffe89e5..2cc9012a 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/AbstractMapBasedEndpointMapping.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/AbstractMapBasedEndpointMapping.java @@ -20,8 +20,12 @@ import java.util.HashMap; import java.util.Map; import java.util.Properties; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextException; +import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.ws.context.MessageContext; @@ -42,10 +46,12 @@ public abstract class AbstractMapBasedEndpointMapping extends AbstractEndpointMa private boolean registerBeanNames = false; + private boolean configured = false; + private final Map endpointMap = new HashMap<>(); // holds mappings set via setEndpointMap and setMappings - private Map temporaryEndpointMap = new HashMap<>(); + private final Map temporaryEndpointMap = new HashMap<>(); /** * Set whether to lazily initialize endpoints. Only applicable to singleton endpoints, @@ -77,6 +83,7 @@ public abstract class AbstractMapBasedEndpointMapping extends AbstractEndpointMa * @throws IllegalArgumentException if the endpoint is invalid */ public final void setEndpointMap(Map endpointMap) { + Assert.state(!this.configured, "Mappings have already been configured"); this.temporaryEndpointMap.putAll(endpointMap); } @@ -85,6 +92,7 @@ public abstract class AbstractMapBasedEndpointMapping extends AbstractEndpointMa * exact subclass used. They can be qualified names, for instance, or mime headers. */ public void setMappings(Properties mappings) { + Assert.state(!this.configured, "Mappings have already been configured"); for (Map.Entry entry : mappings.entrySet()) { if (entry.getKey() instanceof String) { this.temporaryEndpointMap.put((String) entry.getKey(), entry.getValue()); @@ -103,7 +111,7 @@ public abstract class AbstractMapBasedEndpointMapping extends AbstractEndpointMa * key cannot be found. * @return the registration key; or {@code null} */ - protected abstract String getLookupKeyForMessage(MessageContext messageContext) throws Exception; + protected abstract @Nullable String getLookupKeyForMessage(MessageContext messageContext) throws Exception; /** * Lookup an endpoint for the given message. The extraction of the endpoint key is @@ -111,7 +119,7 @@ public abstract class AbstractMapBasedEndpointMapping extends AbstractEndpointMa * @return the looked up endpoint, or {@code null} */ @Override - protected final Object getEndpointInternal(MessageContext messageContext) throws Exception { + protected final @Nullable Object getEndpointInternal(MessageContext messageContext) throws Exception { String key = getLookupKeyForMessage(messageContext); if (!StringUtils.hasLength(key)) { return null; @@ -127,7 +135,7 @@ public abstract class AbstractMapBasedEndpointMapping extends AbstractEndpointMa * @param key key the beans are mapped to * @return the associated endpoint instance, or {@code null} if not found */ - protected Object lookupEndpoint(String key) { + protected @Nullable Object lookupEndpoint(String key) { return this.endpointMap.get(key); } @@ -176,18 +184,19 @@ public abstract class AbstractMapBasedEndpointMapping extends AbstractEndpointMa } registerEndpoint(key, endpoint); } - this.temporaryEndpointMap = null; + this.temporaryEndpointMap.clear(); + this.configured = true; if (this.registerBeanNames) { + ApplicationContext applicationContext = obtainApplicationContext(); if (this.logger.isDebugEnabled()) { - this.logger - .debug("Looking for endpoint mappings in application context: [" + getApplicationContext() + "]"); + this.logger.debug("Looking for endpoint mappings in application context: [" + applicationContext + "]"); } - String[] beanNames = getApplicationContext().getBeanDefinitionNames(); + String[] beanNames = applicationContext.getBeanDefinitionNames(); for (String beanName : beanNames) { if (validateLookupKey(beanName)) { registerEndpoint(beanName, beanName); } - String[] aliases = getApplicationContext().getAliases(beanName); + String[] aliases = applicationContext.getAliases(beanName); for (String aliase : aliases) { if (validateLookupKey(aliase)) { registerEndpoint(aliase, beanName); diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/AbstractMethodEndpointMapping.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/AbstractMethodEndpointMapping.java index 1890b724..d21203bb 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/AbstractMethodEndpointMapping.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/AbstractMethodEndpointMapping.java @@ -26,8 +26,11 @@ import java.util.List; import java.util.Map; import java.util.Set; +import org.jspecify.annotations.Nullable; + import org.springframework.aop.support.AopUtils; import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextException; import org.springframework.core.BridgeMethodResolver; import org.springframework.util.Assert; @@ -59,7 +62,7 @@ public abstract class AbstractMethodEndpointMapping extends AbstractEndpointM * @see #getLookupKeyForMessage(MessageContext) */ @Override - protected Object getEndpointInternal(MessageContext messageContext) throws Exception { + protected @Nullable Object getEndpointInternal(MessageContext messageContext) throws Exception { T key = getLookupKeyForMessage(messageContext); if (key == null) { return null; @@ -74,14 +77,14 @@ public abstract class AbstractMethodEndpointMapping extends AbstractEndpointM * Returns the endpoint keys for the given message context. * @return the registration keys */ - protected abstract T getLookupKeyForMessage(MessageContext messageContext) throws Exception; + protected abstract @Nullable T getLookupKeyForMessage(MessageContext messageContext) throws Exception; /** * Looks up an endpoint instance for the given keys. All keys are tried in order. * @param key key the beans are mapped to * @return the associated endpoint instance, or {@code null} if not found */ - protected MethodEndpoint lookupEndpoint(T key) { + protected @Nullable MethodEndpoint lookupEndpoint(T key) { return this.endpointMap.get(key); } @@ -91,7 +94,7 @@ public abstract class AbstractMethodEndpointMapping extends AbstractEndpointM * @param endpoint the method endpoint instance * @throws BeansException if the endpoint could not be registered */ - protected void registerEndpoint(T key, MethodEndpoint endpoint) throws BeansException { + protected void registerEndpoint(T key, @Nullable MethodEndpoint endpoint) throws BeansException { Object mappedEndpoint = this.endpointMap.get(key); if (mappedEndpoint != null) { throw new ApplicationContextException("Cannot map endpoint [" + endpoint + "] on registration key [" + key @@ -136,8 +139,11 @@ public abstract class AbstractMethodEndpointMapping extends AbstractEndpointM * @see #getLookupKeysForMethod(Method) */ protected void registerMethods(String beanName) { + ApplicationContext applicationContext = getApplicationContext(); + Assert.notNull(applicationContext, "'applicationContext' must not be null"); Assert.hasText(beanName, "'beanName' must not be empty"); - Class endpointType = getApplicationContext().getType(beanName); + Class endpointType = applicationContext.getType(beanName); + Assert.state(endpointType != null, "No type found for bean with name [" + beanName + "]"); endpointType = ClassUtils.getUserClass(endpointType); Set methods = findEndpointMethods(endpointType, new ReflectionUtils.MethodFilter() { @@ -149,7 +155,7 @@ public abstract class AbstractMethodEndpointMapping extends AbstractEndpointM for (Method method : methods) { List keys = getLookupKeysForMethod(method); for (T key : keys) { - registerEndpoint(key, new MethodEndpoint(beanName, getApplicationContext(), method)); + registerEndpoint(key, new MethodEndpoint(beanName, applicationContext, method)); } } @@ -188,7 +194,7 @@ public abstract class AbstractMethodEndpointMapping extends AbstractEndpointM * @return a registration key, or {@code null} if the method is not to be registered * @see #getLookupKeysForMethod(Method) */ - protected T getLookupKeyForMethod(Method method) { + protected @Nullable T getLookupKeyForMethod(Method method) { return null; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/AbstractQNameEndpointMapping.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/AbstractQNameEndpointMapping.java index f03f0837..a0f56425 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/AbstractQNameEndpointMapping.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/AbstractQNameEndpointMapping.java @@ -18,6 +18,8 @@ package org.springframework.ws.server.endpoint.mapping; import javax.xml.namespace.QName; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.context.MessageContext; import org.springframework.xml.namespace.QNameUtils; @@ -31,7 +33,7 @@ import org.springframework.xml.namespace.QNameUtils; public abstract class AbstractQNameEndpointMapping extends AbstractMapBasedEndpointMapping { @Override - protected final String getLookupKeyForMessage(MessageContext messageContext) throws Exception { + protected final @Nullable String getLookupKeyForMessage(MessageContext messageContext) throws Exception { QName qName = resolveQName(messageContext); return (qName != null) ? qName.toString() : null; } @@ -40,7 +42,7 @@ public abstract class AbstractQNameEndpointMapping extends AbstractMapBasedEndpo * Template method that resolves the qualified names from the given SOAP message. * @return an array of qualified names that serve as registration keys */ - protected abstract QName resolveQName(MessageContext messageContext) throws Exception; + protected abstract @Nullable QName resolveQName(MessageContext messageContext) throws Exception; @Override protected boolean validateLookupKey(String key) { diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/PayloadRootAnnotationMethodEndpointMapping.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/PayloadRootAnnotationMethodEndpointMapping.java index 20fb1eaf..c718d36a 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/PayloadRootAnnotationMethodEndpointMapping.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/PayloadRootAnnotationMethodEndpointMapping.java @@ -23,6 +23,8 @@ import java.util.List; import javax.xml.namespace.QName; import javax.xml.transform.TransformerFactory; +import org.jspecify.annotations.Nullable; + import org.springframework.core.annotation.AnnotationUtils; import org.springframework.util.StringUtils; import org.springframework.ws.context.MessageContext; @@ -54,11 +56,7 @@ import org.springframework.xml.transform.TransformerFactoryUtils; */ public class PayloadRootAnnotationMethodEndpointMapping extends AbstractAnnotationMethodEndpointMapping { - private static TransformerFactory transformerFactory; - - static { - setTransformerFactory(TransformerFactoryUtils.newInstance()); - } + private static TransformerFactory transformerFactory = TransformerFactoryUtils.newInstance(); /** * Override the default {@link TransformerFactory}. @@ -69,7 +67,7 @@ public class PayloadRootAnnotationMethodEndpointMapping extends AbstractAnnotati } @Override - protected QName getLookupKeyForMessage(MessageContext messageContext) throws Exception { + protected @Nullable QName getLookupKeyForMessage(MessageContext messageContext) throws Exception { return PayloadRootUtils.getPayloadRootQName(messageContext.getRequest().getPayloadSource(), transformerFactory); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/PayloadRootQNameEndpointMapping.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/PayloadRootQNameEndpointMapping.java index d69bff34..46f67878 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/PayloadRootQNameEndpointMapping.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/PayloadRootQNameEndpointMapping.java @@ -20,6 +20,8 @@ import javax.xml.namespace.QName; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.context.MessageContext; import org.springframework.ws.server.endpoint.support.PayloadRootUtils; import org.springframework.xml.transform.TransformerFactoryUtils; @@ -49,11 +51,7 @@ import org.springframework.xml.transform.TransformerFactoryUtils; */ public class PayloadRootQNameEndpointMapping extends AbstractQNameEndpointMapping { - private static TransformerFactory transformerFactory; - - static { - setTransformerFactory(TransformerFactoryUtils.newInstance()); - } + private static TransformerFactory transformerFactory = TransformerFactoryUtils.newInstance(); /** * Override the default {@link TransformerFactory}. @@ -64,7 +62,7 @@ public class PayloadRootQNameEndpointMapping extends AbstractQNameEndpointMappin } @Override - protected QName resolveQName(MessageContext messageContext) throws TransformerException { + protected @Nullable QName resolveQName(MessageContext messageContext) throws TransformerException { return PayloadRootUtils.getPayloadRootQName(messageContext.getRequest().getPayloadSource(), transformerFactory); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/SimpleMethodEndpointMapping.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/SimpleMethodEndpointMapping.java index ca22934d..e0af54fe 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/SimpleMethodEndpointMapping.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/SimpleMethodEndpointMapping.java @@ -22,6 +22,8 @@ import javax.xml.namespace.QName; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.InitializingBean; import org.springframework.util.Assert; import org.springframework.ws.WebServiceMessage; @@ -42,7 +44,7 @@ import org.springframework.xml.transform.TransformerFactoryUtils; * * public Source handleMyMessage(Source source) { * ... - * } + * } * } * * @@ -61,15 +63,16 @@ public class SimpleMethodEndpointMapping extends AbstractMethodEndpointMapping namespaces; + private @Nullable Map namespaces; - private TransformerFactory transformerFactory; + private final TransformerFactory transformerFactory = TransformerFactoryUtils.newInstance(); /** Sets the XPath expression to be used. */ public void setExpression(String expression) { @@ -94,11 +97,10 @@ public class XPathPayloadEndpointMapping extends AbstractMapBasedEndpointMapping else { this.expression = XPathExpressionFactory.createXPathExpression(this.expressionString, this.namespaces); } - this.transformerFactory = TransformerFactoryUtils.newInstance(); } @Override - protected String getLookupKeyForMessage(MessageContext messageContext) throws Exception { + protected @Nullable String getLookupKeyForMessage(MessageContext messageContext) throws Exception { Element payloadElement = getMessagePayloadElement(messageContext.getRequest()); return this.expression.evaluateAsString(payloadElement); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/jaxb/XmlRootElementEndpointMapping.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/jaxb/XmlRootElementEndpointMapping.java index 4f1b0c8b..311b990c 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/jaxb/XmlRootElementEndpointMapping.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/jaxb/XmlRootElementEndpointMapping.java @@ -25,6 +25,7 @@ import jakarta.xml.bind.JAXBContext; import jakarta.xml.bind.JAXBException; import jakarta.xml.bind.JAXBIntrospector; import jakarta.xml.bind.annotation.XmlRootElement; +import org.jspecify.annotations.Nullable; import org.springframework.core.MethodParameter; import org.springframework.ws.context.MessageContext; @@ -64,7 +65,7 @@ public class XmlRootElementEndpointMapping extends AbstractAnnotationMethodEndpo } @Override - protected QName getLookupKeyForMethod(Method method) { + protected @Nullable QName getLookupKeyForMethod(Method method) { Class[] parameterTypes = method.getParameterTypes(); for (int i = 0; i < parameterTypes.length; i++) { MethodParameter methodParameter = new MethodParameter(method, i); @@ -80,7 +81,7 @@ public class XmlRootElementEndpointMapping extends AbstractAnnotationMethodEndpo return null; } - private QName handleRootElement(Class parameterType) { + private @Nullable QName handleRootElement(Class parameterType) { try { Object param = parameterType.getDeclaredConstructor().newInstance(); QName result = getElementName(parameterType, param); @@ -94,7 +95,7 @@ public class XmlRootElementEndpointMapping extends AbstractAnnotationMethodEndpo return null; } - private QName getElementName(Class parameterType, Object param) { + private @Nullable QName getElementName(Class parameterType, Object param) { try { JAXBContext context = JAXBContext.newInstance(parameterType); JAXBIntrospector introspector = context.createJAXBIntrospector(); @@ -106,7 +107,7 @@ public class XmlRootElementEndpointMapping extends AbstractAnnotationMethodEndpo } @Override - protected QName getLookupKeyForMessage(MessageContext messageContext) throws Exception { + protected @Nullable QName getLookupKeyForMessage(MessageContext messageContext) throws Exception { return PayloadRootUtils.getPayloadRootQName(messageContext.getRequest().getPayloadSource(), this.transformerHelper); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/jaxb/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/jaxb/package-info.java index f4d91caa..ecac9237 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/jaxb/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/jaxb/package-info.java @@ -17,4 +17,7 @@ /** * Provides JAXB2-based {@code EndpointMapping} implementations. */ +@NullMarked package org.springframework.ws.server.endpoint.mapping.jaxb; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/package-info.java index 363c9b60..6aad1919 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/mapping/package-info.java @@ -17,4 +17,7 @@ /** * Provides miscellaneous endpoints {@code EndpointMapping} implementations. */ +@NullMarked package org.springframework.ws.server.endpoint.mapping; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/package-info.java index dd6b6190..d8160c8d 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/package-info.java @@ -17,4 +17,7 @@ /** * Provides standard endpoint, and {@code EndpointAdapter} implementations. */ +@NullMarked package org.springframework.ws.server.endpoint; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/support/PayloadRootUtils.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/support/PayloadRootUtils.java index de6dcc94..6b94060d 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/support/PayloadRootUtils.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/support/PayloadRootUtils.java @@ -30,11 +30,13 @@ import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMResult; +import org.jspecify.annotations.Nullable; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.xml.sax.InputSource; import org.xml.sax.XMLReader; +import org.springframework.lang.Contract; import org.springframework.xml.namespace.QNameUtils; import org.springframework.xml.transform.TransformerHelper; import org.springframework.xml.transform.TraxUtils; @@ -57,12 +59,13 @@ public abstract class PayloadRootUtils { * not a {@code DOMSource} * @return the root element, or {@code null} if {@code source} is {@code null} */ - public static QName getPayloadRootQName(Source source, TransformerFactory transformerFactory) + @Contract("!null, _ -> !null") + public static @Nullable QName getPayloadRootQName(@Nullable Source source, TransformerFactory transformerFactory) throws TransformerException { return getPayloadRootQName(source, new TransformerHelper(transformerFactory)); } - public static QName getPayloadRootQName(Source source, TransformerHelper transformerHelper) + public static @Nullable QName getPayloadRootQName(@Nullable Source source, TransformerHelper transformerHelper) throws TransformerException { if (source == null) { return null; @@ -91,7 +94,7 @@ public abstract class PayloadRootUtils { private static final class PayloadRootSourceCallback implements TraxUtils.SourceCallback { - private QName result; + private @Nullable QName result; @Override public void domSource(Node node) throws Exception { diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/support/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/support/package-info.java index e5592a66..12857fb6 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/support/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/endpoint/support/package-info.java @@ -18,4 +18,7 @@ * Provides helper classes for {@code EndpointAdapter}, {@code EndpointInterceptor}, and * {@code EndpointMapping} implementations. */ +@NullMarked package org.springframework.ws.server.endpoint.support; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/server/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/server/package-info.java index b0785994..d72acf02 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/server/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/server/package-info.java @@ -17,4 +17,7 @@ /** * Contains classes for server-side Spring-WS support. */ +@NullMarked package org.springframework.ws.server; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/AbstractSoapMessage.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/AbstractSoapMessage.java index 90160b67..c8032377 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/AbstractSoapMessage.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/AbstractSoapMessage.java @@ -20,6 +20,8 @@ import javax.xml.namespace.QName; import javax.xml.transform.Result; import javax.xml.transform.Source; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.mime.AbstractMimeMessage; /** @@ -31,7 +33,7 @@ import org.springframework.ws.mime.AbstractMimeMessage; */ public abstract class AbstractSoapMessage extends AbstractMimeMessage implements SoapMessage { - private SoapVersion version; + private @Nullable SoapVersion version; /** Returns {@code getEnvelope().getBody()}. */ @Override @@ -41,13 +43,13 @@ public abstract class AbstractSoapMessage extends AbstractMimeMessage implements /** Returns {@code getEnvelope().getHeader()}. */ @Override - public final SoapHeader getSoapHeader() { + public final @Nullable SoapHeader getSoapHeader() { return getEnvelope().getHeader(); } /** Returns {@code getSoapBody().getPayloadSource()}. */ @Override - public final Source getPayloadSource() { + public final @Nullable Source getPayloadSource() { return getSoapBody().getPayloadSource(); } @@ -65,8 +67,8 @@ public abstract class AbstractSoapMessage extends AbstractMimeMessage implements /** Returns {@code getSoapBody().getFault().getFaultCode()}. */ @Override - public final QName getFaultCode() { - if (hasFault()) { + public final @Nullable QName getFaultCode() { + if (hasFault() && getSoapBody().getFault() != null) { return getSoapBody().getFault().getFaultCode(); } else { @@ -76,8 +78,8 @@ public abstract class AbstractSoapMessage extends AbstractMimeMessage implements /** Returns {@code getSoapBody().getFault().getFaultStringOrReason()}. */ @Override - public final String getFaultReason() { - if (hasFault()) { + public final @Nullable String getFaultReason() { + if (hasFault() && getSoapBody().getFault() != null) { return getSoapBody().getFault().getFaultStringOrReason(); } else { diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/SoapBody.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/SoapBody.java index 22ee5ad4..0d71a7ce 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/SoapBody.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/SoapBody.java @@ -21,6 +21,8 @@ import java.util.Locale; import javax.xml.transform.Result; import javax.xml.transform.Source; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.WebServiceMessage; /** @@ -45,7 +47,7 @@ public interface SoapBody extends SoapElement { * @return the message contents * @see WebServiceMessage#getPayloadSource() */ - Source getPayloadSource(); + @Nullable Source getPayloadSource(); /** * Returns a {@code Result} that represents the contents of the body. @@ -112,6 +114,6 @@ public interface SoapBody extends SoapElement { * Returns the {@code SoapFault} of this body. * @return the {@code SoapFault}, or {@code null} if none is present */ - SoapFault getFault(); + @Nullable SoapFault getFault(); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/SoapEnvelope.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/SoapEnvelope.java index b5e54062..f9e80f22 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/SoapEnvelope.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/SoapEnvelope.java @@ -16,6 +16,8 @@ package org.springframework.ws.soap; +import org.jspecify.annotations.Nullable; + /** * Represents the {@code Envelope} element in a SOAP message. The header contains the * optional {@code SoapHeader} and {@code SoapBody}. @@ -30,7 +32,7 @@ public interface SoapEnvelope extends SoapElement { * @return the {@code SoapHeader}, or {@code null} * @throws SoapHeaderException if the header cannot be returned */ - SoapHeader getHeader() throws SoapHeaderException; + @Nullable SoapHeader getHeader() throws SoapHeaderException; /** * Returns the {@code SoapBody}. diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/SoapFault.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/SoapFault.java index a8d1e396..ac8b4f4e 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/SoapFault.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/SoapFault.java @@ -18,6 +18,8 @@ package org.springframework.ws.soap; import javax.xml.namespace.QName; +import org.jspecify.annotations.Nullable; + /** * Represent the {@code Fault} element in the body of a SOAP message. *

@@ -42,7 +44,7 @@ public interface SoapFault extends SoapElement { * this returns the fault string. For SOAP 1.2, this returns the fault reason for the * default locale. */ - String getFaultStringOrReason(); + @Nullable String getFaultStringOrReason(); /** * Return the optional fault actor or role. For SOAP 1.1, this returns the URI of the @@ -50,7 +52,7 @@ public interface SoapFault extends SoapElement { * identifies the role in which the node was operating at the point the fault * occurred. */ - String getFaultActorOrRole(); + @Nullable String getFaultActorOrRole(); /** * Set the fault actor or role. For SOAP 1.1, this sets the actor. For SOAP 1.2, this @@ -62,7 +64,7 @@ public interface SoapFault extends SoapElement { * Return the optional {@linkplain SoapFaultDetail detail element} of this fault. * @return a fault detail */ - SoapFaultDetail getFaultDetail(); + @Nullable SoapFaultDetail getFaultDetail(); /** * Create a {@link SoapFaultDetail} and assign it to this fault. diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/SoapFaultDetailElement.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/SoapFaultDetailElement.java index 6573dd3b..0a3af070 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/SoapFaultDetailElement.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/SoapFaultDetailElement.java @@ -18,6 +18,8 @@ package org.springframework.ws.soap; import javax.xml.transform.Result; +import org.jspecify.annotations.Nullable; + /** * Represents the content for an individual SOAP detail entry in a SOAP Message. All * {@code SoapFaultDetailElement}s are contained in a {@code SoapDetail}. @@ -35,6 +37,6 @@ public interface SoapFaultDetailElement extends SoapElement { Result getResult(); /** Adds a new text node to this element. */ - void addText(String text); + void addText(@Nullable String text); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/SoapMessage.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/SoapMessage.java index a27140f4..f9f07757 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/SoapMessage.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/SoapMessage.java @@ -16,6 +16,7 @@ package org.springframework.ws.soap; +import org.jspecify.annotations.Nullable; import org.w3c.dom.Document; import org.springframework.ws.FaultAwareWebServiceMessage; @@ -64,7 +65,7 @@ public interface SoapMessage extends MimeMessage, FaultAwareWebServiceMessage { * method for {@code getEnvelope().getHeader()}. * @see SoapEnvelope#getHeader() */ - SoapHeader getSoapHeader() throws SoapHeaderException; + @Nullable SoapHeader getSoapHeader() throws SoapHeaderException; /** * Returns the SOAP version of this message. This can be either SOAP 1.1 or SOAP 1.2. diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/client/ActionCallback.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/client/ActionCallback.java index 338f74b4..8eb4bc9a 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/client/ActionCallback.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/client/ActionCallback.java @@ -22,6 +22,8 @@ import java.net.URISyntaxException; import javax.xml.transform.TransformerException; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; import org.springframework.ws.WebServiceMessage; import org.springframework.ws.client.core.WebServiceMessageCallback; @@ -58,17 +60,17 @@ public class ActionCallback implements WebServiceMessageCallback { private final URI action; - private final URI to; + private @Nullable final URI to; private boolean shouldInitializeTo; private MessageIdStrategy messageIdStrategy; - private EndpointReference from; + private @Nullable EndpointReference from; - private EndpointReference replyTo; + private @Nullable EndpointReference replyTo; - private EndpointReference faultTo; + private @Nullable EndpointReference faultTo; /** * Create a new {@code ActionCallback} with the given {@code Action}. @@ -118,7 +120,7 @@ public class ActionCallback implements WebServiceMessageCallback { * @param version the WS-Addressing version to use * @param to the value of the destination property */ - public ActionCallback(URI action, AddressingVersion version, URI to) { + public ActionCallback(URI action, AddressingVersion version, @Nullable URI to) { Assert.notNull(action, "'action' must not be null"); Assert.notNull(version, "'version' must not be null"); this.action = action; @@ -165,7 +167,7 @@ public class ActionCallback implements WebServiceMessageCallback { * Returns the {@code From}. * @see org.springframework.ws.soap.addressing.core.MessageAddressingProperties#getFrom() */ - public EndpointReference getFrom() { + public @Nullable EndpointReference getFrom() { return this.from; } @@ -181,7 +183,7 @@ public class ActionCallback implements WebServiceMessageCallback { * Returns the {@code ReplyTo}. * @see org.springframework.ws.soap.addressing.core.MessageAddressingProperties#getReplyTo() */ - public EndpointReference getReplyTo() { + public @Nullable EndpointReference getReplyTo() { return this.replyTo; } @@ -197,7 +199,7 @@ public class ActionCallback implements WebServiceMessageCallback { * Returns the {@code FaultTo}. * @see org.springframework.ws.soap.addressing.core.MessageAddressingProperties#getFaultTo() */ - public EndpointReference getFaultTo() { + public @Nullable EndpointReference getFaultTo() { return this.faultTo; } @@ -216,7 +218,7 @@ public class ActionCallback implements WebServiceMessageCallback { * {@link org.springframework.ws.transport.WebServiceConnection#getUri() connection * URI} if no destination was set. */ - protected URI getTo() { + protected @Nullable URI getTo() { if (this.to == null && (isToHeaderRequired() || this.shouldInitializeTo)) { TransportContext transportContext = TransportContextHolder.getTransportContext(); if (transportContext != null && transportContext.getConnection() != null) { diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/client/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/client/package-info.java index ba24782d..3e3e7e59 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/client/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/client/package-info.java @@ -17,4 +17,7 @@ /** * Client-side WS-Addressing support. */ +@NullMarked package org.springframework.ws.soap.addressing.client; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/core/MessageAddressingProperties.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/core/MessageAddressingProperties.java index dbe801bd..60e44726 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/core/MessageAddressingProperties.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/core/MessageAddressingProperties.java @@ -22,6 +22,7 @@ import java.net.URI; import java.util.Collections; import java.util.List; +import org.jspecify.annotations.Nullable; import org.w3c.dom.Node; /** @@ -41,19 +42,19 @@ public final class MessageAddressingProperties implements Serializable { @Serial private static final long serialVersionUID = -6980663311446506672L; - private final URI to; + private final @Nullable URI to; - private final EndpointReference from; + private final @Nullable EndpointReference from; - private final EndpointReference replyTo; + private final @Nullable EndpointReference replyTo; - private final EndpointReference faultTo; + private final @Nullable EndpointReference faultTo; - private final URI action; + private final @Nullable URI action; - private final URI messageId; + private final @Nullable URI messageId; - private final URI relatesTo; + private final @Nullable URI relatesTo; private final List referenceProperties; @@ -68,8 +69,9 @@ public final class MessageAddressingProperties implements Serializable { * @param action the value of the action property * @param messageId the value of the message id property */ - public MessageAddressingProperties(URI to, EndpointReference from, EndpointReference replyTo, - EndpointReference faultTo, URI action, URI messageId) { + public MessageAddressingProperties(@Nullable URI to, @Nullable EndpointReference from, + @Nullable EndpointReference replyTo, @Nullable EndpointReference faultTo, @Nullable URI action, + @Nullable URI messageId) { this.to = to; this.from = from; this.replyTo = replyTo; @@ -89,7 +91,8 @@ public final class MessageAddressingProperties implements Serializable { * @param messageId the value of the message id property * @param relatesTo the value of the relates to property */ - private MessageAddressingProperties(EndpointReference epr, URI action, URI messageId, URI relatesTo) { + private MessageAddressingProperties(EndpointReference epr, @Nullable URI action, URI messageId, + @Nullable URI relatesTo) { this.to = epr.getAddress(); this.action = action; this.messageId = messageId; @@ -102,37 +105,37 @@ public final class MessageAddressingProperties implements Serializable { } /** Returns the value of the destination property. */ - public URI getTo() { + public @Nullable URI getTo() { return this.to; } /** Returns the value of the source endpoint property. */ - public EndpointReference getFrom() { + public @Nullable EndpointReference getFrom() { return this.from; } /** Returns the value of the reply endpoint property. */ - public EndpointReference getReplyTo() { + public @Nullable EndpointReference getReplyTo() { return this.replyTo; } /** Returns the value of the fault endpoint property. */ - public EndpointReference getFaultTo() { + public @Nullable EndpointReference getFaultTo() { return this.faultTo; } /** Returns the value of the action property. */ - public URI getAction() { + public @Nullable URI getAction() { return this.action; } /** Returns the value of the message id property. */ - public URI getMessageId() { + public @Nullable URI getMessageId() { return this.messageId; } /** Returns the value of the relationship property. */ - public URI getRelatesTo() { + public @Nullable URI getRelatesTo() { return this.relatesTo; } @@ -156,7 +159,7 @@ public final class MessageAddressingProperties implements Serializable { * @param epr the endpoint reference to create a reply to * @param action the action */ - public MessageAddressingProperties getReplyProperties(EndpointReference epr, URI action, URI messageId) { + public MessageAddressingProperties getReplyProperties(EndpointReference epr, @Nullable URI action, URI messageId) { return new MessageAddressingProperties(epr, action, messageId, this.messageId); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/core/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/core/package-info.java index 6c6b6ea0..7463316f 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/core/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/core/package-info.java @@ -18,4 +18,7 @@ * Core package for WS-Addressing support. Contains the {@code EndpointReference} and * {@code MessageAddressingProperties} classes. */ +@NullMarked package org.springframework.ws.soap.addressing.core; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/messageid/MessageIdStrategy.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/messageid/MessageIdStrategy.java index 585304b4..dd784ec2 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/messageid/MessageIdStrategy.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/messageid/MessageIdStrategy.java @@ -18,6 +18,8 @@ package org.springframework.ws.soap.addressing.messageid; import java.net.URI; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.soap.SoapMessage; /** @@ -34,7 +36,7 @@ public interface MessageIdStrategy { * @param messageId the message id * @return {@code true} if a duplicate; {@code false} otherwise */ - boolean isDuplicate(URI messageId); + boolean isDuplicate(@Nullable URI messageId); /** * Returns a new WS-Addressing {@code MessageID} for the given {@link SoapMessage}. diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/messageid/UuidMessageIdStrategy.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/messageid/UuidMessageIdStrategy.java index 0ef9a09d..4d446262 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/messageid/UuidMessageIdStrategy.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/messageid/UuidMessageIdStrategy.java @@ -19,6 +19,8 @@ package org.springframework.ws.soap.addressing.messageid; import java.net.URI; import java.util.UUID; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.soap.SoapMessage; /** @@ -39,7 +41,7 @@ public class UuidMessageIdStrategy implements MessageIdStrategy { /** Returns {@code false}. */ @Override - public boolean isDuplicate(URI messageId) { + public boolean isDuplicate(@Nullable URI messageId) { return false; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/messageid/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/messageid/package-info.java index 6b7b2f81..09684a9b 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/messageid/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/messageid/package-info.java @@ -17,4 +17,7 @@ /** * Contains various strategies for generating WS-Addressing MessageIDs. */ +@NullMarked package org.springframework.ws.soap.addressing.messageid; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/package-info.java index d5ae6d0a..64a7f85e 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/package-info.java @@ -17,4 +17,7 @@ /** * Provides WS-Addressing implementation classes. */ +@NullMarked package org.springframework.ws.soap.addressing; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/server/AbstractActionEndpointMapping.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/server/AbstractActionEndpointMapping.java index 7e6042c4..b2b3bbae 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/server/AbstractActionEndpointMapping.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/server/AbstractActionEndpointMapping.java @@ -20,6 +20,8 @@ import java.net.URI; import java.util.HashMap; import java.util.Map; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.BeansException; import org.springframework.util.Assert; import org.springframework.ws.soap.addressing.core.MessageAddressingProperties; @@ -81,7 +83,7 @@ public abstract class AbstractActionEndpointMapping extends AbstractAddressingEn } @Override - protected final Object getEndpointInternal(MessageAddressingProperties map) { + protected final @Nullable Object getEndpointInternal(MessageAddressingProperties map) { URI action = map.getAction(); if (this.logger.isDebugEnabled()) { this.logger.debug("Looking up endpoint for action [" + action + "]"); @@ -103,14 +105,14 @@ public abstract class AbstractActionEndpointMapping extends AbstractAddressingEn * @param endpoint the endpoint to return the address for * @return the endpoint address; or {@code null} to ignore the destination property */ - protected abstract URI getEndpointAddress(Object endpoint); + protected abstract @Nullable URI getEndpointAddress(Object endpoint); /** * Looks up an endpoint instance for the given action. All keys are tried in order. * @param action the action URI * @return the associated endpoint instance, or {@code null} if not found */ - protected Object lookupEndpoint(URI action) { + protected @Nullable Object lookupEndpoint(@Nullable URI action) { return this.endpointMap.get(action); } @@ -149,7 +151,7 @@ public abstract class AbstractActionEndpointMapping extends AbstractAddressingEn } @Override - protected URI getResponseAction(Object endpoint, MessageAddressingProperties requestMap) { + protected @Nullable URI getResponseAction(Object endpoint, MessageAddressingProperties requestMap) { URI requestAction = requestMap.getAction(); if (requestAction != null) { return URI.create(requestAction + getOutputActionSuffix()); @@ -160,7 +162,7 @@ public abstract class AbstractActionEndpointMapping extends AbstractAddressingEn } @Override - protected URI getFaultAction(Object endpoint, MessageAddressingProperties requestMap) { + protected @Nullable URI getFaultAction(Object endpoint, MessageAddressingProperties requestMap) { URI requestAction = requestMap.getAction(); if (requestAction != null) { return URI.create(requestAction + getFaultActionSuffix()); diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/server/AbstractActionMethodEndpointMapping.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/server/AbstractActionMethodEndpointMapping.java index 6d6c9a9f..74149706 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/server/AbstractActionMethodEndpointMapping.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/server/AbstractActionMethodEndpointMapping.java @@ -19,6 +19,8 @@ package org.springframework.ws.soap.addressing.server; import java.lang.reflect.Method; import java.net.URI; +import org.jspecify.annotations.Nullable; + import org.springframework.aop.support.AopUtils; import org.springframework.util.Assert; import org.springframework.ws.server.endpoint.MethodEndpoint; @@ -57,7 +59,7 @@ public abstract class AbstractActionMethodEndpointMapping extends AbstractAction } /** Returns the action value for the specified method. */ - protected abstract URI getActionForMethod(Method method); + protected abstract @Nullable URI getActionForMethod(Method method); /** * Return the class or interface to use for method reflection. diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/server/AbstractAddressingEndpointMapping.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/server/AbstractAddressingEndpointMapping.java index d55ea3e1..f980a352 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/server/AbstractAddressingEndpointMapping.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/server/AbstractAddressingEndpointMapping.java @@ -25,6 +25,8 @@ import java.util.Map; import javax.xml.transform.TransformerException; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.InitializingBean; @@ -84,7 +86,7 @@ import org.springframework.xml.transform.TransformerObjectSupport; public abstract class AbstractAddressingEndpointMapping extends TransformerObjectSupport implements SoapEndpointMapping, ApplicationContextAware, InitializingBean, Ordered { - private String[] actorsOrRoles; + private String @Nullable [] actorsOrRoles; private boolean isUltimateReceiver = true; @@ -100,22 +102,17 @@ public abstract class AbstractAddressingEndpointMapping extends TransformerObjec private SmartEndpointInterceptor[] smartInterceptors = new SmartEndpointInterceptor[0]; - private ApplicationContext applicationContext; + private @Nullable ApplicationContext applicationContext; private int order = Integer.MAX_VALUE; // default: same as non-Ordered - /** Protected constructor. Initializes the default settings. */ - protected AbstractAddressingEndpointMapping() { - initDefaultStrategies(); - } - /** - * Initializes the default implementation for this mapping's strategies: the + * Create a new instance with the default strategies, that is the * {@link org.springframework.ws.soap.addressing.version.Addressing200408} and * {@link org.springframework.ws.soap.addressing.version.Addressing10} versions of the * specification, and the {@link UuidMessageIdStrategy}. */ - protected void initDefaultStrategies() { + protected AbstractAddressingEndpointMapping() { this.versions = new AddressingVersion[] { new Addressing200408(), new Addressing10() }; this.messageIdStrategy = new UuidMessageIdStrategy(); } @@ -138,6 +135,7 @@ public abstract class AbstractAddressingEndpointMapping extends TransformerObjec } public ApplicationContext getApplicationContext() { + Assert.state(this.applicationContext != null, "No ApplicationContext set"); return this.applicationContext; } @@ -243,17 +241,16 @@ public abstract class AbstractAddressingEndpointMapping extends TransformerObjec if (this.logger.isInfoEnabled()) { this.logger.info("Supporting " + Arrays.asList(this.versions)); } - if (getApplicationContext() != null) { - Map smartInterceptors = BeanFactoryUtils - .beansOfTypeIncludingAncestors(getApplicationContext(), SmartEndpointInterceptor.class, true, false); - if (!smartInterceptors.isEmpty()) { - this.smartInterceptors = smartInterceptors.values().toArray(new SmartEndpointInterceptor[0]); - } + Map smartInterceptors = BeanFactoryUtils + .beansOfTypeIncludingAncestors(getApplicationContext(), SmartEndpointInterceptor.class, true, false); + if (!smartInterceptors.isEmpty()) { + this.smartInterceptors = smartInterceptors.values().toArray(new SmartEndpointInterceptor[0]); } } @Override - public final EndpointInvocationChain getEndpoint(MessageContext messageContext) throws TransformerException { + public final @Nullable EndpointInvocationChain getEndpoint(MessageContext messageContext) + throws TransformerException { Assert.isInstanceOf(SoapMessage.class, messageContext.getRequest()); SoapMessage request = (SoapMessage) messageContext.getRequest(); for (AddressingVersion version : this.versions) { @@ -262,9 +259,6 @@ public abstract class AbstractAddressingEndpointMapping extends TransformerObjec this.logger.debug("Request [" + request + "] uses [" + version + "]"); } MessageAddressingProperties requestMap = version.getMessageAddressingProperties(request); - if (requestMap == null) { - return null; - } Object endpoint = getEndpointInternal(requestMap); if (endpoint == null) { return null; @@ -294,11 +288,9 @@ public abstract class AbstractAddressingEndpointMapping extends TransformerObjec interceptors.add(addressingInterceptor); interceptors.addAll(Arrays.asList(this.postInterceptors)); - if (this.smartInterceptors != null) { - for (SmartEndpointInterceptor smartInterceptor : this.smartInterceptors) { - if (smartInterceptor.shouldIntercept(messageContext, endpoint)) { - interceptors.add(smartInterceptor); - } + for (SmartEndpointInterceptor smartInterceptor : this.smartInterceptors) { + if (smartInterceptor.shouldIntercept(messageContext, endpoint)) { + interceptors.add(smartInterceptor); } } @@ -346,7 +338,7 @@ public abstract class AbstractAddressingEndpointMapping extends TransformerObjec * @param map the message addressing properties * @return the endpoint, or {@code null} */ - protected abstract Object getEndpointInternal(MessageAddressingProperties map); + protected abstract @Nullable Object getEndpointInternal(MessageAddressingProperties map); /** * Provides the WS-Addressing Action for response messages, given the endpoint, and @@ -355,7 +347,7 @@ public abstract class AbstractAddressingEndpointMapping extends TransformerObjec * @param requestMap the MAP for the request * @return the response Action */ - protected abstract URI getResponseAction(Object endpoint, MessageAddressingProperties requestMap); + protected abstract @Nullable URI getResponseAction(Object endpoint, MessageAddressingProperties requestMap); /** * Provides the WS-Addressing Action for response fault messages, given the endpoint, @@ -364,6 +356,6 @@ public abstract class AbstractAddressingEndpointMapping extends TransformerObjec * @param requestMap the MAP for the request * @return the response Action */ - protected abstract URI getFaultAction(Object endpoint, MessageAddressingProperties requestMap); + protected abstract @Nullable URI getFaultAction(Object endpoint, MessageAddressingProperties requestMap); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/server/AddressingEndpointInterceptor.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/server/AddressingEndpointInterceptor.java index 1e479393..925d1504 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/server/AddressingEndpointInterceptor.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/server/AddressingEndpointInterceptor.java @@ -21,7 +21,9 @@ import java.net.URI; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; +import org.springframework.lang.Contract; import org.springframework.util.Assert; import org.springframework.ws.context.MessageContext; import org.springframework.ws.soap.SoapHeaderElement; @@ -51,12 +53,12 @@ class AddressingEndpointInterceptor implements SoapEndpointInterceptor { private final WebServiceMessageSender[] messageSenders; - private final URI replyAction; + private final @Nullable URI replyAction; - private final URI faultAction; + private final @Nullable URI faultAction; AddressingEndpointInterceptor(AddressingVersion version, MessageIdStrategy messageIdStrategy, - WebServiceMessageSender[] messageSenders, URI replyAction, URI faultAction) { + WebServiceMessageSender[] messageSenders, @Nullable URI replyAction, @Nullable URI faultAction) { Assert.notNull(version, "version must not be null"); Assert.notNull(messageIdStrategy, "messageIdStrategy must not be null"); Assert.notNull(messageSenders, "'messageSenders' must not be null"); @@ -116,7 +118,8 @@ class AddressingEndpointInterceptor implements SoapEndpointInterceptor { } } - private boolean handleNoneAddress(MessageContext messageContext, EndpointReference replyEpr) { + @Contract("_, null -> true") + private boolean handleNoneAddress(MessageContext messageContext, @Nullable EndpointReference replyEpr) { if (replyEpr == null || this.version.hasNoneAddress(replyEpr)) { if (logger.isDebugEnabled()) { logger.debug("Request [" + messageContext.getRequest() + "] has [" + replyEpr @@ -173,7 +176,7 @@ class AddressingEndpointInterceptor implements SoapEndpointInterceptor { } @Override - public void afterCompletion(MessageContext messageContext, Object endpoint, Exception ex) { + public void afterCompletion(MessageContext messageContext, Object endpoint, @Nullable Exception ex) { } @Override diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/server/AnnotationActionEndpointMapping.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/server/AnnotationActionEndpointMapping.java index 5ef29a8f..b3fc6046 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/server/AnnotationActionEndpointMapping.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/server/AnnotationActionEndpointMapping.java @@ -21,6 +21,8 @@ import java.lang.reflect.Method; import java.net.URI; import java.net.URISyntaxException; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.SmartInitializingSingleton; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.util.StringUtils; @@ -72,7 +74,7 @@ public class AnnotationActionEndpointMapping extends AbstractActionMethodEndpoin * the {@link Action} annotation value. */ @Override - protected URI getActionForMethod(Method method) { + protected @Nullable URI getActionForMethod(Method method) { Action action = method.getAnnotation(Action.class); if (action != null && StringUtils.hasText(action.value())) { try { @@ -96,7 +98,7 @@ public class AnnotationActionEndpointMapping extends AbstractActionMethodEndpoin * @return the endpoint address; or {@code null} to ignore the destination property */ @Override - protected URI getEndpointAddress(Object endpoint) { + protected @Nullable URI getEndpointAddress(Object endpoint) { MethodEndpoint methodEndpoint = (MethodEndpoint) endpoint; Class endpointClass = methodEndpoint.getMethod().getDeclaringClass(); Address address = AnnotationUtils.findAnnotation(endpointClass, Address.class); @@ -109,7 +111,7 @@ public class AnnotationActionEndpointMapping extends AbstractActionMethodEndpoin } @Override - protected URI getResponseAction(Object endpoint, MessageAddressingProperties map) { + protected @Nullable URI getResponseAction(Object endpoint, MessageAddressingProperties map) { MethodEndpoint methodEndpoint = (MethodEndpoint) endpoint; Action action = methodEndpoint.getMethod().getAnnotation(Action.class); if (action != null && StringUtils.hasText(action.output())) { @@ -121,7 +123,7 @@ public class AnnotationActionEndpointMapping extends AbstractActionMethodEndpoin } @Override - protected URI getFaultAction(Object endpoint, MessageAddressingProperties map) { + protected @Nullable URI getFaultAction(Object endpoint, MessageAddressingProperties map) { MethodEndpoint methodEndpoint = (MethodEndpoint) endpoint; Action action = methodEndpoint.getMethod().getAnnotation(Action.class); if (action != null && StringUtils.hasText(action.fault())) { diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/server/SimpleActionEndpointMapping.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/server/SimpleActionEndpointMapping.java index fb65455f..a9f18745 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/server/SimpleActionEndpointMapping.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/server/SimpleActionEndpointMapping.java @@ -22,6 +22,8 @@ import java.util.HashMap; import java.util.Map; import java.util.Properties; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.BeansException; /** @@ -57,7 +59,7 @@ public class SimpleActionEndpointMapping extends AbstractActionEndpointMapping { // contents will be copied over to endpointMap private final Map actionMap = new HashMap<>(); - private URI address; + private @Nullable URI address; /** * Map action URIs to endpoint bean names. This is the typical way of configuring this @@ -132,7 +134,7 @@ public class SimpleActionEndpointMapping extends AbstractActionEndpointMapping { } @Override - protected URI getEndpointAddress(Object endpoint) { + protected @Nullable URI getEndpointAddress(Object endpoint) { return this.address; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/server/annotation/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/server/annotation/package-info.java index 81884c7b..9fed797f 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/server/annotation/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/server/annotation/package-info.java @@ -17,4 +17,7 @@ /** * Annotations for server-side WS-Addressing support. */ +@NullMarked package org.springframework.ws.soap.addressing.server.annotation; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/server/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/server/package-info.java index ace69c89..6e039f44 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/server/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/server/package-info.java @@ -17,4 +17,7 @@ /** * Server-side WS-Addressing support, in the form of {@code EndpointMappings}. */ +@NullMarked package org.springframework.ws.soap.addressing.server; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/version/AbstractAddressingVersion.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/version/AbstractAddressingVersion.java index d895e46b..f07f1a1b 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/version/AbstractAddressingVersion.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/version/AbstractAddressingVersion.java @@ -34,10 +34,12 @@ import javax.xml.transform.TransformerException; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.dom.DOMSource; +import org.jspecify.annotations.Nullable; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; +import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.ws.soap.SoapFault; import org.springframework.ws.soap.SoapHeader; @@ -80,9 +82,9 @@ public abstract class AbstractAddressingVersion extends TransformerObjectSupport private final XPathExpression addressExpression; - private final XPathExpression referencePropertiesExpression; + private final @Nullable XPathExpression referencePropertiesExpression; - private final XPathExpression referenceParametersExpression; + private final @Nullable XPathExpression referenceParametersExpression; protected AbstractAddressingVersion() { Map namespaces = new HashMap<>(); @@ -144,7 +146,7 @@ public abstract class AbstractAddressingVersion extends TransformerObjectSupport return new MessageAddressingProperties(to, from, replyTo, faultTo, action, messageId); } - private URI getUri(Node node, XPathExpression expression) { + private @Nullable URI getUri(Node node, XPathExpression expression) { String messageId = expression.evaluateAsString(node); if (!StringUtils.hasLength(messageId)) { return null; @@ -158,7 +160,9 @@ public abstract class AbstractAddressingVersion extends TransformerObjectSupport } private Element getSoapHeaderElement(SoapMessage message) { - Source source = message.getSoapHeader().getSource(); + SoapHeader soapHeader = message.getSoapHeader(); + Assert.notNull(soapHeader, "'soapHeader' must not be null"); + Source source = soapHeader.getSource(); if (source instanceof DOMSource domSource) { if (domSource.getNode() != null && domSource.getNode().getNodeType() == Node.ELEMENT_NODE) { return (Element) domSource.getNode(); @@ -176,7 +180,7 @@ public abstract class AbstractAddressingVersion extends TransformerObjectSupport } /** Given a ReplyTo, FaultTo, or From node, returns an endpoint reference. */ - private EndpointReference getEndpointReference(Node node) { + private @Nullable EndpointReference getEndpointReference(@Nullable Node node) { if (node == null) { return null; } @@ -193,7 +197,7 @@ public abstract class AbstractAddressingVersion extends TransformerObjectSupport @Override public void addAddressingHeaders(SoapMessage message, MessageAddressingProperties map) { - SoapHeader header = message.getSoapHeader(); + SoapHeader header = getSoapHeader(message); header.addNamespaceDeclaration(getNamespacePrefix(), getNamespaceUri()); // To if (map.getTo() != null) { @@ -217,7 +221,9 @@ public abstract class AbstractAddressingVersion extends TransformerObjectSupport } // Action SoapHeaderElement action = header.addHeaderElement(getActionName()); - action.setText(map.getAction().toString()); + if (map.getAction() != null) { + action.setText((map.getAction().toString())); + } // MessageID if (map.getMessageId() != null) { SoapHeaderElement messageId = header.addHeaderElement(getMessageIdName()); @@ -238,8 +244,8 @@ public abstract class AbstractAddressingVersion extends TransformerObjectSupport } /** Adds ReplyTo, FaultTo, or From EPR to the given header Element. */ - protected void addEndpointReference(SoapHeaderElement headerElement, EndpointReference epr) { - if (epr == null || epr.getAddress() == null) { + protected void addEndpointReference(SoapHeaderElement headerElement, @Nullable EndpointReference epr) { + if (epr == null) { return; } try { @@ -282,18 +288,18 @@ public abstract class AbstractAddressingVersion extends TransformerObjectSupport } @Override - public final SoapFault addInvalidAddressingHeaderFault(SoapMessage message) { + public final @Nullable SoapFault addInvalidAddressingHeaderFault(SoapMessage message) { return addAddressingFault(message, getInvalidAddressingHeaderFaultSubcode(), getInvalidAddressingHeaderFaultReason()); } @Override - public final SoapFault addMessageAddressingHeaderRequiredFault(SoapMessage message) { + public final @Nullable SoapFault addMessageAddressingHeaderRequiredFault(SoapMessage message) { return addAddressingFault(message, getMessageAddressingHeaderRequiredFaultSubcode(), getMessageAddressingHeaderRequiredFaultReason()); } - private SoapFault addAddressingFault(SoapMessage message, QName subcode, String reason) { + private @Nullable SoapFault addAddressingFault(SoapMessage message, QName subcode, String reason) { if (message.getSoapBody() instanceof Soap11Body soapBody) { return soapBody.addFault(subcode, reason, Locale.ENGLISH); } @@ -379,7 +385,7 @@ public abstract class AbstractAddressingVersion extends TransformerObjectSupport * reference. Returns {@code null} when reference properties are not supported by this * version of the spec. */ - protected QName getReferencePropertiesName() { + protected @Nullable QName getReferencePropertiesName() { return new QName(getNamespaceUri(), "ReferenceProperties", getNamespacePrefix()); } @@ -388,7 +394,7 @@ public abstract class AbstractAddressingVersion extends TransformerObjectSupport * reference. Returns {@code null} when reference parameters are not supported by this * version of the spec. */ - protected QName getReferenceParametersName() { + protected @Nullable QName getReferenceParametersName() { return new QName(getNamespaceUri(), "ReferenceParameters", getNamespacePrefix()); } @@ -402,23 +408,23 @@ public abstract class AbstractAddressingVersion extends TransformerObjectSupport } /** Returns the default To URI. */ - protected abstract URI getDefaultTo(); + protected abstract @Nullable URI getDefaultTo(); /** * Returns the default ReplyTo EPR. Can be based on the From EPR, or the anonymous * URI. */ - protected abstract EndpointReference getDefaultReplyTo(EndpointReference from); + protected abstract @Nullable EndpointReference getDefaultReplyTo(@Nullable EndpointReference from); /* * Address URIs */ /** Returns the anonymous URI. */ - protected abstract URI getAnonymous(); + protected abstract @Nullable URI getAnonymous(); /** Returns the none URI, or {@code null} if the spec does not define it. */ - protected abstract URI getNone(); + protected abstract @Nullable URI getNone(); /* * Faults @@ -442,4 +448,10 @@ public abstract class AbstractAddressingVersion extends TransformerObjectSupport /** Returns the reason of the fault that indicates that a header is invalid. */ protected abstract String getInvalidAddressingHeaderFaultReason(); + private static SoapHeader getSoapHeader(SoapMessage message) { + SoapHeader soapHeader = message.getSoapHeader(); + Assert.notNull(soapHeader, "'soapHeader' must not be null"); + return soapHeader; + } + } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/version/Addressing10.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/version/Addressing10.java index bf6952c0..4e4c8050 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/version/Addressing10.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/version/Addressing10.java @@ -20,6 +20,8 @@ import java.net.URI; import javax.xml.namespace.QName; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; import org.springframework.ws.soap.SoapMessage; import org.springframework.ws.soap.addressing.core.EndpointReference; @@ -68,7 +70,7 @@ public class Addressing10 extends AbstractAddressingVersion { } @Override - protected QName getReferencePropertiesName() { + protected @Nullable QName getReferencePropertiesName() { return null; } @@ -78,7 +80,7 @@ public class Addressing10 extends AbstractAddressingVersion { } @Override - protected EndpointReference getDefaultReplyTo(EndpointReference from) { + protected EndpointReference getDefaultReplyTo(@Nullable EndpointReference from) { return new EndpointReference(getAnonymous()); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/version/Addressing200408.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/version/Addressing200408.java index b59830de..c7632217 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/version/Addressing200408.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/version/Addressing200408.java @@ -20,6 +20,8 @@ import java.net.URI; import javax.xml.namespace.QName; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; import org.springframework.ws.soap.SoapMessage; import org.springframework.ws.soap.addressing.core.EndpointReference; @@ -97,17 +99,17 @@ public class Addressing200408 extends AbstractAddressingVersion { } @Override - protected URI getDefaultTo() { + protected @Nullable URI getDefaultTo() { return null; } @Override - protected final EndpointReference getDefaultReplyTo(EndpointReference from) { + protected final @Nullable EndpointReference getDefaultReplyTo(@Nullable EndpointReference from) { return from; } @Override - protected final URI getNone() { + protected final @Nullable URI getNone() { return null; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/version/AddressingVersion.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/version/AddressingVersion.java index 57cbf0b2..fc52a278 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/version/AddressingVersion.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/version/AddressingVersion.java @@ -16,6 +16,8 @@ package org.springframework.ws.soap.addressing.version; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.soap.SoapFault; import org.springframework.ws.soap.SoapHeaderElement; import org.springframework.ws.soap.SoapMessage; @@ -99,13 +101,13 @@ public interface AddressingVersion { * @see Invalid * Addressing Header */ - SoapFault addInvalidAddressingHeaderFault(SoapMessage message); + @Nullable SoapFault addInvalidAddressingHeaderFault(SoapMessage message); /** * Adds a Message Addressing Header Required fault to the given message. * @see Message * Addressing Header Required */ - SoapFault addMessageAddressingHeaderRequiredFault(SoapMessage message); + @Nullable SoapFault addMessageAddressingHeaderRequiredFault(SoapMessage message); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/version/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/version/package-info.java index 58abc6f8..b3693231 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/version/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/addressing/version/package-info.java @@ -17,4 +17,7 @@ /** * Contains abstractions over various versions of the WS-Addressing specification. */ +@NullMarked package org.springframework.ws.soap.addressing.version; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AbstractPayload.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AbstractPayload.java index 0834911a..180988e0 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AbstractPayload.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AbstractPayload.java @@ -24,6 +24,7 @@ import org.apache.axiom.om.OMElement; import org.apache.axiom.om.OMException; import org.apache.axiom.soap.SOAPBody; import org.apache.axiom.soap.SOAPFactory; +import org.jspecify.annotations.Nullable; import org.springframework.util.Assert; import org.springframework.util.xml.StaxUtils; @@ -49,7 +50,7 @@ abstract class AbstractPayload extends Payload { } @Override - public final Source getSource() { + public final @Nullable Source getSource() { try { OMElement payloadElement = getPayloadElement(); if (payloadElement != null) { @@ -83,7 +84,7 @@ abstract class AbstractPayload extends Payload { return this.axiomBody; } - protected OMElement getPayloadElement() throws OMException { + protected @Nullable OMElement getPayloadElement() throws OMException { return getAxiomBody().getFirstElement(); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoap11Body.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoap11Body.java index 11877674..af641309 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoap11Body.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoap11Body.java @@ -29,6 +29,7 @@ import org.apache.axiom.soap.SOAPFault; import org.apache.axiom.soap.SOAPFaultCode; import org.apache.axiom.soap.SOAPFaultReason; import org.apache.axiom.soap.SOAPProcessingException; +import org.jspecify.annotations.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -123,7 +124,7 @@ class AxiomSoap11Body extends AxiomSoapBody implements Soap11Body { faultCode.setText(code); } - private SOAPFault addStandardFault(String localName, String faultString, Locale locale) { + private SOAPFault addStandardFault(String localName, String faultString, @Nullable Locale locale) { Assert.notNull(faultString, "No faultString given"); try { AxiomUtils.removeContents(getAxiomBody()); @@ -151,7 +152,7 @@ class AxiomSoap11Body extends AxiomSoapBody implements Soap11Body { } @Override - public Soap11Fault getFault() { + public @Nullable Soap11Fault getFault() { SOAPFault axiomFault = getAxiomBody().getFault(); return (axiomFault != null) ? new AxiomSoap11Fault(axiomFault, getAxiomFactory()) : null; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoap11Fault.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoap11Fault.java index 3fbd4bce..1db43a3c 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoap11Fault.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoap11Fault.java @@ -23,6 +23,7 @@ import javax.xml.namespace.QName; import org.apache.axiom.om.OMAttribute; import org.apache.axiom.soap.SOAPFactory; import org.apache.axiom.soap.SOAPFault; +import org.jspecify.annotations.Nullable; import org.springframework.ws.soap.axiom.support.AxiomUtils; import org.springframework.ws.soap.soap11.Soap11Fault; @@ -45,7 +46,7 @@ class AxiomSoap11Fault extends AxiomSoapFault implements Soap11Fault { } @Override - public String getFaultStringOrReason() { + public @Nullable String getFaultStringOrReason() { if (getAxiomFault().getReason() != null) { return getAxiomFault().getReason().getText(); } @@ -53,7 +54,7 @@ class AxiomSoap11Fault extends AxiomSoapFault implements Soap11Fault { } @Override - public Locale getFaultStringLocale() { + public @Nullable Locale getFaultStringLocale() { if (getAxiomFault().getReason() != null) { OMAttribute langAttribute = getAxiomFault().getReason() .getAttribute(new QName("http://www.w3.org/XML/1998/namespace", "lang")); diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoap11Header.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoap11Header.java index 349b3d3a..e2495a06 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoap11Header.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoap11Header.java @@ -24,6 +24,7 @@ import org.apache.axiom.soap.RolePlayer; import org.apache.axiom.soap.SOAPFactory; import org.apache.axiom.soap.SOAPHeader; import org.apache.axiom.soap.SOAPHeaderBlock; +import org.jspecify.annotations.Nullable; import org.springframework.util.ObjectUtils; import org.springframework.ws.soap.SoapHeaderElement; @@ -43,7 +44,7 @@ class AxiomSoap11Header extends AxiomSoapHeader implements Soap11Header { @Override @SuppressWarnings("unchecked") - public Iterator examineHeaderElementsToProcess(final String[] actors) { + public Iterator examineHeaderElementsToProcess(final String @Nullable [] actors) { RolePlayer rolePlayer = null; if (!ObjectUtils.isEmpty(actors)) { rolePlayer = new RolePlayer() { diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoap12Body.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoap12Body.java index 90e9824f..3e957085 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoap12Body.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoap12Body.java @@ -29,6 +29,7 @@ import org.apache.axiom.soap.SOAPFaultReason; import org.apache.axiom.soap.SOAPFaultText; import org.apache.axiom.soap.SOAPFaultValue; import org.apache.axiom.soap.SOAPProcessingException; +import org.jspecify.annotations.Nullable; import org.springframework.util.Assert; import org.springframework.ws.soap.axiom.support.AxiomUtils; @@ -82,7 +83,7 @@ class AxiomSoap12Body extends AxiomSoapBody implements Soap12Body { return new AxiomSoap12Fault(fault, getAxiomFactory()); } - private SOAPFault addStandardFault(String localName, String faultStringOrReason, Locale locale) { + private SOAPFault addStandardFault(String localName, String faultStringOrReason, @Nullable Locale locale) { Assert.notNull(faultStringOrReason, "No faultStringOrReason given"); try { AxiomUtils.removeContents(getAxiomBody()); @@ -104,7 +105,7 @@ class AxiomSoap12Body extends AxiomSoapBody implements Soap12Body { } @Override - public Soap12Fault getFault() { + public @Nullable Soap12Fault getFault() { SOAPFault axiomFault = getAxiomBody().getFault(); return (axiomFault != null) ? new AxiomSoap12Fault(axiomFault, getAxiomFactory()) : null; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoap12Fault.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoap12Fault.java index 0d12b808..06269ca0 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoap12Fault.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoap12Fault.java @@ -33,6 +33,7 @@ import org.apache.axiom.soap.SOAPFaultSubCode; import org.apache.axiom.soap.SOAPFaultText; import org.apache.axiom.soap.SOAPFaultValue; import org.apache.axiom.soap.SOAPProcessingException; +import org.jspecify.annotations.Nullable; import org.springframework.util.StringUtils; import org.springframework.ws.soap.axiom.support.AxiomUtils; @@ -107,7 +108,7 @@ class AxiomSoap12Fault extends AxiomSoapFault implements Soap12Fault { } @Override - public String getFaultNode() { + public @Nullable String getFaultNode() { SOAPFaultNode faultNode = getAxiomFault().getNode(); if (faultNode == null) { return null; @@ -130,12 +131,12 @@ class AxiomSoap12Fault extends AxiomSoapFault implements Soap12Fault { } @Override - public String getFaultStringOrReason() { + public @Nullable String getFaultStringOrReason() { return getFaultReasonText(Locale.getDefault()); } @Override - public String getFaultReasonText(Locale locale) { + public @Nullable String getFaultReasonText(Locale locale) { SOAPFaultReason faultReason = getAxiomFault().getReason(); String language = AxiomUtils.toLanguage(locale); SOAPFaultText faultText = faultReason.getSOAPFaultText(language); diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoap12Header.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoap12Header.java index 3cc97ac9..1fe442e7 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoap12Header.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoap12Header.java @@ -30,6 +30,7 @@ import org.apache.axiom.soap.SOAPFactory; import org.apache.axiom.soap.SOAPHeader; import org.apache.axiom.soap.SOAPHeaderBlock; import org.apache.axiom.soap.SOAPProcessingException; +import org.jspecify.annotations.Nullable; import org.springframework.util.ObjectUtils; import org.springframework.ws.soap.SoapHeaderElement; @@ -81,8 +82,7 @@ class AxiomSoap12Header extends AxiomSoapHeader implements Soap12Header { } @Override - @SuppressWarnings("unchecked") - public Iterator examineHeaderElementsToProcess(final String[] roles, + public Iterator examineHeaderElementsToProcess(final String @Nullable [] roles, final boolean isUltimateDestination) throws SoapHeaderException { RolePlayer rolePlayer = null; if (!ObjectUtils.isEmpty(roles)) { @@ -97,7 +97,7 @@ class AxiomSoap12Header extends AxiomSoapHeader implements Soap12Header { } }; } - Iterator result = (Iterator) getAxiomHeader().getHeadersToProcess(rolePlayer); + Iterator result = getAxiomHeader().getHeadersToProcess(rolePlayer); return new AxiomSoapHeaderElementIterator(result); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapBody.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapBody.java index 4e9f6b53..c9125954 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapBody.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapBody.java @@ -24,6 +24,7 @@ import org.apache.axiom.om.OMDataSource; import org.apache.axiom.om.OMElement; import org.apache.axiom.soap.SOAPBody; import org.apache.axiom.soap.SOAPFactory; +import org.jspecify.annotations.Nullable; import org.springframework.util.Assert; import org.springframework.ws.soap.SoapBody; @@ -51,7 +52,7 @@ abstract class AxiomSoapBody extends AxiomSoapElement implements SoapBody { } @Override - public Source getPayloadSource() { + public @Nullable Source getPayloadSource() { return this.payload.getSource(); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapEnvelope.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapEnvelope.java index 22d8da6f..f5407d5b 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapEnvelope.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapEnvelope.java @@ -23,6 +23,7 @@ import org.apache.axiom.soap.SOAPBody; import org.apache.axiom.soap.SOAPEnvelope; import org.apache.axiom.soap.SOAPFactory; import org.apache.axiom.soap.SOAPHeader; +import org.jspecify.annotations.Nullable; import org.springframework.ws.soap.SoapBody; import org.springframework.ws.soap.SoapEnvelope; @@ -38,10 +39,10 @@ class AxiomSoapEnvelope extends AxiomSoapElement implements SoapEnvelope { boolean payloadCaching; - private AxiomSoapBody body; - private final boolean langAttributeOnSoap11FaultString; + private @Nullable AxiomSoapBody body; + AxiomSoapEnvelope(SOAPEnvelope axiomEnvelope, SOAPFactory axiomFactory, boolean payloadCaching, boolean langAttributeOnSoap11FaultString) { super(axiomEnvelope, axiomFactory); @@ -50,7 +51,7 @@ class AxiomSoapEnvelope extends AxiomSoapElement implements SoapEnvelope { } @Override - public SoapHeader getHeader() { + public @Nullable SoapHeader getHeader() { try { if (getAxiomEnvelope().getHeader() == null) { return null; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapFault.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapFault.java index 7a86d2d6..f405c133 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapFault.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapFault.java @@ -22,6 +22,7 @@ import org.apache.axiom.soap.SOAPFault; import org.apache.axiom.soap.SOAPFaultDetail; import org.apache.axiom.soap.SOAPFaultRole; import org.apache.axiom.soap.SOAPProcessingException; +import org.jspecify.annotations.Nullable; import org.springframework.ws.soap.SoapFault; import org.springframework.ws.soap.SoapFaultDetail; @@ -38,7 +39,7 @@ abstract class AxiomSoapFault extends AxiomSoapElement implements SoapFault { } @Override - public String getFaultActorOrRole() { + public @Nullable String getFaultActorOrRole() { SOAPFaultRole faultRole = getAxiomFault().getRole(); return (faultRole != null) ? faultRole.getRoleValue() : null; } @@ -56,7 +57,7 @@ abstract class AxiomSoapFault extends AxiomSoapElement implements SoapFault { } @Override - public SoapFaultDetail getFaultDetail() { + public @Nullable SoapFaultDetail getFaultDetail() { try { SOAPFaultDetail axiomFaultDetail = getAxiomFault().getDetail(); return (axiomFaultDetail != null) ? new AxiomSoapFaultDetail(axiomFaultDetail, getAxiomFactory()) : null; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapFaultDetailElement.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapFaultDetailElement.java index b24cac28..ad0de01b 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapFaultDetailElement.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapFaultDetailElement.java @@ -21,6 +21,7 @@ import javax.xml.transform.Result; import org.apache.axiom.om.OMElement; import org.apache.axiom.om.OMException; import org.apache.axiom.soap.SOAPFactory; +import org.jspecify.annotations.Nullable; import org.springframework.ws.soap.SoapFaultDetailElement; @@ -48,7 +49,7 @@ class AxiomSoapFaultDetailElement extends AxiomSoapElement implements SoapFaultD } @Override - public void addText(String text) { + public void addText(@Nullable String text) { try { getAxiomElement().setText(text); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapMessage.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapMessage.java index 862d050f..66b4f001 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapMessage.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapMessage.java @@ -40,6 +40,7 @@ import org.apache.axiom.soap.SOAPEnvelope; import org.apache.axiom.soap.SOAPFactory; import org.apache.axiom.soap.SOAPMessage; import org.apache.axiom.soap.SOAPProcessingException; +import org.jspecify.annotations.Nullable; import org.w3c.dom.Document; import org.springframework.util.Assert; @@ -76,13 +77,13 @@ public class AxiomSoapMessage extends AbstractSoapMessage implements StreamingWe private final boolean payloadCaching; - private AxiomSoapEnvelope envelope; + private @Nullable AxiomSoapEnvelope envelope; private String soapAction; private final boolean langAttributeOnSoap11FaultString; - private OMOutputFormat outputFormat; + private @Nullable OMOutputFormat outputFormat; /** * Create a new, empty {@code AxiomSoapMessage}. @@ -237,7 +238,7 @@ public class AxiomSoapMessage extends AbstractSoapMessage implements StreamingWe } @Override - public Attachment getAttachment(String contentId) { + public @Nullable Attachment getAttachment(String contentId) { Assert.hasLength(contentId, "contentId must not be empty"); if (contentId.startsWith("<") && contentId.endsWith(">")) { contentId = contentId.substring(1, contentId.length() - 1); diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapMessageFactory.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapMessageFactory.java index eb124884..28d81de5 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapMessageFactory.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapMessageFactory.java @@ -37,6 +37,7 @@ import org.apache.axiom.soap.SOAPModelBuilder; import org.apache.axiom.soap.SOAPVersion; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.beans.factory.InitializingBean; import org.springframework.util.Assert; @@ -95,12 +96,13 @@ public class AxiomSoapMessageFactory implements SoapMessageFactory, Initializing private static final Log logger = LogFactory.getLog(AxiomSoapMessageFactory.class); - private XMLInputFactory inputFactory; + private @Nullable XMLInputFactory inputFactory; private boolean payloadCaching = true; private boolean attachmentCaching = false; + @SuppressWarnings("NullAway.Init") private File attachmentCacheDir; private int attachmentCacheThreshold = 4096; @@ -263,7 +265,8 @@ public class AxiomSoapMessageFactory implements SoapMessageFactory, Initializing } } - private String getHeaderValue(TransportInputStream transportInputStream, String header) throws IOException { + private @Nullable String getHeaderValue(TransportInputStream transportInputStream, String header) + throws IOException { String contentType = null; Iterator iterator = transportInputStream.getHeaders(header); if (iterator.hasNext()) { diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/NonCachingPayload.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/NonCachingPayload.java index 2573c50b..1c90cc95 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/NonCachingPayload.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/NonCachingPayload.java @@ -33,7 +33,9 @@ import org.apache.axiom.om.ds.BlobOMDataSource; import org.apache.axiom.om.util.StAXUtils; import org.apache.axiom.soap.SOAPBody; import org.apache.axiom.soap.SOAPFactory; +import org.jspecify.annotations.Nullable; +import org.springframework.util.Assert; import org.springframework.util.xml.StaxUtils; /** @@ -67,7 +69,7 @@ class NonCachingPayload extends AbstractPayload { private final XMLStreamWriter delegate; - private QName name; + private @Nullable QName name; private String encoding = "UTF-8"; @@ -138,6 +140,7 @@ class NonCachingPayload extends AbstractPayload { if (this.elementDepth <= 0 && !this.payloadAdded) { this.delegate.flush(); if (this.baos.size() > 0) { + Assert.notNull(this.name, "name is required"); byte[] buf = this.baos.toByteArray(); OMDataSource dataSource = new BlobOMDataSource(Blobs.createBlob(buf), this.encoding); OMNamespace namespace = getAxiomFactory().createOMNamespace(this.name.getNamespaceURI(), diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/Payload.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/Payload.java index 677b1f08..b8ad42b2 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/Payload.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/Payload.java @@ -19,6 +19,8 @@ package org.springframework.ws.soap.axiom; import javax.xml.transform.Result; import javax.xml.transform.Source; +import org.jspecify.annotations.Nullable; + /** * Defines the contract for payloads in Axiom. * @@ -31,7 +33,7 @@ abstract class Payload { * Returns the source of the payload. * @return the source of the payload */ - public abstract Source getSource(); + public abstract @Nullable Source getSource(); /** * Returns the result of the payload. diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/package-info.java index a156b9cc..038e2b2d 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/package-info.java @@ -17,4 +17,7 @@ /** * AXis Object Model (AXIOM) support for Spring-WS soap message infrastructure. */ +@NullMarked package org.springframework.ws.soap.axiom; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/support/AxiomUtils.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/support/AxiomUtils.java index 28bd3523..2c5c6412 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/support/AxiomUtils.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/support/AxiomUtils.java @@ -32,6 +32,7 @@ import org.apache.axiom.om.OMNamespace; import org.apache.axiom.om.OMOutputFormat; import org.apache.axiom.om.OMXMLBuilderFactory; import org.apache.axiom.soap.SOAPEnvelope; +import org.jspecify.annotations.Nullable; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -91,7 +92,7 @@ public abstract class AxiomUtils { * @param language the language string * @return the locale */ - public static Locale toLocale(String language) { + public static @Nullable Locale toLocale(String language) { language = language.replace('-', '_'); return StringUtils.parseLocaleString(language); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/support/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/support/package-info.java index e491c047..7be978c7 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/support/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/axiom/support/package-info.java @@ -17,4 +17,7 @@ /** * Support classes for working with the AXis Object Model (AXIOM). */ +@NullMarked package org.springframework.ws.soap.axiom.support; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/client/SoapFaultClientException.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/client/SoapFaultClientException.java index 238500b4..6025d2b2 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/client/SoapFaultClientException.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/client/SoapFaultClientException.java @@ -18,6 +18,8 @@ package org.springframework.ws.soap.client; import javax.xml.namespace.QName; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.client.WebServiceFaultException; import org.springframework.ws.soap.SoapBody; import org.springframework.ws.soap.SoapFault; @@ -32,7 +34,7 @@ import org.springframework.ws.soap.SoapMessage; @SuppressWarnings("serial") public class SoapFaultClientException extends WebServiceFaultException { - private final SoapFault soapFault; + private final @Nullable SoapFault soapFault; /** * Create a new instance of the {@code SoapFaultClientException} class. @@ -41,16 +43,16 @@ public class SoapFaultClientException extends WebServiceFaultException { public SoapFaultClientException(SoapMessage faultMessage) { super(faultMessage); SoapBody body = faultMessage.getSoapBody(); - this.soapFault = (body != null) ? body.getFault() : null; + this.soapFault = body.getFault(); } /** Returns the {@link SoapFault}. */ - public SoapFault getSoapFault() { + public @Nullable SoapFault getSoapFault() { return this.soapFault; } /** Returns the fault code. */ - public QName getFaultCode() { + public @Nullable QName getFaultCode() { return (this.soapFault != null) ? this.soapFault.getFaultCode() : null; } @@ -60,7 +62,7 @@ public class SoapFaultClientException extends WebServiceFaultException { *

* Note that this message returns the same as {@link #getMessage()}. */ - public String getFaultStringOrReason() { + public @Nullable String getFaultStringOrReason() { return (this.soapFault != null) ? this.soapFault.getFaultStringOrReason() : null; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/client/core/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/client/core/package-info.java index 885a7b6a..ed6d4451 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/client/core/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/client/core/package-info.java @@ -17,4 +17,7 @@ /** * Contains core classes for SOAP-specific client-side Spring-WS support. */ +@NullMarked package org.springframework.ws.soap.client.core; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/client/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/client/package-info.java index 2efa83a9..80df23f8 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/client/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/client/package-info.java @@ -17,4 +17,7 @@ /** * Contains classes for SOAP-specific client-side Spring-WS support. */ +@NullMarked package org.springframework.ws.soap.client; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/package-info.java index 841975f3..eb10aa3f 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/package-info.java @@ -18,4 +18,7 @@ * Provides the SOAP functionality of the Spring Web Services framework. Contains the * SoapMessage and related interfaces. */ +@NullMarked package org.springframework.ws.soap; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoap11Body.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoap11Body.java index 53bd2c51..de60db28 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoap11Body.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoap11Body.java @@ -23,6 +23,7 @@ import javax.xml.namespace.QName; import jakarta.xml.soap.SOAPBody; import jakarta.xml.soap.SOAPException; import jakarta.xml.soap.SOAPFault; +import org.jspecify.annotations.Nullable; import org.springframework.util.Assert; import org.springframework.ws.soap.SoapVersion; @@ -46,7 +47,7 @@ class SaajSoap11Body extends SaajSoapBody implements Soap11Body { } @Override - public Soap11Fault getFault() { + public @Nullable Soap11Fault getFault() { SOAPFault fault = getSaajBody().getFault(); return (fault != null) ? new SaajSoap11Fault(fault) : null; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoap11Header.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoap11Header.java index bb86f066..18a4ba5d 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoap11Header.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoap11Header.java @@ -23,6 +23,7 @@ import java.util.List; import jakarta.xml.soap.SOAPConstants; import jakarta.xml.soap.SOAPHeader; import jakarta.xml.soap.SOAPHeaderElement; +import org.jspecify.annotations.Nullable; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; @@ -43,8 +44,7 @@ class SaajSoap11Header extends SaajSoapHeader implements Soap11Header { } @Override - @SuppressWarnings("unchecked") - public Iterator examineHeaderElementsToProcess(String[] actors) { + public Iterator examineHeaderElementsToProcess(String @Nullable [] actors) { List result = new ArrayList<>(); Iterator iterator = getSaajHeader().examineAllHeaderElements(); while (iterator.hasNext()) { @@ -57,7 +57,7 @@ class SaajSoap11Header extends SaajSoapHeader implements Soap11Header { return new SaajSoapHeaderElementIterator(result.iterator()); } - private boolean shouldProcess(String headerActor, String[] actors) { + private boolean shouldProcess(String headerActor, String @Nullable [] actors) { if (!StringUtils.hasLength(headerActor)) { return true; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoap12Body.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoap12Body.java index 8e4f5b27..cbdb1052 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoap12Body.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoap12Body.java @@ -23,6 +23,7 @@ import javax.xml.namespace.QName; import jakarta.xml.soap.SOAPBody; import jakarta.xml.soap.SOAPException; import jakarta.xml.soap.SOAPFault; +import org.jspecify.annotations.Nullable; import org.springframework.util.Assert; import org.springframework.ws.soap.SoapVersion; @@ -43,7 +44,7 @@ class SaajSoap12Body extends SaajSoapBody implements Soap12Body { } @Override - public Soap12Fault getFault() { + public @Nullable Soap12Fault getFault() { SOAPFault fault = getSaajBody().getFault(); return (fault != null) ? new SaajSoap12Fault(fault) : null; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoap12Header.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoap12Header.java index 11a45535..c61921e3 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoap12Header.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoap12Header.java @@ -26,6 +26,7 @@ import jakarta.xml.soap.SOAPConstants; import jakarta.xml.soap.SOAPException; import jakarta.xml.soap.SOAPHeader; import jakarta.xml.soap.SOAPHeaderElement; +import org.jspecify.annotations.Nullable; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; @@ -69,9 +70,8 @@ class SaajSoap12Header extends SaajSoapHeader implements Soap12Header { } @Override - @SuppressWarnings("unchecked") - public Iterator examineHeaderElementsToProcess(String[] roles, boolean isUltimateDestination) - throws SoapHeaderException { + public Iterator examineHeaderElementsToProcess(String @Nullable [] roles, + boolean isUltimateDestination) throws SoapHeaderException { List result = new ArrayList<>(); Iterator iterator = getSaajHeader().examineAllHeaderElements(); while (iterator.hasNext()) { @@ -85,7 +85,7 @@ class SaajSoap12Header extends SaajSoapHeader implements Soap12Header { } - private boolean shouldProcess(String headerRole, String[] roles, boolean isUltimateDestination) { + private boolean shouldProcess(String headerRole, String @Nullable [] roles, boolean isUltimateDestination) { if (!StringUtils.hasLength(headerRole)) { return true; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapBody.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapBody.java index 54f0b5a6..4563a6be 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapBody.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapBody.java @@ -23,6 +23,7 @@ import javax.xml.transform.dom.DOMSource; import jakarta.xml.soap.SOAPBody; import jakarta.xml.soap.SOAPElement; +import org.jspecify.annotations.Nullable; import org.springframework.ws.soap.SoapBody; import org.springframework.ws.soap.saaj.support.SaajUtils; @@ -41,7 +42,7 @@ abstract class SaajSoapBody extends SaajSoapElement implements SoapBod } @Override - public Source getPayloadSource() { + public @Nullable Source getPayloadSource() { SOAPElement bodyElement = SaajUtils.getFirstBodyElement(getSaajBody()); return (bodyElement != null) ? new DOMSource(bodyElement) : null; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapEnvelope.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapEnvelope.java index b09f9147..19f723c0 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapEnvelope.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapEnvelope.java @@ -20,6 +20,7 @@ import jakarta.xml.soap.SOAPBody; import jakarta.xml.soap.SOAPEnvelope; import jakarta.xml.soap.SOAPException; import jakarta.xml.soap.SOAPHeader; +import org.jspecify.annotations.Nullable; import org.springframework.ws.soap.SoapBody; import org.springframework.ws.soap.SoapEnvelope; @@ -35,9 +36,9 @@ import org.springframework.ws.soap.SoapVersion; */ class SaajSoapEnvelope extends SaajSoapElement implements SoapEnvelope { - private SaajSoapBody body; + private @Nullable SaajSoapBody body; - private SaajSoapHeader header; + private @Nullable SaajSoapHeader header; private final boolean langAttributeOnSoap11FaultString; @@ -71,7 +72,7 @@ class SaajSoapEnvelope extends SaajSoapElement implements SoapEnve } @Override - public SoapHeader getHeader() { + public @Nullable SoapHeader getHeader() { if (this.header == null) { try { SOAPHeader saajHeader = getSaajEnvelope().getHeader(); diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapFault.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapFault.java index 02aea8b5..cfed35f2 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapFault.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapFault.java @@ -21,6 +21,7 @@ import javax.xml.namespace.QName; import jakarta.xml.soap.Detail; import jakarta.xml.soap.SOAPException; import jakarta.xml.soap.SOAPFault; +import org.jspecify.annotations.Nullable; import org.springframework.ws.soap.SoapFault; import org.springframework.ws.soap.SoapFaultDetail; @@ -48,7 +49,7 @@ abstract class SaajSoapFault extends SaajSoapElement implements SoapF } @Override - public SoapFaultDetail getFaultDetail() { + public @Nullable SoapFaultDetail getFaultDetail() { Detail saajDetail = getSaajFault().getDetail(); return (saajDetail != null) ? new SaajSoapFaultDetail(saajDetail) : null; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapFaultDetailElement.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapFaultDetailElement.java index 73777f9d..36df57ab 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapFaultDetailElement.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapFaultDetailElement.java @@ -21,6 +21,7 @@ import javax.xml.transform.dom.DOMResult; import jakarta.xml.soap.DetailEntry; import jakarta.xml.soap.SOAPException; +import org.jspecify.annotations.Nullable; import org.springframework.ws.soap.SoapFaultDetailElement; @@ -43,7 +44,7 @@ class SaajSoapFaultDetailElement extends SaajSoapElement implements } @Override - public void addText(String text) { + public void addText(@Nullable String text) { try { getSaajDetailEntry().addTextNode(text); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapMessage.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapMessage.java index 450b3cd3..c682c227 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapMessage.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapMessage.java @@ -33,6 +33,7 @@ import jakarta.xml.soap.SOAPEnvelope; import jakarta.xml.soap.SOAPException; import jakarta.xml.soap.SOAPMessage; import jakarta.xml.soap.SOAPPart; +import org.jspecify.annotations.Nullable; import org.w3c.dom.DOMImplementation; import org.w3c.dom.Document; import org.w3c.dom.ls.DOMImplementationLS; @@ -65,11 +66,11 @@ public class SaajSoapMessage extends AbstractSoapMessage { private static final String CONTENT_TYPE_XOP = "application/xop+xml"; - private final MessageFactory messageFactory; + private final @Nullable MessageFactory messageFactory; private SOAPMessage saajMessage; - private SoapEnvelope envelope; + private @Nullable SoapEnvelope envelope; private final boolean langAttributeOnSoap11FaultString; @@ -108,7 +109,7 @@ public class SaajSoapMessage extends AbstractSoapMessage { * @param messageFactory the message factory */ public SaajSoapMessage(SOAPMessage soapMessage, boolean langAttributeOnSoap11FaultString, - MessageFactory messageFactory) { + @Nullable MessageFactory messageFactory) { Assert.notNull(soapMessage, "soapMessage must not be null"); this.saajMessage = soapMessage; this.langAttributeOnSoap11FaultString = langAttributeOnSoap11FaultString; @@ -311,15 +312,13 @@ public class SaajSoapMessage extends AbstractSoapMessage { } @Override - @SuppressWarnings("unchecked") public Iterator getAttachments() throws AttachmentException { Iterator iterator = getSaajMessage().getAttachments(); return new SaajAttachmentIterator(iterator); } @Override - @SuppressWarnings("unchecked") - public Attachment getAttachment(String contentId) { + public @Nullable Attachment getAttachment(String contentId) { Assert.hasLength(contentId, "contentId must not be empty"); MimeHeaders mimeHeaders = new MimeHeaders(); mimeHeaders.setHeader(TransportConstants.HEADER_CONTENT_ID, contentId); diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapMessageFactory.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapMessageFactory.java index d6b09163..fc70651b 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapMessageFactory.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapMessageFactory.java @@ -31,9 +31,11 @@ import jakarta.xml.soap.SOAPException; import jakarta.xml.soap.SOAPMessage; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.xml.sax.SAXParseException; import org.springframework.beans.factory.InitializingBean; +import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; @@ -67,13 +69,14 @@ public class SaajSoapMessageFactory implements SoapMessageFactory, InitializingB private static final Log logger = LogFactory.getLog(SaajSoapMessageFactory.class); - private MessageFactory messageFactory; + private @Nullable MessageFactory messageFactory; + @SuppressWarnings("NullAway.Init") private String messageFactoryProtocol; private boolean langAttributeOnSoap11FaultString = true; - private Map messageProperties; + private @Nullable Map messageProperties; /** Default, empty constructor. */ public SaajSoapMessageFactory() { @@ -86,6 +89,7 @@ public class SaajSoapMessageFactory implements SoapMessageFactory, InitializingB /** Returns the SAAJ {@code MessageFactory} used. */ public MessageFactory getMessageFactory() { + Assert.state(this.messageFactory != null, "'messageFactory' is required"); return this.messageFactory; } @@ -138,51 +142,55 @@ public class SaajSoapMessageFactory implements SoapMessageFactory, InitializingB @Override public void afterPropertiesSet() { if (this.messageFactory == null) { - try { - if (SaajUtils.getSaajVersion() >= SaajUtils.SAAJ_13) { - if (!StringUtils.hasLength(this.messageFactoryProtocol)) { - this.messageFactoryProtocol = SOAPConstants.SOAP_1_1_PROTOCOL; - } - if (logger.isInfoEnabled()) { - logger.info("Creating SAAJ 1.3 MessageFactory with " + this.messageFactoryProtocol); - } - this.messageFactory = MessageFactory.newInstance(this.messageFactoryProtocol); - } - else if (SaajUtils.getSaajVersion() == SaajUtils.SAAJ_12) { - logger.info("Creating SAAJ 1.2 MessageFactory"); - this.messageFactory = MessageFactory.newInstance(); - } - else if (SaajUtils.getSaajVersion() == SaajUtils.SAAJ_11) { - logger.info("Creating SAAJ 1.1 MessageFactory"); - this.messageFactory = MessageFactory.newInstance(); - } - else { - throw new IllegalStateException( - "SaajSoapMessageFactory requires SAAJ 1.1, which was not found on the classpath"); - } - } - catch (NoSuchMethodError ex) { - throw new SoapMessageCreationException( - "Could not create SAAJ MessageFactory. Is the version of the SAAJ specification interfaces [" - + SaajUtils.getSaajVersionString() - + "] the same as the version supported by the application server?", - ex); - } - catch (SOAPException ex) { - throw new SoapMessageCreationException("Could not create SAAJ MessageFactory: " + ex.getMessage(), ex); - } + this.messageFactory = initializeMessageFactory(); } if (logger.isDebugEnabled()) { logger.debug("Using MessageFactory class [" + this.messageFactory.getClass().getName() + "]"); } } + private MessageFactory initializeMessageFactory() { + try { + if (SaajUtils.getSaajVersion() >= SaajUtils.SAAJ_13) { + if (!StringUtils.hasLength(this.messageFactoryProtocol)) { + this.messageFactoryProtocol = SOAPConstants.SOAP_1_1_PROTOCOL; + } + if (logger.isInfoEnabled()) { + logger.info("Creating SAAJ 1.3 MessageFactory with " + this.messageFactoryProtocol); + } + return MessageFactory.newInstance(this.messageFactoryProtocol); + } + else if (SaajUtils.getSaajVersion() == SaajUtils.SAAJ_12) { + logger.info("Creating SAAJ 1.2 MessageFactory"); + return MessageFactory.newInstance(); + } + else if (SaajUtils.getSaajVersion() == SaajUtils.SAAJ_11) { + logger.info("Creating SAAJ 1.1 MessageFactory"); + return MessageFactory.newInstance(); + } + else { + throw new IllegalStateException( + "SaajSoapMessageFactory requires SAAJ 1.1, which was not found on the classpath"); + } + } + catch (NoSuchMethodError ex) { + throw new SoapMessageCreationException( + "Could not create SAAJ MessageFactory. Is the version of the SAAJ specification interfaces [" + + SaajUtils.getSaajVersionString() + + "] the same as the version supported by the application server?", + ex); + } + catch (SOAPException ex) { + throw new SoapMessageCreationException("Could not create SAAJ MessageFactory: " + ex.getMessage(), ex); + } + } + @Override public SaajSoapMessage createWebServiceMessage() { try { - SOAPMessage saajMessage = this.messageFactory.createMessage(); + SOAPMessage saajMessage = getMessageFactory().createMessage(); postProcess(saajMessage); - return new SaajSoapMessage(saajMessage, this.langAttributeOnSoap11FaultString, this.messageFactory); + return new SaajSoapMessage(saajMessage, this.langAttributeOnSoap11FaultString, getMessageFactory()); } catch (SOAPException ex) { throw new SoapMessageCreationException("Could not create empty message: " + ex.getMessage(), ex); @@ -194,7 +202,7 @@ public class SaajSoapMessageFactory implements SoapMessageFactory, InitializingB MimeHeaders mimeHeaders = parseMimeHeaders(inputStream); try { inputStream = checkForUtf8ByteOrderMark(inputStream); - SOAPMessage saajMessage = this.messageFactory.createMessage(mimeHeaders, inputStream); + SOAPMessage saajMessage = getMessageFactory().createMessage(mimeHeaders, inputStream); saajMessage.getSOAPPart().getEnvelope(); postProcess(saajMessage); return new SaajSoapMessage(saajMessage, this.langAttributeOnSoap11FaultString, this.messageFactory); @@ -209,7 +217,7 @@ public class SaajSoapMessageFactory implements SoapMessageFactory, InitializingB contentType = contentType.replace("startinfo", "start-info"); mimeHeaders.setHeader(TransportConstants.HEADER_CONTENT_TYPE, contentType); try { - SOAPMessage saajMessage = this.messageFactory.createMessage(mimeHeaders, inputStream); + SOAPMessage saajMessage = getMessageFactory().createMessage(mimeHeaders, inputStream); postProcess(saajMessage); return new SaajSoapMessage(saajMessage, this.langAttributeOnSoap11FaultString); } @@ -228,7 +236,7 @@ public class SaajSoapMessageFactory implements SoapMessageFactory, InitializingB } } - private SAXParseException getSAXParseException(Throwable ex) { + private @Nullable SAXParseException getSAXParseException(Throwable ex) { if (ex instanceof SAXParseException) { return (SAXParseException) ex; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/package-info.java index 85eafc98..e8ab44d5 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/package-info.java @@ -18,4 +18,7 @@ * SOAP with Attachments API for Java (SAAJ) support for Spring-WS soap message * infrastructure. */ +@NullMarked package org.springframework.ws.soap.saaj; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/support/SaajContentHandler.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/support/SaajContentHandler.java index c1a3e336..c26876b0 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/support/SaajContentHandler.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/support/SaajContentHandler.java @@ -23,6 +23,7 @@ import jakarta.xml.soap.Name; import jakarta.xml.soap.SOAPElement; import jakarta.xml.soap.SOAPEnvelope; import jakarta.xml.soap.SOAPException; +import org.jspecify.annotations.Nullable; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.Locator; @@ -59,7 +60,9 @@ public class SaajContentHandler implements ContentHandler { this.envelope = (SOAPEnvelope) element; } else { - this.envelope = SaajUtils.getEnvelope(element); + SOAPEnvelope elementEnvelope = SaajUtils.getEnvelope(element); + Assert.notNull(elementEnvelope, "Could not determine SOAP envelope from " + element); + this.envelope = elementEnvelope; } this.element = element; } @@ -163,7 +166,7 @@ public class SaajContentHandler implements ContentHandler { public void skippedEntity(String name) throws SAXException { } - private String getPrefix(String qName) { + private @Nullable String getPrefix(String qName) { int idx = qName.indexOf(':'); if (idx != -1) { return qName.substring(0, idx); diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/support/SaajUtils.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/support/SaajUtils.java index eddc499e..ca09899e 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/support/SaajUtils.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/support/SaajUtils.java @@ -30,6 +30,7 @@ import jakarta.xml.soap.SOAPElement; import jakarta.xml.soap.SOAPEnvelope; import jakarta.xml.soap.SOAPException; import jakarta.xml.soap.SOAPMessage; +import org.jspecify.annotations.Nullable; import org.springframework.core.io.Resource; import org.springframework.util.Assert; @@ -136,6 +137,7 @@ public abstract class SaajUtils { public static Name toName(QName qName, SOAPElement resolveElement) throws SOAPException { String qNamePrefix = qName.getPrefix(); SOAPEnvelope envelope = getEnvelope(resolveElement); + Assert.notNull(envelope, "SOAPEnvelope must not be null"); if (StringUtils.hasLength(qName.getNamespaceURI()) && StringUtils.hasLength(qNamePrefix)) { return envelope.createName(qName.getLocalPart(), qNamePrefix, qName.getNamespaceURI()); } @@ -201,7 +203,7 @@ public abstract class SaajUtils { * @param element the element to return the envelope from * @return the envelope, or {@code null} if not found */ - public static SOAPEnvelope getEnvelope(SOAPElement element) { + public static @Nullable SOAPEnvelope getEnvelope(SOAPElement element) { Assert.notNull(element, "Element should not be null"); do { if (element instanceof SOAPEnvelope) { @@ -216,7 +218,7 @@ public abstract class SaajUtils { /** * Returns the first child element of the given body. */ - public static SOAPElement getFirstBodyElement(SOAPBody body) { + public static @Nullable SOAPElement getFirstBodyElement(SOAPBody body) { for (Iterator iterator = body.getChildElements(); iterator.hasNext();) { Object child = iterator.next(); if (child instanceof SOAPElement) { diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/support/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/support/package-info.java index 2fd98c10..cb1db780 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/support/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/saaj/support/package-info.java @@ -17,4 +17,7 @@ /** * Support classes for working with the SOAP with Attachments API for Java (SAAJ). */ +@NullMarked package org.springframework.ws.soap.saaj.support; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/SoapEndpointInvocationChain.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/SoapEndpointInvocationChain.java index 1625cb9b..c348eee9 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/SoapEndpointInvocationChain.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/SoapEndpointInvocationChain.java @@ -16,6 +16,8 @@ package org.springframework.ws.soap.server; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.server.EndpointInterceptor; import org.springframework.ws.server.EndpointInvocationChain; @@ -31,7 +33,7 @@ import org.springframework.ws.server.EndpointInvocationChain; */ public class SoapEndpointInvocationChain extends EndpointInvocationChain { - private String[] actorsOrRoles; + private String @Nullable [] actorsOrRoles; private boolean isUltimateReceiver = true; @@ -48,7 +50,7 @@ public class SoapEndpointInvocationChain extends EndpointInvocationChain { * @param endpoint the endpoint object to invoke * @param interceptors the array of interceptors to apply */ - public SoapEndpointInvocationChain(Object endpoint, EndpointInterceptor[] interceptors) { + public SoapEndpointInvocationChain(Object endpoint, EndpointInterceptor @Nullable [] interceptors) { super(endpoint, interceptors); } @@ -60,8 +62,8 @@ public class SoapEndpointInvocationChain extends EndpointInvocationChain { * @param isUltimateReceiver whether this chain fullfils the SOAP 1.2 Ultimate * receiver role */ - public SoapEndpointInvocationChain(Object endpoint, EndpointInterceptor[] interceptors, String[] actorsOrRoles, - boolean isUltimateReceiver) { + public SoapEndpointInvocationChain(Object endpoint, EndpointInterceptor @Nullable [] interceptors, + String @Nullable [] actorsOrRoles, boolean isUltimateReceiver) { super(endpoint, interceptors); this.actorsOrRoles = actorsOrRoles; this.isUltimateReceiver = isUltimateReceiver; @@ -72,7 +74,7 @@ public class SoapEndpointInvocationChain extends EndpointInvocationChain { * this chain and its contained interceptors and endpoint. * @return a string array of URIs for SOAP actors/roles */ - public String[] getActorsOrRoles() { + public String @Nullable [] getActorsOrRoles() { return this.actorsOrRoles; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/SoapMessageDispatcher.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/SoapMessageDispatcher.java index d45c2165..b784b1b8 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/SoapMessageDispatcher.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/SoapMessageDispatcher.java @@ -23,6 +23,8 @@ import java.util.Locale; import javax.xml.namespace.QName; +import org.jspecify.annotations.Nullable; + import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import org.springframework.ws.context.MessageContext; @@ -100,7 +102,7 @@ public class SoapMessageDispatcher extends MessageDispatcher { } private boolean handleHeaders(EndpointInvocationChain mappedEndpoint, MessageContext messageContext, - String[] actorsOrRoles, boolean isUltimateReceiver) { + String @Nullable [] actorsOrRoles, boolean isUltimateReceiver) { SoapMessage soapRequest = (SoapMessage) messageContext.getRequest(); SoapHeader soapHeader = soapRequest.getSoapHeader(); if (soapHeader == null) { @@ -158,7 +160,7 @@ public class SoapMessageDispatcher extends MessageDispatcher { } private void createMustUnderstandFault(SoapMessage soapResponse, List notUnderstoodHeaderNames, - String[] actorsOrRoles) { + String @Nullable [] actorsOrRoles) { if (this.logger.isWarnEnabled()) { this.logger.warn("Could not handle mustUnderstand headers: " + StringUtils.collectionToCommaDelimitedString(notUnderstoodHeaderNames) + ". Returning fault"); diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/AbstractSoapFaultDefinitionExceptionResolver.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/AbstractSoapFaultDefinitionExceptionResolver.java index e23f63e4..aabe1d95 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/AbstractSoapFaultDefinitionExceptionResolver.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/AbstractSoapFaultDefinitionExceptionResolver.java @@ -16,6 +16,8 @@ package org.springframework.ws.soap.server.endpoint; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.ws.context.MessageContext; @@ -40,7 +42,7 @@ import org.springframework.ws.soap.soap12.Soap12Fault; */ public abstract class AbstractSoapFaultDefinitionExceptionResolver extends AbstractEndpointExceptionResolver { - private SoapFaultDefinition defaultFault; + private @Nullable SoapFaultDefinition defaultFault; /** * Set the default fault. This fault will be returned if no specific mapping was @@ -58,10 +60,11 @@ public abstract class AbstractSoapFaultDefinitionExceptionResolver extends Abstr * @param ex the exception to be handled * @return the definition mapped to the exception, or {@code null} if none is found. */ - protected abstract SoapFaultDefinition getFaultDefinition(Object endpoint, Exception ex); + protected abstract @Nullable SoapFaultDefinition getFaultDefinition(@Nullable Object endpoint, Exception ex); @Override - protected final boolean resolveExceptionInternal(MessageContext messageContext, Object endpoint, Exception ex) { + protected final boolean resolveExceptionInternal(MessageContext messageContext, @Nullable Object endpoint, + Exception ex) { Assert.isInstanceOf(SoapMessage.class, messageContext.getResponse(), "AbstractSoapFaultDefinitionExceptionResolver requires a SoapMessage"); @@ -102,9 +105,7 @@ public abstract class AbstractSoapFaultDefinitionExceptionResolver extends Abstr throw new IllegalStateException("This class only supports SOAP 1.1 and SOAP 1.2."); } } - if (fault != null) { - customizeFault(endpoint, ex, fault); - } + customizeFault(endpoint, ex, fault); return true; } @@ -119,7 +120,7 @@ public abstract class AbstractSoapFaultDefinitionExceptionResolver extends Abstr * @param ex the exception to be handled * @param fault the created fault */ - protected void customizeFault(Object endpoint, Exception ex, SoapFault fault) { + protected void customizeFault(@Nullable Object endpoint, Exception ex, SoapFault fault) { } } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/SimpleSoapExceptionResolver.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/SimpleSoapExceptionResolver.java index 9c86990e..e11f25a1 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/SimpleSoapExceptionResolver.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/SimpleSoapExceptionResolver.java @@ -18,6 +18,8 @@ package org.springframework.ws.soap.server.endpoint; import java.util.Locale; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.ws.context.MessageContext; @@ -60,7 +62,8 @@ public class SimpleSoapExceptionResolver extends AbstractEndpointExceptionResolv } @Override - protected final boolean resolveExceptionInternal(MessageContext messageContext, Object endpoint, Exception ex) { + protected final boolean resolveExceptionInternal(MessageContext messageContext, @Nullable Object endpoint, + Exception ex) { Assert.isInstanceOf(SoapMessage.class, messageContext.getResponse(), "SimpleSoapExceptionResolver requires a SoapMessage"); SoapMessage response = (SoapMessage) messageContext.getResponse(); @@ -74,14 +77,15 @@ public class SimpleSoapExceptionResolver extends AbstractEndpointExceptionResolv /** * Empty template method to allow subclasses an opportunity to customize the given * {@link SoapFault}. Called from - * {@link #resolveExceptionInternal(MessageContext,Object,Exception)}. + * {@link AbstractEndpointExceptionResolver#resolveExceptionInternal(MessageContext, Object, Exception)}. * @param messageContext current message context * @param endpoint the executed endpoint, or {@code null} if none chosen at the time * of the exception * @param ex the exception that got thrown during endpoint execution * @param fault the SOAP fault to be customized. */ - protected void customizeFault(MessageContext messageContext, Object endpoint, Exception ex, SoapFault fault) { + protected void customizeFault(MessageContext messageContext, @Nullable Object endpoint, Exception ex, + SoapFault fault) { } } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/SoapFaultAnnotationExceptionResolver.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/SoapFaultAnnotationExceptionResolver.java index f1a60a94..651c9f13 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/SoapFaultAnnotationExceptionResolver.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/SoapFaultAnnotationExceptionResolver.java @@ -16,8 +16,12 @@ package org.springframework.ws.soap.server.endpoint; +import java.util.Locale; + import javax.xml.namespace.QName; +import org.jspecify.annotations.Nullable; + import org.springframework.util.StringUtils; import org.springframework.ws.soap.server.endpoint.annotation.FaultCode; import org.springframework.ws.soap.server.endpoint.annotation.SoapFault; @@ -32,7 +36,7 @@ import org.springframework.ws.soap.server.endpoint.annotation.SoapFault; public class SoapFaultAnnotationExceptionResolver extends AbstractSoapFaultDefinitionExceptionResolver { @Override - protected final SoapFaultDefinition getFaultDefinition(Object endpoint, Exception ex) { + protected final @Nullable SoapFaultDefinition getFaultDefinition(@Nullable Object endpoint, Exception ex) { SoapFault faultAnnotation = ex.getClass().getAnnotation(SoapFault.class); if (faultAnnotation != null) { SoapFaultDefinition definition = new SoapFaultDefinition(); @@ -43,7 +47,10 @@ public class SoapFaultAnnotationExceptionResolver extends AbstractSoapFaultDefin definition.setFaultCode(QName.valueOf(faultAnnotation.customFaultCode())); } definition.setFaultStringOrReason(faultAnnotation.faultStringOrReason()); - definition.setLocale(StringUtils.parseLocaleString(faultAnnotation.locale())); + Locale locale = StringUtils.parseLocaleString(faultAnnotation.locale()); + if (locale != null) { + definition.setLocale(locale); + } return definition; } else { diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/SoapFaultDefinition.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/SoapFaultDefinition.java index 2a687d8c..4bb4f16b 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/SoapFaultDefinition.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/SoapFaultDefinition.java @@ -20,6 +20,10 @@ import java.util.Locale; import javax.xml.namespace.QName; +import org.jspecify.annotations.Nullable; + +import org.springframework.util.Assert; + /** * Defines properties for a SOAP Fault. Used by the {@code SoapFaultDefinitionEditor} and * the {@code SoapFaultMappingExceptionResolver}. @@ -34,39 +38,44 @@ public class SoapFaultDefinition { /** * Constant {@code QName} used to indicate that a {@code Client} fault must be * created. - * @see org.springframework.ws.soap.SoapBody#addClientOrSenderFault(String,java.util.Locale) + * @see org.springframework.ws.soap.SoapBody#addClientOrSenderFault(String, + * java.util.Locale) */ public static final QName CLIENT = new QName("CLIENT"); /** * Constant {@code QName} used to indicate that a {@code Receiver} fault must be * created. - * @see org.springframework.ws.soap.SoapBody#addServerOrReceiverFault(String,java.util.Locale) + * @see org.springframework.ws.soap.SoapBody#addServerOrReceiverFault(String, + * java.util.Locale) */ public static final QName RECEIVER = new QName("RECEIVER"); /** * Constant {@code QName} used to indicate that a {@code Sender} fault must be * created. - * @see org.springframework.ws.soap.SoapBody#addServerOrReceiverFault(String,java.util.Locale) + * @see org.springframework.ws.soap.SoapBody#addServerOrReceiverFault(String, + * java.util.Locale) */ public static final QName SENDER = new QName("SENDER"); /** * Constant {@code QName} used to indicate that a {@code Server} fault must be * created. - * @see org.springframework.ws.soap.SoapBody#addClientOrSenderFault(String,java.util.Locale) + * @see org.springframework.ws.soap.SoapBody#addClientOrSenderFault(String, + * java.util.Locale) */ public static final QName SERVER = new QName("SERVER"); - private QName faultCode; + private @Nullable QName faultCode; - private String faultStringOrReason; + private @Nullable String faultStringOrReason; private Locale locale = Locale.ENGLISH; /** Returns the fault code. */ public QName getFaultCode() { + Assert.state(this.faultCode != null, "'faultCode' is required"); return this.faultCode; } @@ -79,7 +88,7 @@ public class SoapFaultDefinition { * Returns the fault string or reason text. By default, it is set to the exception * message. */ - public String getFaultStringOrReason() { + public @Nullable String getFaultStringOrReason() { return this.faultStringOrReason; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/SoapFaultMappingExceptionResolver.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/SoapFaultMappingExceptionResolver.java index 0e70363e..430ba61a 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/SoapFaultMappingExceptionResolver.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/SoapFaultMappingExceptionResolver.java @@ -20,6 +20,8 @@ import java.util.LinkedHashMap; import java.util.Map; import java.util.Properties; +import org.jspecify.annotations.Nullable; + import org.springframework.util.CollectionUtils; /** @@ -55,7 +57,7 @@ public class SoapFaultMappingExceptionResolver extends AbstractSoapFaultDefiniti } @Override - protected SoapFaultDefinition getFaultDefinition(Object endpoint, Exception ex) { + protected @Nullable SoapFaultDefinition getFaultDefinition(@Nullable Object endpoint, Exception ex) { if (!CollectionUtils.isEmpty(this.exceptionMappings)) { String definitionText = null; int deepest = Integer.MAX_VALUE; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/adapter/method/SoapHeaderElementMethodArgumentResolver.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/adapter/method/SoapHeaderElementMethodArgumentResolver.java index 357e5388..3bc82115 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/adapter/method/SoapHeaderElementMethodArgumentResolver.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/adapter/method/SoapHeaderElementMethodArgumentResolver.java @@ -24,6 +24,8 @@ import java.util.List; import javax.xml.namespace.QName; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; import org.springframework.util.Assert; import org.springframework.ws.context.MessageContext; @@ -73,21 +75,21 @@ public class SoapHeaderElementMethodArgumentResolver implements MethodArgumentRe Type genericType = parameter.getGenericParameterType(); if (genericType instanceof ParameterizedType parameterizedType) { Type[] typeArguments = parameterizedType.getActualTypeArguments(); - if (typeArguments.length == 1 && SoapHeaderElement.class.equals(typeArguments[0])) { - return true; - } + return typeArguments.length == 1 && SoapHeaderElement.class.equals(typeArguments[0]); } } return false; } @Override - public Object resolveArgument(MessageContext messageContext, MethodParameter parameter) throws Exception { + public @Nullable Object resolveArgument(MessageContext messageContext, MethodParameter parameter) throws Exception { Assert.isInstanceOf(SoapMessage.class, messageContext.getRequest()); SoapMessage request = (SoapMessage) messageContext.getRequest(); org.springframework.ws.soap.SoapHeader soapHeader = request.getSoapHeader(); - String paramValue = parameter.getParameterAnnotation(SoapHeader.class).value(); + SoapHeader parameterAnnotation = parameter.getParameterAnnotation(SoapHeader.class); + Assert.state(parameterAnnotation != null, "Cannot resolve parameter, @SoapHeader annotation is required"); + String paramValue = parameterAnnotation.value(); Assert.isTrue(QNameUtils.validateQName(paramValue), "Invalid header qualified name [" + paramValue + "]. " + "QName must be of the form '{namespace}localPart'."); @@ -96,17 +98,18 @@ public class SoapHeaderElementMethodArgumentResolver implements MethodArgumentRe Class parameterType = parameter.getParameterType(); - if (SoapHeaderElement.class.equals(parameterType)) { + if (SoapHeaderElement.class.equals(parameterType) && soapHeader != null) { return extractSoapHeader(qname, soapHeader); } - else if (List.class.equals(parameterType)) { + else if (List.class.equals(parameterType) && soapHeader != null) { return extractSoapHeaderList(qname, soapHeader); } // should not happen throw new UnsupportedOperationException(); } - private SoapHeaderElement extractSoapHeader(QName qname, org.springframework.ws.soap.SoapHeader soapHeader) { + private @Nullable SoapHeaderElement extractSoapHeader(QName qname, + org.springframework.ws.soap.SoapHeader soapHeader) { Iterator elements = soapHeader.examineAllHeaderElements(); while (elements.hasNext()) { SoapHeaderElement e = elements.next(); diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/adapter/method/SoapMethodArgumentResolver.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/adapter/method/SoapMethodArgumentResolver.java index be811cf3..ccb79e5c 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/adapter/method/SoapMethodArgumentResolver.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/adapter/method/SoapMethodArgumentResolver.java @@ -16,6 +16,8 @@ package org.springframework.ws.soap.server.endpoint.adapter.method; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; import org.springframework.util.Assert; import org.springframework.ws.context.MessageContext; @@ -42,7 +44,7 @@ public class SoapMethodArgumentResolver implements MethodArgumentResolver { } @Override - public Object resolveArgument(MessageContext messageContext, MethodParameter parameter) { + public @Nullable Object resolveArgument(MessageContext messageContext, MethodParameter parameter) { Assert.isInstanceOf(SoapMessage.class, messageContext.getRequest()); SoapMessage request = (SoapMessage) messageContext.getRequest(); diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/adapter/method/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/adapter/method/package-info.java index 0e791c25..ac86e9c2 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/adapter/method/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/adapter/method/package-info.java @@ -17,4 +17,7 @@ /** * Method argument resolvers for SOAP headers. */ +@NullMarked package org.springframework.ws.soap.server.endpoint.adapter.method; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/annotation/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/annotation/package-info.java index 39d8821f..ba4885b0 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/annotation/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/annotation/package-info.java @@ -17,4 +17,7 @@ /** * Annotations for Spring-WS SOAP endpoints. */ +@NullMarked package org.springframework.ws.soap.server.endpoint.annotation; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/interceptor/PayloadValidatingInterceptor.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/interceptor/PayloadValidatingInterceptor.java index 16869dd2..cce91ae2 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/interceptor/PayloadValidatingInterceptor.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/interceptor/PayloadValidatingInterceptor.java @@ -18,6 +18,8 @@ package org.springframework.ws.soap.server.endpoint.interceptor; import javax.xml.transform.Source; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.WebServiceMessage; /** @@ -44,13 +46,13 @@ public class PayloadValidatingInterceptor extends AbstractFaultCreatingValidatin /** Returns the payload source of the given message. */ @Override - protected Source getValidationRequestSource(WebServiceMessage request) { + protected @Nullable Source getValidationRequestSource(WebServiceMessage request) { return request.getPayloadSource(); } /** Returns the payload source of the given message. */ @Override - protected Source getValidationResponseSource(WebServiceMessage response) { + protected @Nullable Source getValidationResponseSource(WebServiceMessage response) { return response.getPayloadSource(); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/interceptor/SoapEnvelopeLoggingInterceptor.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/interceptor/SoapEnvelopeLoggingInterceptor.java index 73f63f21..4b8165cc 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/interceptor/SoapEnvelopeLoggingInterceptor.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/interceptor/SoapEnvelopeLoggingInterceptor.java @@ -18,6 +18,8 @@ package org.springframework.ws.soap.server.endpoint.interceptor; import javax.xml.transform.Source; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.WebServiceMessage; import org.springframework.ws.context.MessageContext; import org.springframework.ws.server.endpoint.AbstractLoggingInterceptor; @@ -60,7 +62,7 @@ public class SoapEnvelopeLoggingInterceptor extends AbstractLoggingInterceptor i } @Override - protected Source getSource(WebServiceMessage message) { + protected @Nullable Source getSource(WebServiceMessage message) { if (message instanceof SoapMessage soapMessage) { return soapMessage.getEnvelope().getSource(); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/interceptor/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/interceptor/package-info.java index ac0f2fe1..abb0f719 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/interceptor/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/interceptor/package-info.java @@ -18,4 +18,7 @@ * Provides miscellaneous endpoints {@code EndpointInterceptor} implementations for SOAP * purposes. */ +@NullMarked package org.springframework.ws.soap.server.endpoint.interceptor; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/mapping/DelegatingSoapEndpointMapping.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/mapping/DelegatingSoapEndpointMapping.java index a78f465a..2a6100ac 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/mapping/DelegatingSoapEndpointMapping.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/mapping/DelegatingSoapEndpointMapping.java @@ -16,6 +16,8 @@ package org.springframework.ws.soap.server.endpoint.mapping; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.InitializingBean; import org.springframework.util.Assert; import org.springframework.ws.context.MessageContext; @@ -44,9 +46,9 @@ import org.springframework.ws.soap.server.SoapEndpointMapping; */ public class DelegatingSoapEndpointMapping implements InitializingBean, SoapEndpointMapping { - private EndpointMapping delegate; + private @Nullable EndpointMapping delegate; - private String[] actorsOrRoles; + private String @Nullable [] actorsOrRoles; private boolean isUltimateReceiver = true; @@ -78,7 +80,8 @@ public class DelegatingSoapEndpointMapping implements InitializingBean, SoapEndp * @see #setActorsOrRoles(String[]) */ @Override - public EndpointInvocationChain getEndpoint(MessageContext messageContext) throws Exception { + public @Nullable EndpointInvocationChain getEndpoint(MessageContext messageContext) throws Exception { + Assert.notNull(this.delegate, "delegate must not be null"); EndpointInvocationChain delegateChain = this.delegate.getEndpoint(messageContext); if (delegateChain != null) { return new SoapEndpointInvocationChain(delegateChain.getEndpoint(), delegateChain.getInterceptors(), diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/mapping/SoapActionAnnotationMethodEndpointMapping.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/mapping/SoapActionAnnotationMethodEndpointMapping.java index f26206e7..b7c532d9 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/mapping/SoapActionAnnotationMethodEndpointMapping.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/mapping/SoapActionAnnotationMethodEndpointMapping.java @@ -20,6 +20,8 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; +import org.jspecify.annotations.Nullable; + import org.springframework.core.annotation.AnnotationUtils; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -55,7 +57,7 @@ import org.springframework.ws.soap.server.endpoint.annotation.SoapActions; public class SoapActionAnnotationMethodEndpointMapping extends AbstractAnnotationMethodEndpointMapping implements SoapEndpointMapping { - private String[] actorsOrRoles; + private String @Nullable [] actorsOrRoles; private boolean isUltimateReceiver = true; @@ -92,7 +94,7 @@ public class SoapActionAnnotationMethodEndpointMapping extends AbstractAnnotatio } @Override - protected String getLookupKeyForMessage(MessageContext messageContext) throws Exception { + protected @Nullable String getLookupKeyForMessage(MessageContext messageContext) throws Exception { if (messageContext.getRequest() instanceof SoapMessage request) { String soapAction = request.getSoapAction(); if (StringUtils.hasLength(soapAction) && soapAction.charAt(0) == '"' @@ -109,7 +111,7 @@ public class SoapActionAnnotationMethodEndpointMapping extends AbstractAnnotatio } @Override - protected String getLookupKeyForMethod(Method method) { + protected @Nullable String getLookupKeyForMethod(Method method) { SoapAction soapAction = AnnotationUtils.findAnnotation(method, SoapAction.class); return (soapAction != null) ? soapAction.value() : null; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/mapping/SoapActionEndpointMapping.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/mapping/SoapActionEndpointMapping.java index 0113dc81..c7527ebf 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/mapping/SoapActionEndpointMapping.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/mapping/SoapActionEndpointMapping.java @@ -16,6 +16,8 @@ package org.springframework.ws.soap.server.endpoint.mapping; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.ws.context.MessageContext; @@ -54,7 +56,7 @@ import org.springframework.ws.soap.server.SoapEndpointMapping; */ public class SoapActionEndpointMapping extends AbstractMapBasedEndpointMapping implements SoapEndpointMapping { - private String[] actorsOrRoles; + private String @Nullable [] actorsOrRoles; private boolean isUltimateReceiver = true; @@ -91,7 +93,7 @@ public class SoapActionEndpointMapping extends AbstractMapBasedEndpointMapping i } @Override - protected String getLookupKeyForMessage(MessageContext messageContext) throws Exception { + protected @Nullable String getLookupKeyForMessage(MessageContext messageContext) throws Exception { if (messageContext.getRequest() instanceof SoapMessage request) { String soapAction = request.getSoapAction(); if (StringUtils.hasLength(soapAction) && soapAction.charAt(0) == '"' diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/mapping/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/mapping/package-info.java index 7b4c3073..155e531e 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/mapping/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/mapping/package-info.java @@ -18,4 +18,7 @@ * Provides miscellaneous endpoints {@code EndpointMapping} implementations for SOAP * purposes. */ +@NullMarked package org.springframework.ws.soap.server.endpoint.mapping; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/package-info.java index c67a437a..89add470 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/endpoint/package-info.java @@ -18,4 +18,7 @@ * Provides {@code EndpointAdapter}, {@code EndpointMapping}, and * {@code EndpointExceptionResolver} implementations for SOAP. */ +@NullMarked package org.springframework.ws.soap.server.endpoint; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/package-info.java index 41a9511f..e776c49e 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/server/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/server/package-info.java @@ -17,4 +17,7 @@ /** * Contains classes for SOAP-specific server-side Spring-WS support. */ +@NullMarked package org.springframework.ws.soap.server; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/soap11/Soap11Body.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/soap11/Soap11Body.java index 063d6a5e..fb35f95a 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/soap11/Soap11Body.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/soap11/Soap11Body.java @@ -20,6 +20,8 @@ import java.util.Locale; import javax.xml.namespace.QName; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.soap.SoapBody; import org.springframework.ws.soap.SoapFaultException; @@ -45,7 +47,7 @@ public interface Soap11Body extends SoapBody { Soap11Fault addFault(QName faultCode, String faultString, Locale faultStringLocale) throws SoapFaultException; @Override - Soap11Fault getFault(); + @Nullable Soap11Fault getFault(); @Override Soap11Fault addMustUnderstandFault(String faultStringOrReason, Locale locale) throws SoapFaultException; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/soap11/Soap11Fault.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/soap11/Soap11Fault.java index abdeefff..2d112950 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/soap11/Soap11Fault.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/soap11/Soap11Fault.java @@ -18,6 +18,8 @@ package org.springframework.ws.soap.soap11; import java.util.Locale; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.soap.SoapFault; /** @@ -30,6 +32,6 @@ import org.springframework.ws.soap.SoapFault; public interface Soap11Fault extends SoapFault { /** Returns the locale of the fault string. */ - Locale getFaultStringLocale(); + @Nullable Locale getFaultStringLocale(); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/soap11/Soap11Header.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/soap11/Soap11Header.java index f52ec146..95e7ecfc 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/soap11/Soap11Header.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/soap11/Soap11Header.java @@ -18,6 +18,8 @@ package org.springframework.ws.soap.soap11; import java.util.Iterator; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.soap.SoapHeader; import org.springframework.ws.soap.SoapHeaderElement; import org.springframework.ws.soap.SoapHeaderException; @@ -39,6 +41,6 @@ public interface Soap11Header extends SoapHeader { * @throws SoapHeaderException if the headers cannot be returned * @see SoapHeaderElement */ - Iterator examineHeaderElementsToProcess(String[] actors) throws SoapHeaderException; + Iterator examineHeaderElementsToProcess(String @Nullable [] actors) throws SoapHeaderException; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/soap11/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/soap11/package-info.java index 67172e11..2cdfd857 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/soap11/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/soap11/package-info.java @@ -17,4 +17,7 @@ /** * Contains interfaces specific to SOAP 1.1. */ +@NullMarked package org.springframework.ws.soap.soap11; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/soap12/Soap12Body.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/soap12/Soap12Body.java index 098a5d13..4a20c306 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/soap12/Soap12Body.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/soap12/Soap12Body.java @@ -20,6 +20,8 @@ import java.util.Locale; import javax.xml.namespace.QName; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.soap.SoapBody; import org.springframework.ws.soap.SoapFaultException; @@ -44,7 +46,7 @@ public interface Soap12Body extends SoapBody { Soap12Fault addDataEncodingUnknownFault(QName[] subcodes, String reason, Locale locale) throws SoapFaultException; @Override - Soap12Fault getFault(); + @Nullable Soap12Fault getFault(); @Override Soap12Fault addMustUnderstandFault(String faultStringOrReason, Locale locale) throws SoapFaultException; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/soap12/Soap12Fault.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/soap12/Soap12Fault.java index 528530f6..df400070 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/soap12/Soap12Fault.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/soap12/Soap12Fault.java @@ -21,6 +21,8 @@ import java.util.Locale; import javax.xml.namespace.QName; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.soap.SoapFault; /** @@ -46,7 +48,7 @@ public interface Soap12Fault extends SoapFault { void addFaultSubcode(QName subcode); /** Returns the fault node. Optional. */ - String getFaultNode(); + @Nullable String getFaultNode(); /** Sets the fault node. */ void setFaultNode(String uri); @@ -55,6 +57,6 @@ public interface Soap12Fault extends SoapFault { void setFaultReasonText(Locale locale, String text); /** Returns the reason associated with the given language. */ - String getFaultReasonText(Locale locale); + @Nullable String getFaultReasonText(Locale locale); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/soap12/Soap12Header.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/soap12/Soap12Header.java index 77b6920a..33370b0f 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/soap12/Soap12Header.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/soap12/Soap12Header.java @@ -20,6 +20,8 @@ import java.util.Iterator; import javax.xml.namespace.QName; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.soap.SoapHeader; import org.springframework.ws.soap.SoapHeaderElement; import org.springframework.ws.soap.SoapHeaderException; @@ -60,7 +62,7 @@ public interface Soap12Header extends SoapHeader { * @throws SoapHeaderException if the headers cannot be returned * @see SoapHeaderElement */ - Iterator examineHeaderElementsToProcess(String[] roles, boolean isUltimateReceiver) + Iterator examineHeaderElementsToProcess(String @Nullable [] roles, boolean isUltimateReceiver) throws SoapHeaderException; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/soap12/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/soap12/package-info.java index 1acfb0fa..6c51ab0f 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/soap12/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/soap12/package-info.java @@ -17,4 +17,7 @@ /** * Contains interfaces specific to SOAP 1.2. */ +@NullMarked package org.springframework.ws.soap.soap12; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/support/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/support/package-info.java index 05fc7580..2f8933cb 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/support/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/support/package-info.java @@ -17,4 +17,7 @@ /** * Classes supporting the org.springframework.ws.soap package. */ +@NullMarked package org.springframework.ws.soap.support; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/stream/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/stream/package-info.java index 920844b3..543e0432 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/stream/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/stream/package-info.java @@ -17,4 +17,7 @@ /** * Streaming support. */ +@NullMarked package org.springframework.ws.stream; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/support/DefaultStrategiesHelper.java b/spring-ws-core/src/main/java/org/springframework/ws/support/DefaultStrategiesHelper.java index 27007644..3c4981a6 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/support/DefaultStrategiesHelper.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/support/DefaultStrategiesHelper.java @@ -23,6 +23,7 @@ import java.util.List; import java.util.Properties; import jakarta.servlet.ServletContext; +import org.jspecify.annotations.Nullable; import org.springframework.beans.BeanUtils; import org.springframework.beans.BeansException; @@ -121,7 +122,7 @@ public class DefaultStrategiesHelper { * @throws BeansException if initialization failed */ @SuppressWarnings("unchecked") - public List getDefaultStrategies(Class strategyInterface, ApplicationContext applicationContext) + public List getDefaultStrategies(Class strategyInterface, @Nullable ApplicationContext applicationContext) throws BeanInitializationException { String key = strategyInterface.getName(); try { @@ -155,13 +156,13 @@ public class DefaultStrategiesHelper { } /** Instantiates the given bean, simulating the standard bean life cycle. */ - private T instantiateBean(Class clazz, ApplicationContext applicationContext) { + private T instantiateBean(Class clazz, @Nullable ApplicationContext applicationContext) { T strategy = BeanUtils.instantiateClass(clazz); if (strategy instanceof BeanNameAware beanNameAware) { beanNameAware.setBeanName(clazz.getName()); } if (applicationContext != null) { - if (strategy instanceof BeanClassLoaderAware) { + if (strategy instanceof BeanClassLoaderAware && applicationContext.getClassLoader() != null) { ((BeanClassLoaderAware) strategy).setBeanClassLoader(applicationContext.getClassLoader()); } if (strategy instanceof BeanFactoryAware) { @@ -181,7 +182,9 @@ public class DefaultStrategiesHelper { } if (applicationContext instanceof WebApplicationContext && strategy instanceof ServletContextAware) { ServletContext servletContext = ((WebApplicationContext) applicationContext).getServletContext(); - ((ServletContextAware) strategy).setServletContext(servletContext); + if (servletContext != null) { + ((ServletContextAware) strategy).setServletContext(servletContext); + } } } if (strategy instanceof InitializingBean initializingBean) { @@ -217,7 +220,7 @@ public class DefaultStrategiesHelper { * @return the corresponding strategy object * @throws BeansException if initialization failed */ - public T getDefaultStrategy(Class strategyInterface, ApplicationContext applicationContext) + public T getDefaultStrategy(Class strategyInterface, @Nullable ApplicationContext applicationContext) throws BeanInitializationException { List result = getDefaultStrategies(strategyInterface, applicationContext); if (result.size() != 1) { diff --git a/spring-ws-core/src/main/java/org/springframework/ws/support/MarshallingUtils.java b/spring-ws-core/src/main/java/org/springframework/ws/support/MarshallingUtils.java index 90d50846..aeaa2c2a 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/support/MarshallingUtils.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/support/MarshallingUtils.java @@ -21,6 +21,7 @@ import java.io.IOException; import javax.xml.transform.Source; import jakarta.activation.DataHandler; +import org.jspecify.annotations.Nullable; import org.springframework.oxm.Marshaller; import org.springframework.oxm.Unmarshaller; @@ -54,7 +55,7 @@ public abstract class MarshallingUtils { * @return the unmarshalled object * @throws IOException in case of I/O errors */ - public static Object unmarshal(Unmarshaller unmarshaller, WebServiceMessage message) throws IOException { + public static @Nullable Object unmarshal(Unmarshaller unmarshaller, WebServiceMessage message) throws IOException { Source payload = message.getPayloadSource(); if (payload == null) { return null; @@ -110,7 +111,7 @@ public abstract class MarshallingUtils { } @Override - public DataHandler getAttachment(String contentId) { + public @Nullable DataHandler getAttachment(String contentId) { Attachment attachment = this.mimeMessage.getAttachment(contentId); return (attachment != null) ? attachment.getDataHandler() : null; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/support/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/support/package-info.java index ee8c74ad..d405117d 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/support/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/support/package-info.java @@ -17,4 +17,7 @@ /** * Provides general helper classes for Spring Web Services. */ +@NullMarked package org.springframework.ws.support; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/AbstractReceiverConnection.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/AbstractReceiverConnection.java index 4943f11d..b919a1a4 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/AbstractReceiverConnection.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/AbstractReceiverConnection.java @@ -21,6 +21,8 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.Iterator; +import org.jspecify.annotations.Nullable; + /** * Abstract base class for {@link WebServiceConnection} implementations used for receiving * requests. @@ -32,9 +34,9 @@ import java.util.Iterator; public abstract class AbstractReceiverConnection extends AbstractWebServiceConnection implements HeadersAwareReceiverWebServiceConnection { - private TransportInputStream requestInputStream; + private @Nullable TransportInputStream requestInputStream; - private TransportOutputStream responseOutputStream; + private @Nullable TransportOutputStream responseOutputStream; @Override protected final TransportInputStream createTransportInputStream() throws IOException { diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/AbstractSenderConnection.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/AbstractSenderConnection.java index 31826aa1..fce12dbe 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/AbstractSenderConnection.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/AbstractSenderConnection.java @@ -21,6 +21,8 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.Iterator; +import org.jspecify.annotations.Nullable; + /** * Abstract base class for {@link WebServiceConnection} implementations used for sending * requests. @@ -32,9 +34,9 @@ import java.util.Iterator; public abstract class AbstractSenderConnection extends AbstractWebServiceConnection implements HeadersAwareSenderWebServiceConnection { - private TransportOutputStream requestOutputStream; + private @Nullable TransportOutputStream requestOutputStream; - private TransportInputStream responseInputStream; + private @Nullable TransportInputStream responseInputStream; @Override protected final TransportOutputStream createTransportOutputStream() throws IOException { @@ -45,7 +47,7 @@ public abstract class AbstractSenderConnection extends AbstractWebServiceConnect } @Override - protected final TransportInputStream createTransportInputStream() throws IOException { + protected final @Nullable TransportInputStream createTransportInputStream() throws IOException { if (hasResponse()) { if (this.responseInputStream == null) { this.responseInputStream = new ResponseTransportInputStream(); diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/AbstractWebServiceConnection.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/AbstractWebServiceConnection.java index 8d6a108c..9bb9d20d 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/AbstractWebServiceConnection.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/AbstractWebServiceConnection.java @@ -18,6 +18,8 @@ package org.springframework.ws.transport; import java.io.IOException; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.WebServiceMessage; import org.springframework.ws.WebServiceMessageFactory; @@ -29,9 +31,9 @@ import org.springframework.ws.WebServiceMessageFactory; */ public abstract class AbstractWebServiceConnection implements WebServiceConnection { - private TransportInputStream tis; + private @Nullable TransportInputStream tis; - private TransportOutputStream tos; + private @Nullable TransportOutputStream tos; private boolean closed = false; @@ -65,7 +67,7 @@ public abstract class AbstractWebServiceConnection implements WebServiceConnecti * @return the output stream * @throws IOException when an I/O exception occurs */ - protected abstract TransportOutputStream createTransportOutputStream() throws IOException; + protected abstract @Nullable TransportOutputStream createTransportOutputStream() throws IOException; /** * Called after the given message has been written to the @@ -79,7 +81,7 @@ public abstract class AbstractWebServiceConnection implements WebServiceConnecti } @Override - public final WebServiceMessage receive(WebServiceMessageFactory messageFactory) throws IOException { + public final @Nullable WebServiceMessage receive(WebServiceMessageFactory messageFactory) throws IOException { checkClosed(); onReceiveBeforeRead(); this.tis = createTransportInputStream(); @@ -107,7 +109,7 @@ public abstract class AbstractWebServiceConnection implements WebServiceConnecti * @return the input stream, or {@code null} if no response can be read * @throws IOException when an I/O exception occurs */ - protected abstract TransportInputStream createTransportInputStream() throws IOException; + protected abstract @Nullable TransportInputStream createTransportInputStream() throws IOException; /** * Called when the given message has been read from the {@code TransportInputStream}. diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/FaultAwareWebServiceConnection.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/FaultAwareWebServiceConnection.java index 6aab5e31..67000efc 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/FaultAwareWebServiceConnection.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/FaultAwareWebServiceConnection.java @@ -20,6 +20,8 @@ import java.io.IOException; import javax.xml.namespace.QName; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.soap.SoapFault; /** @@ -50,6 +52,6 @@ public interface FaultAwareWebServiceConnection extends WebServiceConnection { * fault. * @throws IOException in case of I/O errors */ - void setFaultCode(QName faultCode) throws IOException; + void setFaultCode(@Nullable QName faultCode) throws IOException; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/TransportException.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/TransportException.java index 8fe79780..1a69fa8b 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/TransportException.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/TransportException.java @@ -18,6 +18,8 @@ package org.springframework.ws.transport; import java.io.IOException; +import org.jspecify.annotations.Nullable; + /** * Abstract base class for exceptions related to the transport layer. * @@ -27,7 +29,7 @@ import java.io.IOException; @SuppressWarnings("serial") public abstract class TransportException extends IOException { - protected TransportException(String msg) { + protected TransportException(@Nullable String msg) { super(msg); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/TransportInputStream.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/TransportInputStream.java index 852146df..a7016c93 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/TransportInputStream.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/TransportInputStream.java @@ -20,6 +20,8 @@ import java.io.IOException; import java.io.InputStream; import java.util.Iterator; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; /** @@ -34,7 +36,7 @@ import org.springframework.util.Assert; */ public abstract class TransportInputStream extends InputStream { - private InputStream inputStream; + private @Nullable InputStream inputStream; protected TransportInputStream() { } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/TransportOutputStream.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/TransportOutputStream.java index f342c178..52d61f1e 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/TransportOutputStream.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/TransportOutputStream.java @@ -19,6 +19,8 @@ package org.springframework.ws.transport; import java.io.IOException; import java.io.OutputStream; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; /** @@ -32,7 +34,7 @@ import org.springframework.util.Assert; */ public abstract class TransportOutputStream extends OutputStream { - private OutputStream outputStream; + private @Nullable OutputStream outputStream; protected TransportOutputStream() { } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/WebServiceConnection.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/WebServiceConnection.java index 0c409b66..02a36e62 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/WebServiceConnection.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/WebServiceConnection.java @@ -20,6 +20,8 @@ import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.WebServiceMessage; import org.springframework.ws.WebServiceMessageFactory; @@ -49,10 +51,10 @@ public interface WebServiceConnection extends AutoCloseable { * @return the read message, or {@code null} if no message received * @throws IOException in case of I/O errors */ - WebServiceMessage receive(WebServiceMessageFactory messageFactory) throws IOException; + @Nullable WebServiceMessage receive(WebServiceMessageFactory messageFactory) throws IOException; /** Returns the URI for this connection. */ - URI getUri() throws URISyntaxException; + @Nullable URI getUri() throws URISyntaxException; /** * Indicates whether this connection has an error. Typically, error detection is done @@ -67,7 +69,7 @@ public interface WebServiceConnection extends AutoCloseable { * present * @see #hasError() */ - String getErrorMessage() throws IOException; + @Nullable String getErrorMessage() throws IOException; /** * Closes this connection. diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/context/TransportContext.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/context/TransportContext.java index 02ffc75c..b89f1d76 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/context/TransportContext.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/context/TransportContext.java @@ -16,6 +16,8 @@ package org.springframework.ws.transport.context; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.transport.WebServiceConnection; /** @@ -31,6 +33,6 @@ import org.springframework.ws.transport.WebServiceConnection; public interface TransportContext { /** Returns the current {@code WebServiceConnection}. */ - WebServiceConnection getConnection(); + @Nullable WebServiceConnection getConnection(); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/context/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/context/package-info.java index 36e5832a..a43d2825 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/context/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/context/package-info.java @@ -17,4 +17,7 @@ /** * Abstraction for determining the current TransportInputStream and TransportOutputStream. */ +@NullMarked package org.springframework.ws.transport.context; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/AbstractHttpComponents5MessageSender.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/AbstractHttpComponents5MessageSender.java index 51e5dbcc..275dfa60 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/AbstractHttpComponents5MessageSender.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/AbstractHttpComponents5MessageSender.java @@ -24,6 +24,7 @@ import org.apache.hc.client5.http.classic.methods.HttpPost; import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; import org.apache.hc.core5.http.HttpHost; import org.apache.hc.core5.http.protocol.HttpContext; +import org.jspecify.annotations.Nullable; import org.springframework.beans.factory.DisposableBean; import org.springframework.ws.transport.WebServiceConnection; @@ -75,7 +76,7 @@ public abstract class AbstractHttpComponents5MessageSender extends AbstractHttpW * @param uri the URI to create the context for * @return the context, or {@code null} */ - protected HttpContext createContext(URI uri) { + protected @Nullable HttpContext createContext(URI uri) { return null; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/AbstractHttpSenderConnection.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/AbstractHttpSenderConnection.java index ac41873a..38a4d65b 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/AbstractHttpSenderConnection.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/AbstractHttpSenderConnection.java @@ -24,6 +24,8 @@ import java.util.zip.GZIPInputStream; import javax.xml.namespace.QName; +import org.jspecify.annotations.Nullable; + import org.springframework.util.StringUtils; import org.springframework.ws.transport.AbstractSenderConnection; import org.springframework.ws.transport.FaultAwareWebServiceConnection; @@ -43,13 +45,13 @@ public abstract class AbstractHttpSenderConnection extends AbstractSenderConnect /** * Cached result of {@code hasResponse}. */ - private Boolean hasResponse; + private @Nullable Boolean hasResponse; /** * The raw response input stream to use instead of calling * {@link #getRawResponseInputStream()}. */ - private PushbackInputStream rawResponseInputStream; + private @Nullable PushbackInputStream rawResponseInputStream; @Override public final boolean hasError() throws IOException { @@ -168,7 +170,7 @@ public abstract class AbstractHttpSenderConnection extends AbstractSenderConnect } @Override - public final void setFaultCode(QName faultCode) throws IOException { + public final void setFaultCode(@Nullable QName faultCode) throws IOException { } } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/ClientHttpRequestConnection.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/ClientHttpRequestConnection.java index f399d338..da858f13 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/ClientHttpRequestConnection.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/ClientHttpRequestConnection.java @@ -25,6 +25,8 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; +import org.jspecify.annotations.Nullable; + import org.springframework.http.client.ClientHttpRequest; import org.springframework.http.client.ClientHttpResponse; import org.springframework.util.Assert; @@ -44,7 +46,7 @@ public class ClientHttpRequestConnection extends AbstractHttpSenderConnection { private final ClientHttpRequest request; - private ClientHttpResponse response; + private @Nullable ClientHttpResponse response; public ClientHttpRequestConnection(ClientHttpRequest request) { Assert.notNull(request, "'request' must not be null"); @@ -56,6 +58,7 @@ public class ClientHttpRequestConnection extends AbstractHttpSenderConnection { } public ClientHttpResponse getClientHttpResponse() { + Assert.notNull(this.response, "Response is not available"); return this.response; } @@ -87,33 +90,33 @@ public class ClientHttpRequestConnection extends AbstractHttpSenderConnection { @Override protected long getResponseContentLength() throws IOException { - return this.response.getHeaders().getContentLength(); + return getClientHttpResponse().getHeaders().getContentLength(); } @Override public Iterator getResponseHeaderNames() throws IOException { - return this.response.getHeaders().headerNames().iterator(); + return getClientHttpResponse().getHeaders().headerNames().iterator(); } @Override public Iterator getResponseHeaders(String name) throws IOException { - List headers = this.response.getHeaders().get(name); + List headers = getClientHttpResponse().getHeaders().get(name); return (headers != null) ? headers.iterator() : Collections.emptyIterator(); } @Override protected int getResponseCode() throws IOException { - return this.response.getStatusCode().value(); + return getClientHttpResponse().getStatusCode().value(); } @Override protected String getResponseMessage() throws IOException { - return this.response.getStatusText(); + return getClientHttpResponse().getStatusText(); } @Override protected InputStream getRawResponseInputStream() throws IOException { - return this.response.getBody(); + return getClientHttpResponse().getBody(); } @Override diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/ClientHttpRequestMessageSender.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/ClientHttpRequestMessageSender.java index 6ffc9f3a..347a56d6 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/ClientHttpRequestMessageSender.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/ClientHttpRequestMessageSender.java @@ -43,7 +43,7 @@ public class ClientHttpRequestMessageSender extends AbstractHttpWebServiceMessag } public ClientHttpRequestMessageSender(ClientHttpRequestFactory requestFactory) { - setRequestFactory(requestFactory); + this.requestFactory = requestFactory; } public ClientHttpRequestFactory getRequestFactory() { diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/HttpComponents5ClientFactory.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/HttpComponents5ClientFactory.java index ffe2f16b..c9826fed 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/HttpComponents5ClientFactory.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/HttpComponents5ClientFactory.java @@ -40,6 +40,7 @@ import org.apache.hc.core5.http.HttpRequest; import org.apache.hc.core5.http.HttpRequestInterceptor; import org.apache.hc.core5.http.protocol.HttpContext; import org.apache.hc.core5.util.Timeout; +import org.jspecify.annotations.Nullable; import org.springframework.beans.factory.FactoryBean; import org.springframework.ws.client.support.interceptor.ClientInterceptor; @@ -81,11 +82,11 @@ public class HttpComponents5ClientFactory implements FactoryBean maxConnectionsPerHost = Map.of(); - private PoolingHttpClientConnectionManager connectionManager; + private @Nullable PoolingHttpClientConnectionManager connectionManager; /** * Create a new instance with default settings. This configures @@ -195,7 +196,7 @@ public class HttpComponents5ClientFactory implements FactoryBean getResponseHeaderNames() throws IOException { - return Arrays.stream(this.httpResponse.getHeaders()).map(NameValuePair::getName).iterator(); + return Arrays.stream(getHttpResponse().getHeaders()).map(NameValuePair::getName).iterator(); } @Override public Iterator getResponseHeaders(String name) throws IOException { - return Arrays.stream(this.httpResponse.getHeaders(name)).map(NameValuePair::getValue).iterator(); + return Arrays.stream(getHttpResponse().getHeaders(name)).map(NameValuePair::getValue).iterator(); } } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/HttpComponents5MessageSender.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/HttpComponents5MessageSender.java index 55aa5b5e..265d23f2 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/HttpComponents5MessageSender.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/HttpComponents5MessageSender.java @@ -23,8 +23,10 @@ import org.apache.hc.client5.http.auth.AuthScope; import org.apache.hc.client5.http.auth.Credentials; import org.apache.hc.client5.http.classic.HttpClient; import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; +import org.jspecify.annotations.Nullable; import org.springframework.beans.factory.InitializingBean; +import org.springframework.util.Assert; /** * {@code AbstractHttpComponents5MessageSender} implementation that configures the @@ -46,7 +48,7 @@ public class HttpComponents5MessageSender extends AbstractHttpComponents5Message private final HttpComponents5ClientFactory clientFactory; - private HttpClient httpClient; + private @Nullable HttpClient httpClient; /** * Create a new instance of the {@code HttpClientMessageSender} with a default @@ -58,6 +60,7 @@ public class HttpComponents5MessageSender extends AbstractHttpComponents5Message @Override public HttpClient getHttpClient() { + Assert.notNull(this.httpClient, "'httpClient' must not be null"); return this.httpClient; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/HttpComponentsConnection.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/HttpComponentsConnection.java index 454fd5e3..44ff887f 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/HttpComponentsConnection.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/HttpComponentsConnection.java @@ -33,6 +33,7 @@ import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.ByteArrayEntity; import org.apache.http.protocol.HttpContext; import org.apache.http.util.EntityUtils; +import org.jspecify.annotations.Nullable; import org.springframework.util.Assert; import org.springframework.ws.WebServiceMessage; @@ -54,13 +55,13 @@ public class HttpComponentsConnection extends AbstractHttpSenderConnection { private final HttpPost httpPost; - private final HttpContext httpContext; + private final @Nullable HttpContext httpContext; - private HttpResponse httpResponse; + private @Nullable HttpResponse httpResponse; - private ByteArrayOutputStream requestBuffer; + private @Nullable ByteArrayOutputStream requestBuffer; - protected HttpComponentsConnection(HttpClient httpClient, HttpPost httpPost, HttpContext httpContext) { + protected HttpComponentsConnection(HttpClient httpClient, HttpPost httpPost, @Nullable HttpContext httpContext) { Assert.notNull(httpClient, "httpClient must not be null"); Assert.notNull(httpPost, "httpPost must not be null"); this.httpClient = httpClient; @@ -73,6 +74,7 @@ public class HttpComponentsConnection extends AbstractHttpSenderConnection { } public HttpResponse getHttpResponse() { + Assert.notNull(this.httpResponse, "HttpResponse is not available"); return this.httpResponse; } @@ -107,11 +109,13 @@ public class HttpComponentsConnection extends AbstractHttpSenderConnection { @Override protected OutputStream getRequestOutputStream() throws IOException { + Assert.notNull(this.requestBuffer, "Request OutputStream is not available"); return this.requestBuffer; } @Override protected void onSendAfterWrite(WebServiceMessage message) throws IOException { + Assert.state(this.requestBuffer != null, "onSendBeforeWrite has not been called"); this.httpPost.setEntity(new ByteArrayEntity(this.requestBuffer.toByteArray())); this.requestBuffer = null; if (this.httpContext != null) { @@ -128,17 +132,17 @@ public class HttpComponentsConnection extends AbstractHttpSenderConnection { @Override protected int getResponseCode() throws IOException { - return this.httpResponse.getStatusLine().getStatusCode(); + return getHttpResponse().getStatusLine().getStatusCode(); } @Override protected String getResponseMessage() throws IOException { - return this.httpResponse.getStatusLine().getReasonPhrase(); + return getHttpResponse().getStatusLine().getReasonPhrase(); } @Override protected long getResponseContentLength() throws IOException { - HttpEntity entity = this.httpResponse.getEntity(); + HttpEntity entity = getHttpResponse().getEntity(); if (entity != null) { return entity.getContentLength(); } @@ -147,7 +151,7 @@ public class HttpComponentsConnection extends AbstractHttpSenderConnection { @Override protected InputStream getRawResponseInputStream() throws IOException { - HttpEntity entity = this.httpResponse.getEntity(); + HttpEntity entity = getHttpResponse().getEntity(); if (entity != null) { return entity.getContent(); } @@ -156,7 +160,7 @@ public class HttpComponentsConnection extends AbstractHttpSenderConnection { @Override public Iterator getResponseHeaderNames() throws IOException { - Header[] headers = this.httpResponse.getAllHeaders(); + Header[] headers = getHttpResponse().getAllHeaders(); String[] names = new String[headers.length]; for (int i = 0; i < headers.length; i++) { names[i] = headers[i].getName(); @@ -166,7 +170,7 @@ public class HttpComponentsConnection extends AbstractHttpSenderConnection { @Override public Iterator getResponseHeaders(String name) throws IOException { - Header[] headers = this.httpResponse.getHeaders(name); + Header[] headers = getHttpResponse().getHeaders(name); String[] values = new String[headers.length]; for (int i = 0; i < headers.length; i++) { values[i] = headers[i].getValue(); diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/HttpComponentsMessageSender.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/HttpComponentsMessageSender.java index b5316dba..949b69d2 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/HttpComponentsMessageSender.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/HttpComponentsMessageSender.java @@ -34,6 +34,7 @@ import org.apache.http.client.methods.HttpPost; import org.apache.http.conn.routing.HttpRoute; import org.apache.http.protocol.HTTP; import org.apache.http.protocol.HttpContext; +import org.jspecify.annotations.Nullable; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; @@ -66,7 +67,7 @@ public class HttpComponentsMessageSender extends AbstractHttpWebServiceMessageSe private HttpClient httpClient; - private Credentials credentials; + private @Nullable Credentials credentials; private AuthScope authScope = AuthScope.ANY; @@ -248,7 +249,7 @@ public class HttpComponentsMessageSender extends AbstractHttpWebServiceMessageSe * @param uri the URI to create the context for * @return the context, or {@code null} */ - protected HttpContext createContext(URI uri) { + protected @Nullable HttpContext createContext(URI uri) { return null; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/HttpExchangeConnection.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/HttpExchangeConnection.java index 0cf08da0..9a9a1c75 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/HttpExchangeConnection.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/HttpExchangeConnection.java @@ -30,6 +30,7 @@ import javax.xml.namespace.QName; import com.sun.net.httpserver.HttpExchange; import jakarta.xml.soap.SOAPConstants; +import org.jspecify.annotations.Nullable; import org.springframework.util.Assert; import org.springframework.util.FileCopyUtils; @@ -52,7 +53,7 @@ public class HttpExchangeConnection extends AbstractReceiverConnection private final HttpExchange httpExchange; - private ByteArrayOutputStream responseBuffer; + private @Nullable ByteArrayOutputStream responseBuffer; private int responseStatusCode = HttpTransportConstants.STATUS_ACCEPTED; @@ -93,7 +94,7 @@ public class HttpExchangeConnection extends AbstractReceiverConnection } @Override - public String getErrorMessage() throws IOException { + public @Nullable String getErrorMessage() throws IOException { return null; } @@ -143,6 +144,7 @@ public class HttpExchangeConnection extends AbstractReceiverConnection @Override protected void onSendAfterWrite(WebServiceMessage message) throws IOException { if (!this.chunkedEncoding) { + Assert.state(this.responseBuffer != null, "responseBuffer has not been initialized"); byte[] buf = this.responseBuffer.toByteArray(); this.httpExchange.sendResponseHeaders(this.responseStatusCode, buf.length); OutputStream responseBody = this.httpExchange.getResponseBody(); @@ -170,7 +172,7 @@ public class HttpExchangeConnection extends AbstractReceiverConnection } @Override - public void setFaultCode(QName faultCode) throws IOException { + public void setFaultCode(@Nullable QName faultCode) throws IOException { if (faultCode != null) { if (SOAPConstants.SOAP_SENDER_FAULT.equals(faultCode)) { this.responseStatusCode = HttpTransportConstants.STATUS_BAD_REQUEST; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/HttpServletConnection.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/HttpServletConnection.java index 92699e94..818f4344 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/HttpServletConnection.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/HttpServletConnection.java @@ -28,6 +28,7 @@ import javax.xml.namespace.QName; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import jakarta.xml.soap.SOAPConstants; +import org.jspecify.annotations.Nullable; import org.springframework.ws.WebServiceMessage; import org.springframework.ws.transport.AbstractReceiverConnection; @@ -87,7 +88,7 @@ public class HttpServletConnection extends AbstractReceiverConnection } @Override - public String getErrorMessage() throws IOException { + public @Nullable String getErrorMessage() throws IOException { return null; } @@ -157,7 +158,7 @@ public class HttpServletConnection extends AbstractReceiverConnection } @Override - public void setFaultCode(QName faultCode) throws IOException { + public void setFaultCode(@Nullable QName faultCode) throws IOException { if (faultCode != null) { if (SOAPConstants.SOAP_SENDER_FAULT.equals(faultCode)) { getHttpServletResponse().setStatus(HttpTransportConstants.STATUS_BAD_REQUEST); diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/HttpsUrlConnectionMessageSender.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/HttpsUrlConnectionMessageSender.java index 4b4f0dc1..ca2e4d1c 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/HttpsUrlConnectionMessageSender.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/HttpsUrlConnectionMessageSender.java @@ -30,6 +30,8 @@ import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.InitializingBean; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -50,17 +52,17 @@ public class HttpsUrlConnectionMessageSender extends HttpUrlConnectionMessageSen private String sslProtocol = DEFAULT_SSL_PROTOCOL; - private String sslProvider; + private @Nullable String sslProvider; - private KeyManager[] keyManagers; + private KeyManager @Nullable [] keyManagers; - private TrustManager[] trustManagers; + private TrustManager @Nullable [] trustManagers; - private HostnameVerifier hostnameVerifier; + private @Nullable HostnameVerifier hostnameVerifier; - private SecureRandom rnd; + private @Nullable SecureRandom rnd; - private SSLSocketFactory sslSocketFactory; + private @Nullable SSLSocketFactory sslSocketFactory; /** * Sets the SSL protocol to use. Default is {@code ssl}. diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/JdkHttpClientConnection.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/JdkHttpClientConnection.java index 3e433303..0ab5c8fe 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/JdkHttpClientConnection.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/JdkHttpClientConnection.java @@ -34,6 +34,7 @@ import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.http.HttpStatus; import org.springframework.util.Assert; @@ -62,11 +63,9 @@ public class JdkHttpClientConnection extends AbstractHttpSenderConnection { private final Builder requestBuilder; - private HttpRequest request; + private @Nullable ByteArrayOutputStream requestBuffer; - private ByteArrayOutputStream requestBuffer; - - private HttpResponse response; + private @Nullable HttpResponse response; protected JdkHttpClientConnection(HttpClient httpClient, URI uri, Duration requestTimeout) { @@ -79,19 +78,25 @@ public class JdkHttpClientConnection extends AbstractHttpSenderConnection { this.requestBuilder = HttpRequest.newBuilder(uri).timeout(requestTimeout); } + protected HttpResponse getResponse() { + Assert.notNull(this.response, "HttpResponse is not available"); + return this.response; + } + @Override protected OutputStream getRequestOutputStream() throws IOException { + Assert.notNull(this.requestBuffer, "Request OutputStream is not available"); return this.requestBuffer; } @Override public Iterator getResponseHeaderNames() throws IOException { - return this.response.headers().map().keySet().iterator(); + return getResponse().headers().map().keySet().iterator(); } @Override public Iterator getResponseHeaders(String name) throws IOException { - return this.response.headers().allValues(name).iterator(); + return getResponse().headers().allValues(name).iterator(); } @Override @@ -134,7 +139,7 @@ public class JdkHttpClientConnection extends AbstractHttpSenderConnection { @Override protected InputStream getRawResponseInputStream() throws IOException { - return this.response.body(); + return getResponse().body(); } @Override @@ -144,13 +149,12 @@ public class JdkHttpClientConnection extends AbstractHttpSenderConnection { @Override protected void onSendAfterWrite(WebServiceMessage message) throws IOException { - + Assert.state(this.requestBuffer != null, "onSendBeforeWrite has not been called"); byte[] body = this.requestBuffer.toByteArray(); - this.request = this.requestBuilder.POST(BodyPublishers.ofByteArray(body)).build(); - + HttpRequest request = this.requestBuilder.POST(BodyPublishers.ofByteArray(body)).build(); try { - this.response = this.httpClient.send(this.request, BodyHandlers.ofInputStream()); + this.response = this.httpClient.send(request, BodyHandlers.ofInputStream()); } catch (InterruptedException ex) { Thread.currentThread().interrupt(); diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/JdkHttpClientMessageSender.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/JdkHttpClientMessageSender.java index 712aa3af..3e0a4be0 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/JdkHttpClientMessageSender.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/JdkHttpClientMessageSender.java @@ -44,7 +44,7 @@ public class JdkHttpClientMessageSender extends AbstractHttpWebServiceMessageSen private static final Duration DEFAULT_REQUEST_TIMEOUT = Duration.ofSeconds(60); - private HttpClient httpClient; + private @Nullable HttpClient httpClient; private Duration connectionTimeout = DEFAULT_CONNECTION_TIMEOUT; @@ -63,17 +63,17 @@ public class JdkHttpClientMessageSender extends AbstractHttpWebServiceMessageSen this.httpClient = httpClient; } - public void setConnectionTimeout(@Nullable Duration connectionTimeout) { + public void setConnectionTimeout(Duration connectionTimeout) { this.connectionTimeout = connectionTimeout; } - public void setRequestTimeout(@Nullable Duration requestTimeout) { + public void setRequestTimeout(Duration requestTimeout) { this.requestTimeout = requestTimeout; } @Override public WebServiceConnection createConnection(URI uri) throws IOException { - + Assert.state(this.httpClient != null, "HttpClient is not available"); JdkHttpClientConnection connection = new JdkHttpClientConnection(this.httpClient, uri, this.requestTimeout); if (isAcceptGzipEncoding()) { diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/MessageDispatcherServlet.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/MessageDispatcherServlet.java index 234f330c..e1e6bcb6 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/MessageDispatcherServlet.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/MessageDispatcherServlet.java @@ -16,10 +16,12 @@ package org.springframework.ws.transport.http; +import java.util.Collections; import java.util.Map; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.jspecify.annotations.Nullable; import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.BeanInitializationException; @@ -112,27 +114,31 @@ public class MessageDispatcherServlet extends FrameworkServlet { private String messageReceiverHandlerAdapterBeanName = DEFAULT_MESSAGE_RECEIVER_HANDLER_ADAPTER_BEAN_NAME; /** The {@link WebServiceMessageReceiverHandlerAdapter} used by this servlet. */ + @SuppressWarnings("NullAway.Init") private WebServiceMessageReceiverHandlerAdapter messageReceiverHandlerAdapter; private String wsdlDefinitionHandlerAdapterBeanName = DEFAULT_WSDL_DEFINITION_HANDLER_ADAPTER_BEAN_NAME; /** The {@link WsdlDefinitionHandlerAdapter} used by this servlet. */ + @SuppressWarnings("NullAway.Init") private WsdlDefinitionHandlerAdapter wsdlDefinitionHandlerAdapter; private String xsdSchemaHandlerAdapterBeanName = DEFAULT_XSD_SCHEMA_HANDLER_ADAPTER_BEAN_NAME; /** The {@link XsdSchemaHandlerAdapter} used by this servlet. */ + @SuppressWarnings("NullAway.Init") private XsdSchemaHandlerAdapter xsdSchemaHandlerAdapter; private String messageReceiverBeanName = DEFAULT_MESSAGE_RECEIVER_BEAN_NAME; /** The {@link WebServiceMessageReceiver} used by this servlet. */ + @SuppressWarnings("NullAway.Init") private WebServiceMessageReceiver messageReceiver; /** Keys are bean names, values are {@link WsdlDefinition WsdlDefinitions}. */ - private Map wsdlDefinitions; + private Map wsdlDefinitions = Collections.emptyMap(); - private Map xsdSchemas; + private Map xsdSchemas = Collections.emptyMap(); private boolean transformWsdlLocations = false; @@ -142,7 +148,8 @@ public class MessageDispatcherServlet extends FrameworkServlet { * Public constructor, necessary for some Web application servers. */ public MessageDispatcherServlet() { - this(null); + super(); + this.defaultStrategiesHelper = new DefaultStrategiesHelper(MessageDispatcherServlet.class); } /** @@ -337,7 +344,7 @@ public class MessageDispatcherServlet extends FrameworkServlet { * @param request the {@code HttpServletRequest} * @return a definition, or {@code null} */ - protected WsdlDefinition getWsdlDefinition(HttpServletRequest request) { + protected @Nullable WsdlDefinition getWsdlDefinition(HttpServletRequest request) { if (HttpTransportConstants.METHOD_GET.equals(request.getMethod()) && request.getRequestURI().endsWith(WSDL_SUFFIX_NAME)) { String fileName = WebUtils.extractFilenameFromUrlPath(request.getRequestURI()); @@ -358,7 +365,7 @@ public class MessageDispatcherServlet extends FrameworkServlet { * @param request the {@code HttpServletRequest} * @return a schema, or {@code null} */ - protected XsdSchema getXsdSchema(HttpServletRequest request) { + protected @Nullable XsdSchema getXsdSchema(HttpServletRequest request) { if (HttpTransportConstants.METHOD_GET.equals(request.getMethod()) && request.getRequestURI().endsWith(XSD_SUFFIX_NAME)) { String fileName = WebUtils.extractFilenameFromUrlPath(request.getRequestURI()); @@ -459,7 +466,7 @@ public class MessageDispatcherServlet extends FrameworkServlet { catch (NoSuchBeanDefinitionException ex) { this.messageReceiver = this.defaultStrategiesHelper.getDefaultStrategy(WebServiceMessageReceiver.class, context); - if (this.messageReceiver instanceof BeanNameAware) { + if (this.messageReceiver instanceof BeanNameAware && getServletName() != null) { ((BeanNameAware) this.messageReceiver).setBeanName(getServletName()); } if (this.logger.isDebugEnabled()) { diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/WebServiceMessageReceiverHandlerAdapter.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/WebServiceMessageReceiverHandlerAdapter.java index cebac6cf..90042428 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/WebServiceMessageReceiverHandlerAdapter.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/WebServiceMessageReceiverHandlerAdapter.java @@ -18,6 +18,7 @@ package org.springframework.ws.transport.http; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.jspecify.annotations.Nullable; import org.springframework.web.servlet.HandlerAdapter; import org.springframework.web.servlet.ModelAndView; @@ -49,7 +50,7 @@ public class WebServiceMessageReceiverHandlerAdapter extends WebServiceMessageRe implements HandlerAdapter { @Override - public ModelAndView handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, + public @Nullable ModelAndView handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler) throws Exception { if (HttpTransportConstants.METHOD_POST.equals(httpServletRequest.getMethod())) { WebServiceConnection connection = new HttpServletConnection(httpServletRequest, httpServletResponse); diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/WsdlDefinitionHandlerAdapter.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/WsdlDefinitionHandlerAdapter.java index c1fe2697..27db8baf 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/WsdlDefinitionHandlerAdapter.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/WsdlDefinitionHandlerAdapter.java @@ -27,9 +27,11 @@ import javax.xml.transform.stream.StreamResult; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.jspecify.annotations.Nullable; import org.w3c.dom.Document; import org.springframework.beans.factory.InitializingBean; +import org.springframework.util.Assert; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.servlet.HandlerAdapter; import org.springframework.web.servlet.ModelAndView; @@ -95,9 +97,9 @@ public class WsdlDefinitionHandlerAdapter extends LocationTransformerObjectSuppo private String schemaLocationExpression = DEFAULT_SCHEMA_LOCATION_EXPRESSION; - private XPathExpression locationXPathExpression; + private @Nullable XPathExpression locationXPathExpression; - private XPathExpression schemaLocationXPathExpression; + private @Nullable XPathExpression schemaLocationXPathExpression; private boolean transformLocations = false; @@ -141,7 +143,7 @@ public class WsdlDefinitionHandlerAdapter extends LocationTransformerObjectSuppo } @Override - public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) + public @Nullable ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (HttpTransportConstants.METHOD_GET.equals(request.getMethod())) { WsdlDefinition definition = (WsdlDefinition) handler; @@ -199,6 +201,7 @@ public class WsdlDefinitionHandlerAdapter extends LocationTransformerObjectSuppo * @see #transformLocation(String,jakarta.servlet.http.HttpServletRequest) */ protected void transformLocations(Document definitionDocument, HttpServletRequest request) throws Exception { + Assert.notNull(this.locationXPathExpression, "locationXPathExpression is required"); transformLocations(this.locationXPathExpression, definitionDocument, request); } @@ -215,6 +218,7 @@ public class WsdlDefinitionHandlerAdapter extends LocationTransformerObjectSuppo * @see #transformLocation(String,jakarta.servlet.http.HttpServletRequest) */ protected void transformSchemaLocations(Document definitionDocument, HttpServletRequest request) throws Exception { + Assert.notNull(this.schemaLocationXPathExpression, "schemaLocationXPathExpression is required"); transformLocations(this.schemaLocationXPathExpression, definitionDocument, request); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/WsdlDefinitionHttpHandler.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/WsdlDefinitionHttpHandler.java index c093094a..b8380d52 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/WsdlDefinitionHttpHandler.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/WsdlDefinitionHttpHandler.java @@ -42,6 +42,7 @@ public class WsdlDefinitionHttpHandler extends TransformerObjectSupport implemen private static final String CONTENT_TYPE = "text/xml"; + @SuppressWarnings("NullAway.Init") private WsdlDefinition definition; public WsdlDefinitionHttpHandler() { diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/XsdSchemaHandlerAdapter.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/XsdSchemaHandlerAdapter.java index a693988a..25ca49b5 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/XsdSchemaHandlerAdapter.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/XsdSchemaHandlerAdapter.java @@ -27,6 +27,7 @@ import javax.xml.transform.stream.StreamResult; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.jspecify.annotations.Nullable; import org.w3c.dom.Document; import org.springframework.beans.factory.InitializingBean; @@ -65,6 +66,7 @@ public class XsdSchemaHandlerAdapter extends LocationTransformerObjectSupport private String schemaLocationExpression = DEFAULT_SCHEMA_LOCATION_EXPRESSION; + @SuppressWarnings("NullAway.Init") private XPathExpression schemaLocationXPathExpression; private boolean transformSchemaLocations = false; @@ -89,7 +91,7 @@ public class XsdSchemaHandlerAdapter extends LocationTransformerObjectSupport } @Override - public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) + public @Nullable ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (HttpTransportConstants.METHOD_GET.equals(request.getMethod())) { Source schemaSource = getSchemaSource((XsdSchema) handler); diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/package-info.java index e54a45e3..5f2a0157 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/package-info.java @@ -20,4 +20,7 @@ * access, and the {@code HttpUrlConnectionMessageSender} and * {@code CommonsHttpMessageSender} for client-side access. */ +@NullMarked package org.springframework.ws.transport.http; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/support/AbstractAnnotationConfigMessageDispatcherServletInitializer.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/support/AbstractAnnotationConfigMessageDispatcherServletInitializer.java index d457a6e5..1dac23e8 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/support/AbstractAnnotationConfigMessageDispatcherServletInitializer.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/support/AbstractAnnotationConfigMessageDispatcherServletInitializer.java @@ -16,6 +16,8 @@ package org.springframework.ws.transport.http.support; +import org.jspecify.annotations.Nullable; + import org.springframework.context.annotation.Configuration; import org.springframework.util.ObjectUtils; import org.springframework.web.WebApplicationInitializer; @@ -48,7 +50,7 @@ public abstract class AbstractAnnotationConfigMessageDispatcherServletInitialize * Returns {@code null} if {@link #getRootConfigClasses()} returns {@code null}. */ @Override - protected WebApplicationContext createRootApplicationContext() { + protected @Nullable WebApplicationContext createRootApplicationContext() { Class[] configClasses = getRootConfigClasses(); if (!ObjectUtils.isEmpty(configClasses)) { AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext(); diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/support/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/support/package-info.java index f3b2a67b..759afcfc 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/support/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/support/package-info.java @@ -17,4 +17,7 @@ /** * Support classes for handling messages via HTTP. */ +@NullMarked package org.springframework.ws.transport.http.support; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/package-info.java index 775f1042..ff8d68db 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/package-info.java @@ -17,4 +17,7 @@ /** * Contains the TransportRequest and TransportResponse interfaces. */ +@NullMarked package org.springframework.ws.transport; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/support/AbstractAsyncStandaloneMessageReceiver.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/support/AbstractAsyncStandaloneMessageReceiver.java index e7df2c2c..1db6d3e7 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/support/AbstractAsyncStandaloneMessageReceiver.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/support/AbstractAsyncStandaloneMessageReceiver.java @@ -16,6 +16,8 @@ package org.springframework.ws.transport.support; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.BeanNameAware; import org.springframework.core.task.SimpleAsyncTaskExecutor; import org.springframework.core.task.TaskExecutor; @@ -33,9 +35,10 @@ public abstract class AbstractAsyncStandaloneMessageReceiver extends AbstractSta /** Default thread name prefix. */ public final String DEFAULT_THREAD_NAME_PREFIX = ClassUtils.getShortName(getClass()) + "-"; + @SuppressWarnings("NullAway.Init") private TaskExecutor taskExecutor; - private String beanName; + private @Nullable String beanName; /** * Set the Spring {@link TaskExecutor} to use for running the listener threads. diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/support/SimpleWebServiceMessageReceiverObjectSupport.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/support/SimpleWebServiceMessageReceiverObjectSupport.java index 46e608d7..ec6ec008 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/support/SimpleWebServiceMessageReceiverObjectSupport.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/support/SimpleWebServiceMessageReceiverObjectSupport.java @@ -32,6 +32,7 @@ import org.springframework.ws.transport.WebServiceMessageReceiver; public abstract class SimpleWebServiceMessageReceiverObjectSupport extends WebServiceMessageReceiverObjectSupport implements InitializingBean { + @SuppressWarnings("NullAway.Init") private WebServiceMessageReceiver messageReceiver; /** diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/support/WebServiceMessageReceiverObjectSupport.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/support/WebServiceMessageReceiverObjectSupport.java index 24544bf3..70890c5f 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/support/WebServiceMessageReceiverObjectSupport.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/support/WebServiceMessageReceiverObjectSupport.java @@ -51,6 +51,7 @@ public abstract class WebServiceMessageReceiverObjectSupport implements Initiali /** Logger available to subclasses. */ protected final Log logger = LogFactory.getLog(getClass()); + @SuppressWarnings("NullAway.Init") private WebServiceMessageFactory messageFactory; /** Returns the {@code WebServiceMessageFactory}. */ @@ -88,6 +89,7 @@ public abstract class WebServiceMessageReceiverObjectSupport implements Initiali try { WebServiceMessage request = connection.receive(getMessageFactory()); + Assert.notNull(request, "no WebServiceMessage received"); MessageContext messageContext = new DefaultMessageContext(request, getMessageFactory()); receiver.receive(messageContext); if (messageContext.hasResponse()) { diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/support/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/support/package-info.java index 7966d3a7..1640ebd1 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/support/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/support/package-info.java @@ -17,4 +17,7 @@ /** * Classes supporting the org.springframework.ws.transport package. */ +@NullMarked package org.springframework.ws.transport.support; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/wsdl/WsdlDefinitionException.java b/spring-ws-core/src/main/java/org/springframework/ws/wsdl/WsdlDefinitionException.java index b08b3937..00e21cbc 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/wsdl/WsdlDefinitionException.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/wsdl/WsdlDefinitionException.java @@ -16,6 +16,8 @@ package org.springframework.ws.wsdl; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.WebServiceException; /** @@ -31,7 +33,7 @@ public class WsdlDefinitionException extends WebServiceException { super(reason); } - public WsdlDefinitionException(String reason, Throwable throwable) { + public WsdlDefinitionException(@Nullable String reason, Throwable throwable) { super(reason, throwable); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/wsdl/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/wsdl/package-info.java index b0a64276..42b58de0 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/wsdl/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/wsdl/package-info.java @@ -18,4 +18,7 @@ * Provides the WSDL functionality of the Spring Web Services framework. Contains the * WsdlDefinition and related interfaces. */ +@NullMarked package org.springframework.ws.wsdl; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/DefaultWsdl11Definition.java b/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/DefaultWsdl11Definition.java index d711c2a0..3e6d850e 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/DefaultWsdl11Definition.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/DefaultWsdl11Definition.java @@ -20,6 +20,8 @@ import java.util.Properties; import javax.xml.transform.Source; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.InitializingBean; import org.springframework.util.StringUtils; import org.springframework.ws.wsdl.wsdl11.provider.DefaultMessagesProvider; @@ -63,7 +65,7 @@ public class DefaultWsdl11Definition implements Wsdl11Definition, InitializingBe private final ProviderBasedWsdl4jDefinition delegate = new ProviderBasedWsdl4jDefinition(); - private String serviceName; + private @Nullable String serviceName; /** Creates a new instance of the {@link DefaultWsdl11Definition}. */ public DefaultWsdl11Definition() { @@ -175,7 +177,7 @@ public class DefaultWsdl11Definition implements Wsdl11Definition, InitializingBe @Override public void afterPropertiesSet() throws Exception { - if (!StringUtils.hasText(this.delegate.getTargetNamespace()) && this.typesProvider.getSchemaCollection() != null + if (!StringUtils.hasText(this.delegate.getTargetNamespace()) && this.typesProvider.getSchemaCollection().getXsdSchemas().length > 0) { XsdSchema schema = this.typesProvider.getSchemaCollection().getXsdSchemas()[0]; setTargetNamespace(schema.getTargetNamespace()); diff --git a/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/ProviderBasedWsdl4jDefinition.java b/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/ProviderBasedWsdl4jDefinition.java index dd0298f5..02e14af1 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/ProviderBasedWsdl4jDefinition.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/ProviderBasedWsdl4jDefinition.java @@ -20,6 +20,8 @@ import javax.wsdl.Definition; import javax.wsdl.WSDLException; import javax.wsdl.factory.WSDLFactory; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.InitializingBean; import org.springframework.util.Assert; import org.springframework.ws.wsdl.wsdl11.provider.BindingsProvider; @@ -62,19 +64,19 @@ public class ProviderBasedWsdl4jDefinition extends Wsdl4jDefinition implements I /** The prefix used to register the target namespace in the WSDL. */ public static final String TARGET_NAMESPACE_PREFIX = "tns"; - private ImportsProvider importsProvider; + private @Nullable ImportsProvider importsProvider; - private TypesProvider typesProvider; + private @Nullable TypesProvider typesProvider; - private MessagesProvider messagesProvider; + private @Nullable MessagesProvider messagesProvider; - private PortTypesProvider portTypesProvider; + private @Nullable PortTypesProvider portTypesProvider; - private BindingsProvider bindingsProvider; + private @Nullable BindingsProvider bindingsProvider; - private ServicesProvider servicesProvider; + private @Nullable ServicesProvider servicesProvider; - private String targetNamespace; + private @Nullable String targetNamespace; /** * Returns the {@link ImportsProvider} for this definition. @@ -82,7 +84,7 @@ public class ProviderBasedWsdl4jDefinition extends Wsdl4jDefinition implements I * Default is {@code null}, indicating that no {@code <import>} will be created * @return the import provider; or {@code null} */ - public ImportsProvider getImportsProvider() { + public @Nullable ImportsProvider getImportsProvider() { return this.importsProvider; } @@ -102,7 +104,7 @@ public class ProviderBasedWsdl4jDefinition extends Wsdl4jDefinition implements I * Defaults to {@code null}, indicating that no {@code <types>} will be created * @return the types provider; or {@code null} */ - public TypesProvider getTypesProvider() { + public @Nullable TypesProvider getTypesProvider() { return this.typesProvider; } @@ -123,7 +125,7 @@ public class ProviderBasedWsdl4jDefinition extends Wsdl4jDefinition implements I * created * @return the messages provider; or {@code null} */ - public MessagesProvider getMessagesProvider() { + public @Nullable MessagesProvider getMessagesProvider() { return this.messagesProvider; } @@ -145,7 +147,7 @@ public class ProviderBasedWsdl4jDefinition extends Wsdl4jDefinition implements I * created * @return the port types provider; or {@code null} */ - public PortTypesProvider getPortTypesProvider() { + public @Nullable PortTypesProvider getPortTypesProvider() { return this.portTypesProvider; } @@ -167,7 +169,7 @@ public class ProviderBasedWsdl4jDefinition extends Wsdl4jDefinition implements I * created * @return the binding provider; or {@code null} */ - public BindingsProvider getBindingsProvider() { + public @Nullable BindingsProvider getBindingsProvider() { return this.bindingsProvider; } @@ -189,7 +191,7 @@ public class ProviderBasedWsdl4jDefinition extends Wsdl4jDefinition implements I * created * @return the services provider; or {@code null} */ - public ServicesProvider getServicesProvider() { + public @Nullable ServicesProvider getServicesProvider() { return this.servicesProvider; } @@ -209,7 +211,7 @@ public class ProviderBasedWsdl4jDefinition extends Wsdl4jDefinition implements I * @return the target namespace * @see javax.wsdl.Definition#getTargetNamespace() */ - public String getTargetNamespace() { + public @Nullable String getTargetNamespace() { return this.targetNamespace; } @@ -224,11 +226,11 @@ public class ProviderBasedWsdl4jDefinition extends Wsdl4jDefinition implements I @Override public void afterPropertiesSet() throws WSDLException { - Assert.notNull(getTargetNamespace(), "'targetNamespace' is required"); + Assert.notNull(this.targetNamespace, "'targetNamespace' is required"); WSDLFactory wsdlFactory = WSDLFactory.newInstance(); Definition definition = wsdlFactory.newDefinition(); definition.setTargetNamespace(getTargetNamespace()); - definition.addNamespace(TARGET_NAMESPACE_PREFIX, getTargetNamespace()); + definition.addNamespace(TARGET_NAMESPACE_PREFIX, this.targetNamespace); if (this.importsProvider != null) { this.importsProvider.addImports(definition); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/SimpleWsdl11Definition.java b/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/SimpleWsdl11Definition.java index 893df556..9d6dcff3 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/SimpleWsdl11Definition.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/SimpleWsdl11Definition.java @@ -20,6 +20,7 @@ import java.io.IOException; import javax.xml.transform.Source; +import org.jspecify.annotations.Nullable; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; @@ -41,7 +42,7 @@ import org.springframework.xml.transform.ResourceSource; */ public class SimpleWsdl11Definition implements Wsdl11Definition, InitializingBean { - private Resource wsdlResource; + private @Nullable Resource wsdlResource; /** * Create a new instance of the {@link SimpleWsdl11Definition} class. @@ -71,6 +72,7 @@ public class SimpleWsdl11Definition implements Wsdl11Definition, InitializingBea @Override public Source getSource() { + Assert.notNull(this.wsdlResource, "wsdl is required"); try { XMLReader xmlReader = SaxUtils.namespaceAwareXmlReader(); xmlReader.setFeature("http://xml.org/sax/features/namespace-prefixes", true); diff --git a/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/Wsdl4jDefinition.java b/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/Wsdl4jDefinition.java index fb7d616d..49c2cb8d 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/Wsdl4jDefinition.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/Wsdl4jDefinition.java @@ -23,6 +23,7 @@ import javax.wsdl.xml.WSDLWriter; import javax.xml.transform.Source; import javax.xml.transform.dom.DOMSource; +import org.jspecify.annotations.Nullable; import org.w3c.dom.Document; import org.springframework.util.Assert; @@ -42,7 +43,7 @@ import org.springframework.ws.wsdl.WsdlDefinitionException; */ public class Wsdl4jDefinition implements Wsdl11Definition { - private Definition definition; + private @Nullable Definition definition; /** WSDL4J is not thread safe, hence the need for a monitor. */ private final Object monitor = new Object(); @@ -63,7 +64,7 @@ public class Wsdl4jDefinition implements Wsdl11Definition { } /** Returns the WSDL4J {@code Definition}. */ - public Definition getDefinition() { + public @Nullable Definition getDefinition() { synchronized (this.monitor) { return this.definition; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/package-info.java index 67da6e82..0d10ab6e 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/package-info.java @@ -17,4 +17,7 @@ /** * Contains interfaces and classes specific to WSDL 1.1. */ +@NullMarked package org.springframework.ws.wsdl.wsdl11; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/provider/AbstractPortTypesProvider.java b/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/provider/AbstractPortTypesProvider.java index 38a2758c..aafef1f6 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/provider/AbstractPortTypesProvider.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/provider/AbstractPortTypesProvider.java @@ -31,8 +31,10 @@ import javax.xml.namespace.QName; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.util.StringUtils; @@ -48,10 +50,10 @@ public abstract class AbstractPortTypesProvider implements PortTypesProvider { /** Logger available to subclasses. */ protected final Log logger = LogFactory.getLog(getClass()); - private String portTypeName; + private @Nullable String portTypeName; /** Returns the port type name used for this definition. */ - public String getPortTypeName() { + public @Nullable String getPortTypeName() { return this.portTypeName; } @@ -116,24 +118,26 @@ public abstract class AbstractPortTypesProvider implements PortTypesProvider { Operation operation = definition.createOperation(); operation.setName(operationName); List messages = operations.get(operationName); - for (Message message : messages) { - if (isInputMessage(message)) { - Input input = definition.createInput(); - input.setMessage(message); - populateInput(definition, input); - operation.setInput(input); - } - else if (isOutputMessage(message)) { - Output output = definition.createOutput(); - output.setMessage(message); - populateOutput(definition, output); - operation.setOutput(output); - } - else if (isFaultMessage(message)) { - Fault fault = definition.createFault(); - fault.setMessage(message); - populateFault(definition, fault); - operation.addFault(fault); + if (!CollectionUtils.isEmpty(messages)) { + for (Message message : messages) { + if (isInputMessage(message)) { + Input input = definition.createInput(); + input.setMessage(message); + populateInput(definition, input); + operation.setInput(input); + } + else if (isOutputMessage(message)) { + Output output = definition.createOutput(); + output.setMessage(message); + populateOutput(definition, output); + operation.setOutput(output); + } + else if (isFaultMessage(message)) { + Fault fault = definition.createFault(); + fault.setMessage(message); + populateFault(definition, fault); + operation.addFault(fault); + } } } operation.setStyle(getOperationType(operation)); @@ -153,7 +157,7 @@ public abstract class AbstractPortTypesProvider implements PortTypesProvider { * @param message the WSDL4J {@code Message} * @return the operation name; or {@code null} */ - protected abstract String getOperationName(Message message); + protected abstract @Nullable String getOperationName(Message message); /** * Indicates whether the given name name should be included as {@link Input} message @@ -224,7 +228,7 @@ public abstract class AbstractPortTypesProvider implements PortTypesProvider { * @param operation the WSDL4J {@code Operation} * @return the operation type for the operation */ - protected OperationType getOperationType(Operation operation) { + protected @Nullable OperationType getOperationType(Operation operation) { if (operation.getInput() != null && operation.getOutput() != null) { return OperationType.REQUEST_RESPONSE; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/provider/DefaultConcretePartProvider.java b/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/provider/DefaultConcretePartProvider.java index 82f90585..2add2b67 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/provider/DefaultConcretePartProvider.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/provider/DefaultConcretePartProvider.java @@ -35,6 +35,7 @@ import javax.xml.namespace.QName; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -55,12 +56,12 @@ public class DefaultConcretePartProvider implements BindingsProvider, ServicesPr /** Logger available to subclasses. */ protected final Log logger = LogFactory.getLog(getClass()); - private String bindingSuffix; + private @Nullable String bindingSuffix; - private String serviceName; + private @Nullable String serviceName; /** Returns the service name. */ - public String getServiceName() { + public @Nullable String getServiceName() { return this.serviceName; } @@ -72,7 +73,7 @@ public class DefaultConcretePartProvider implements BindingsProvider, ServicesPr } /** Returns the suffix to append to the port type name to obtain the binding name. */ - public String getBindingSuffix() { + public @Nullable String getBindingSuffix() { return this.bindingSuffix; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/provider/InliningXsdSchemaTypesProvider.java b/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/provider/InliningXsdSchemaTypesProvider.java index af12e1d5..f985947f 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/provider/InliningXsdSchemaTypesProvider.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/provider/InliningXsdSchemaTypesProvider.java @@ -26,6 +26,7 @@ import javax.xml.transform.dom.DOMResult; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -50,7 +51,7 @@ public class InliningXsdSchemaTypesProvider extends TransformerObjectSupport imp /** The prefix used to register the schema namespace in the WSDL. */ public static final String SCHEMA_PREFIX = "sch"; - private XsdSchemaCollection schemaCollection; + private @Nullable XsdSchemaCollection schemaCollection; /** * Sets the single XSD schema to inline. Either this property, or @@ -71,6 +72,7 @@ public class InliningXsdSchemaTypesProvider extends TransformerObjectSupport imp /** Returns the XSD schema collection to inline. */ public XsdSchemaCollection getSchemaCollection() { + Assert.notNull(this.schemaCollection, "setting 'schema' or 'schemaCollection' is required"); return this.schemaCollection; } @@ -84,9 +86,8 @@ public class InliningXsdSchemaTypesProvider extends TransformerObjectSupport imp @Override public void addTypes(Definition definition) throws WSDLException { - Assert.notNull(getSchemaCollection(), "setting 'schema' or 'schemaCollection' is required"); Types types = definition.createTypes(); - XsdSchema[] schemas = this.schemaCollection.getXsdSchemas(); + XsdSchema[] schemas = getSchemaCollection().getXsdSchemas(); for (int i = 0; i < schemas.length; i++) { if (logger.isDebugEnabled()) { logger.debug("Inlining " + schemas[i]); diff --git a/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/provider/Soap11Provider.java b/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/provider/Soap11Provider.java index 4452d529..f65ba40a 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/provider/Soap11Provider.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/provider/Soap11Provider.java @@ -38,6 +38,8 @@ import javax.wsdl.extensions.soap.SOAPFault; import javax.wsdl.extensions.soap.SOAPOperation; import javax.xml.namespace.QName; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; /** @@ -67,7 +69,7 @@ public class Soap11Provider extends DefaultConcretePartProvider { private Properties soapActions = new Properties(); - private String locationUri; + private @Nullable String locationUri; /** * Constructs a new version of the {@link Soap11Provider}. @@ -123,7 +125,7 @@ public class Soap11Provider extends DefaultConcretePartProvider { } /** Returns the value used for the SOAP Address location attribute value. */ - public String getLocationUri() { + public @Nullable String getLocationUri() { return this.locationUri; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/provider/Soap12Provider.java b/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/provider/Soap12Provider.java index 113d5857..3af96b22 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/provider/Soap12Provider.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/provider/Soap12Provider.java @@ -37,6 +37,8 @@ import javax.wsdl.extensions.soap12.SOAP12Fault; import javax.wsdl.extensions.soap12.SOAP12Operation; import javax.xml.namespace.QName; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; /** @@ -66,7 +68,7 @@ public class Soap12Provider extends DefaultConcretePartProvider { private Properties soapActions = new Properties(); - private String locationUri; + private @Nullable String locationUri; /** * Constructs a new version of the {@link Soap12Provider}. @@ -122,7 +124,7 @@ public class Soap12Provider extends DefaultConcretePartProvider { } /** Returns the value used for the SOAP Address location attribute value. */ - public String getLocationUri() { + public @Nullable String getLocationUri() { return this.locationUri; } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/provider/SuffixBasedPortTypesProvider.java b/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/provider/SuffixBasedPortTypesProvider.java index 8d71b88f..174972ae 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/provider/SuffixBasedPortTypesProvider.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/provider/SuffixBasedPortTypesProvider.java @@ -18,6 +18,8 @@ package org.springframework.ws.wsdl.wsdl11.provider; import javax.wsdl.Message; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; /** @@ -95,7 +97,7 @@ public class SuffixBasedPortTypesProvider extends AbstractPortTypesProvider { } @Override - protected String getOperationName(Message message) { + protected @Nullable String getOperationName(Message message) { String messageName = getMessageName(message); if (messageName != null) { if (messageName.endsWith(getRequestSuffix())) { @@ -156,7 +158,7 @@ public class SuffixBasedPortTypesProvider extends AbstractPortTypesProvider { return messageName != null && messageName.endsWith(getFaultSuffix()); } - private String getMessageName(Message message) { + private @Nullable String getMessageName(Message message) { return message.getQName().getLocalPart(); } diff --git a/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/provider/package-info.java b/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/provider/package-info.java index 7beccb0c..eb3bba06 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/provider/package-info.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/wsdl/wsdl11/provider/package-info.java @@ -17,4 +17,7 @@ /** * Provides a contribution strategy for WSDL definitions. */ +@NullMarked package org.springframework.ws.wsdl.wsdl11.provider; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-core/src/test/java/org/springframework/ws/server/endpoint/CompositeEndpointExceptionResolverTests.java b/spring-ws-core/src/test/java/org/springframework/ws/server/endpoint/CompositeEndpointExceptionResolverTests.java index 285ab116..d1c4f6db 100644 --- a/spring-ws-core/src/test/java/org/springframework/ws/server/endpoint/CompositeEndpointExceptionResolverTests.java +++ b/spring-ws-core/src/test/java/org/springframework/ws/server/endpoint/CompositeEndpointExceptionResolverTests.java @@ -75,7 +75,7 @@ class CompositeEndpointExceptionResolverTests { } @Override - protected void logException(Exception ex, MessageContext messageContext) { + protected void logException(MessageContext messageContext, Exception ex) { if (this.logException) { throw new IllegalStateException("Log exception already called"); } diff --git a/spring-ws-core/src/test/java/org/springframework/ws/soap/addressing/server/SimpleActionEndpointMappingTests.java b/spring-ws-core/src/test/java/org/springframework/ws/soap/addressing/server/SimpleActionEndpointMappingTests.java index 6a15d53c..1dd6284b 100644 --- a/spring-ws-core/src/test/java/org/springframework/ws/soap/addressing/server/SimpleActionEndpointMappingTests.java +++ b/spring-ws-core/src/test/java/org/springframework/ws/soap/addressing/server/SimpleActionEndpointMappingTests.java @@ -23,6 +23,7 @@ import java.util.Map; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.context.support.StaticApplicationContext; import org.springframework.ws.context.DefaultMessageContext; import org.springframework.ws.context.MessageContext; import org.springframework.ws.server.EndpointInterceptor; @@ -57,6 +58,7 @@ class SimpleActionEndpointMappingTests extends AbstractWsAddressingTests { this.mapping.setPostInterceptors(new EndpointInterceptor[] { new PayloadValidatingInterceptor() }); this.mapping.setAddress(new URI("mailto:fabrikam@example.com")); this.mapping.setActionMap(map); + this.mapping.setApplicationContext(new StaticApplicationContext()); this.mapping.afterPropertiesSet(); } diff --git a/spring-ws-core/src/test/java/org/springframework/ws/transport/http/HttpComponents5MessageSenderTests.java b/spring-ws-core/src/test/java/org/springframework/ws/transport/http/HttpComponents5MessageSenderTests.java index e53bf754..d0a5e7b4 100644 --- a/spring-ws-core/src/test/java/org/springframework/ws/transport/http/HttpComponents5MessageSenderTests.java +++ b/spring-ws-core/src/test/java/org/springframework/ws/transport/http/HttpComponents5MessageSenderTests.java @@ -33,7 +33,7 @@ class HttpComponents5MessageSenderTests { @Test void afterPropertiesSetShouldProperlyInitializeHttpClient() throws Exception { HttpComponents5MessageSender messageSender = new HttpComponents5MessageSender(); - assertThat(messageSender.getHttpClient()).isNull(); + assertThat(messageSender).hasFieldOrPropertyWithValue("httpClient", null); messageSender.setConnectionTimeout(Duration.ofSeconds(1)); messageSender.afterPropertiesSet(); diff --git a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/AbstractWsSecurityInterceptor.java b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/AbstractWsSecurityInterceptor.java index 92f6e8ee..41a0bc0b 100644 --- a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/AbstractWsSecurityInterceptor.java +++ b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/AbstractWsSecurityInterceptor.java @@ -18,11 +18,13 @@ package org.springframework.ws.soap.security; import java.util.Iterator; import java.util.Locale; +import java.util.Objects; import javax.xml.namespace.QName; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.util.Assert; import org.springframework.ws.client.WebServiceClientException; @@ -69,7 +71,7 @@ public abstract class AbstractWsSecurityInterceptor implements SoapEndpointInter private boolean skipValidationIfNoHeaderPresent = false; - private EndpointExceptionResolver exceptionResolver; + private @Nullable EndpointExceptionResolver exceptionResolver; /** * Indicates whether server-side incoming request are to be validated. Defaults to @@ -197,7 +199,7 @@ public abstract class AbstractWsSecurityInterceptor implements SoapEndpointInter } @Override - public void afterCompletion(MessageContext messageContext, Object endpoint, Exception ex) { + public void afterCompletion(MessageContext messageContext, Object endpoint, @Nullable Exception ex) { cleanUp(); } @@ -279,7 +281,8 @@ public abstract class AbstractWsSecurityInterceptor implements SoapEndpointInter } @Override - public void afterCompletion(MessageContext messageContext, Exception ex) throws WebServiceClientException { + public void afterCompletion(MessageContext messageContext, @Nullable Exception ex) + throws WebServiceClientException { cleanUp(); } @@ -320,7 +323,7 @@ public abstract class AbstractWsSecurityInterceptor implements SoapEndpointInter this.logger.debug("No exception resolver present, creating basic soap fault"); } SoapBody response = ((SoapMessage) messageContext.getResponse()).getSoapBody(); - response.addClientOrSenderFault(ex.getMessage(), Locale.ENGLISH); + response.addClientOrSenderFault(Objects.requireNonNull(ex.getMessage()), Locale.ENGLISH); } return false; } diff --git a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/WsSecurityException.java b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/WsSecurityException.java index 891c7d36..e43828f9 100644 --- a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/WsSecurityException.java +++ b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/WsSecurityException.java @@ -16,6 +16,8 @@ package org.springframework.ws.soap.security; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.WebServiceException; /** @@ -32,7 +34,7 @@ public abstract class WsSecurityException extends WebServiceException { super(msg); } - public WsSecurityException(String msg, Throwable ex) { + public WsSecurityException(@Nullable String msg, Throwable ex) { super(msg, ex); } diff --git a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/WsSecuritySecurementException.java b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/WsSecuritySecurementException.java index c799f953..d9d77f5b 100644 --- a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/WsSecuritySecurementException.java +++ b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/WsSecuritySecurementException.java @@ -16,6 +16,8 @@ package org.springframework.ws.soap.security; +import org.jspecify.annotations.Nullable; + /** * Exception indicating that something went wrong during the securement of a message. *

@@ -33,7 +35,7 @@ public abstract class WsSecuritySecurementException extends WsSecurityException super(msg); } - public WsSecuritySecurementException(String msg, Throwable ex) { + public WsSecuritySecurementException(@Nullable String msg, Throwable ex) { super(msg, ex); } diff --git a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/WsSecurityValidationException.java b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/WsSecurityValidationException.java index 13d03456..3ea7332f 100644 --- a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/WsSecurityValidationException.java +++ b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/WsSecurityValidationException.java @@ -16,6 +16,8 @@ package org.springframework.ws.soap.security; +import org.jspecify.annotations.Nullable; + /** * Exception indicating that something went wrong during the validation of a message. *

@@ -33,7 +35,7 @@ public abstract class WsSecurityValidationException extends WsSecurityException super(msg); } - public WsSecurityValidationException(String msg, Throwable ex) { + public WsSecurityValidationException(@Nullable String msg, Throwable ex) { super(msg, ex); } diff --git a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/callback/package-info.java b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/callback/package-info.java index c5e8d259..8f5908a0 100644 --- a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/callback/package-info.java +++ b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/callback/package-info.java @@ -17,4 +17,7 @@ /** * Contains generic {@code CallbackHandler} implementations. */ +@NullMarked package org.springframework.ws.soap.security.callback; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/package-info.java b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/package-info.java index 2d06a371..9ad0b3e9 100644 --- a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/package-info.java +++ b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/package-info.java @@ -18,4 +18,7 @@ * Provides WS-Security implementation classes. Contains the * {@code AbstractWsSecurityInterceptor} and exceptions. */ +@NullMarked package org.springframework.ws.soap.security; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/support/KeyManagersFactoryBean.java b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/support/KeyManagersFactoryBean.java index a19b3cef..14876a94 100644 --- a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/support/KeyManagersFactoryBean.java +++ b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/support/KeyManagersFactoryBean.java @@ -21,6 +21,8 @@ import java.security.KeyStore; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.util.StringUtils; @@ -38,21 +40,21 @@ import org.springframework.util.StringUtils; */ public class KeyManagersFactoryBean implements FactoryBean, InitializingBean { - private KeyManager[] keyManagers; + private KeyManager @Nullable [] keyManagers; - private KeyStore keyStore; + private @Nullable KeyStore keyStore; - private String algorithm; + private @Nullable String algorithm; - private String provider; + private @Nullable String provider; - private char[] password; + private char @Nullable [] password; /** * Sets the password to use for integrity checking. If this property is not set, then * integrity checking is not performed. */ - public void setPassword(String password) { + public void setPassword(@Nullable String password) { if (password != null) { this.password = password.toCharArray(); } @@ -84,7 +86,7 @@ public class KeyManagersFactoryBean implements FactoryBean, Initia } @Override - public KeyManager[] getObject() throws Exception { + public KeyManager @Nullable [] getObject() throws Exception { return this.keyManagers; } diff --git a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/support/KeyStoreFactoryBean.java b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/support/KeyStoreFactoryBean.java index b1697543..214acbae 100644 --- a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/support/KeyStoreFactoryBean.java +++ b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/support/KeyStoreFactoryBean.java @@ -23,10 +23,12 @@ import java.security.KeyStore; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.core.io.Resource; +import org.springframework.util.Assert; import org.springframework.util.StringUtils; /** @@ -45,22 +47,22 @@ public class KeyStoreFactoryBean implements FactoryBean, InitializingB private static final Log logger = LogFactory.getLog(KeyStoreFactoryBean.class); - private KeyStore keyStore; + private @Nullable KeyStore keyStore; - private String type; + private @Nullable String type; - private String provider; + private @Nullable String provider; - private Resource location; + private @Nullable Resource location; - private char[] password; + private char @Nullable [] password; /** * Sets the location of the key store to use. If this is not set, a new, empty key * store will be used. * @see KeyStore#load(java.io.InputStream,char[]) */ - public void setLocation(Resource location) { + public void setLocation(@Nullable Resource location) { this.location = location; } @@ -68,7 +70,7 @@ public class KeyStoreFactoryBean implements FactoryBean, InitializingB * Sets the password to use for integrity checking. If this property is not set, then * integrity checking is not performed. */ - public void setPassword(String password) { + public void setPassword(@Nullable String password) { if (password != null) { this.password = password.toCharArray(); } @@ -86,12 +88,13 @@ public class KeyStoreFactoryBean implements FactoryBean, InitializingB * used. * @see KeyStore#getDefaultType() */ - public void setType(String type) { + public void setType(@Nullable String type) { this.type = type; } @Override public KeyStore getObject() { + Assert.state(this.keyStore != null, "KeyStore has not been initialized"); return this.keyStore; } diff --git a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/support/TrustManagersFactoryBean.java b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/support/TrustManagersFactoryBean.java index 354fd3fa..4370a5f8 100644 --- a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/support/TrustManagersFactoryBean.java +++ b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/support/TrustManagersFactoryBean.java @@ -21,6 +21,8 @@ import java.security.KeyStore; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.util.StringUtils; @@ -37,13 +39,13 @@ import org.springframework.util.StringUtils; */ public class TrustManagersFactoryBean implements FactoryBean, InitializingBean { - private TrustManager[] trustManagers; + private TrustManager @Nullable [] trustManagers; - private KeyStore keyStore; + private @Nullable KeyStore keyStore; - private String algorithm; + private @Nullable String algorithm; - private String provider; + private @Nullable String provider; /** * Sets the provider of the trust manager to use. If this is not set, the default is @@ -71,7 +73,7 @@ public class TrustManagersFactoryBean implements FactoryBean, In } @Override - public TrustManager[] getObject() throws Exception { + public TrustManager @Nullable [] getObject() throws Exception { return this.trustManagers; } diff --git a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/support/package-info.java b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/support/package-info.java index 9281d12d..d7b3f27b 100644 --- a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/support/package-info.java +++ b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/support/package-info.java @@ -17,4 +17,7 @@ /** * Contains support classes for handling WS-Security messages. */ +@NullMarked package org.springframework.ws.soap.security.support; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/Wss4jHandler.java b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/Wss4jHandler.java index 8ec9b85f..9e0324c5 100644 --- a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/Wss4jHandler.java +++ b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/Wss4jHandler.java @@ -26,6 +26,7 @@ import org.apache.wss4j.dom.engine.WSSecurityEngineResult; import org.apache.wss4j.dom.handler.HandlerAction; import org.apache.wss4j.dom.handler.RequestData; import org.apache.wss4j.dom.handler.WSHandler; +import org.jspecify.annotations.Nullable; import org.w3c.dom.Document; import org.springframework.util.StringUtils; @@ -45,11 +46,11 @@ class Wss4jHandler extends WSHandler { /** Keys are constants from {@link ConfigurationConstants}; values are strings. */ private final Properties options = new Properties(); - private String securementPassword; + private @Nullable String securementPassword; - private Crypto securementEncryptionCrypto; + private @Nullable Crypto securementEncryptionCrypto; - private Crypto securementSignatureCrypto; + private @Nullable Crypto securementSignatureCrypto; Wss4jHandler() { // set up default handler properties @@ -94,7 +95,7 @@ class Wss4jHandler extends WSHandler { } @Override - public String getPassword(Object msgContext) { + public @Nullable String getPassword(Object msgContext) { String contextPassword = (String) getProperty(msgContext, Wss4jSecurityInterceptor.SECUREMENT_PASSWORD_PROPERTY_NAME); if (StringUtils.hasLength(contextPassword)) { @@ -104,17 +105,17 @@ class Wss4jHandler extends WSHandler { } @Override - public Object getProperty(Object msgContext, String key) { + public @Nullable Object getProperty(Object msgContext, String key) { return ((MessageContext) msgContext).getProperty(key); } @Override - protected Crypto loadEncryptionCrypto(RequestData reqData) throws WSSecurityException { + protected @Nullable Crypto loadEncryptionCrypto(RequestData reqData) throws WSSecurityException { return this.securementEncryptionCrypto; } @Override - public Crypto loadSignatureCrypto(RequestData reqData) throws WSSecurityException { + public @Nullable Crypto loadSignatureCrypto(RequestData reqData) throws WSSecurityException { return this.securementSignatureCrypto; } diff --git a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/Wss4jSecurityInterceptor.java b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/Wss4jSecurityInterceptor.java index 11f59338..a0392a0a 100644 --- a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/Wss4jSecurityInterceptor.java +++ b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/Wss4jSecurityInterceptor.java @@ -22,6 +22,7 @@ import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.regex.Pattern; import javax.security.auth.callback.Callback; @@ -46,6 +47,7 @@ import org.apache.wss4j.dom.validate.Credential; import org.apache.wss4j.dom.validate.SignatureTrustValidator; import org.apache.wss4j.dom.validate.TimestampValidator; import org.apache.wss4j.dom.validate.Validator; +import org.jspecify.annotations.Nullable; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -54,6 +56,7 @@ import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import org.springframework.ws.context.MessageContext; +import org.springframework.ws.soap.SoapHeader; import org.springframework.ws.soap.SoapMessage; import org.springframework.ws.soap.security.AbstractWsSecurityInterceptor; import org.springframework.ws.soap.security.WsSecuritySecurementException; @@ -160,21 +163,21 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl */ public static final String SECUREMENT_PASSWORD_PROPERTY_NAME = "Wss4jSecurityInterceptor.securementPassword"; - private String securementActions; + private @Nullable String securementActions; - private String securementUsername; + private @Nullable String securementUsername; - private CallbackHandler validationCallbackHandler; + private @Nullable CallbackHandler validationCallbackHandler; - private String validationActions; + private @Nullable String validationActions; - private List validationActionsVector; + private List validationActionsVector = Collections.emptyList(); - private String validationActor; + private @Nullable String validationActor; - private Crypto validationDecryptionCrypto; + private @Nullable Crypto validationDecryptionCrypto; - private Crypto validationSignatureCrypto; + private @Nullable Crypto validationSignatureCrypto; private boolean timestampStrict = true; @@ -186,7 +189,7 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl private int futureTimeToLive = 60; - private WSSConfig wssConfig; + private @Nullable WSSConfig wssConfig; private final Wss4jHandler handler = new Wss4jHandler(); @@ -200,9 +203,9 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl private boolean securementUseDerivedKey; - private CallbackHandler samlCallbackHandler; + private @Nullable CallbackHandler samlCallbackHandler; - private CallbackHandler attachmentCallbackHandler; + private @Nullable CallbackHandler attachmentCallbackHandler; // Allow RSA 15 to maintain default behavior private boolean allowRSA15KeyTransportAlgorithm = true; @@ -871,7 +874,10 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl soapMessage.setDocument(envelopeAsDocument); if (this.getRemoveSecurityHeader()) { - soapMessage.getEnvelope().getHeader().removeHeaderElement(WS_SECURITY_NAME); + SoapHeader header = soapMessage.getEnvelope().getHeader(); + if (header != null) { + header.removeHeaderElement(WS_SECURITY_NAME); + } } } @@ -973,7 +979,7 @@ public class Wss4jSecurityInterceptor extends AbstractWsSecurityInterceptor impl if (principal instanceof WSUsernameTokenPrincipalImpl usernameTokenPrincipal) { UsernameTokenPrincipalCallback callback = new UsernameTokenPrincipalCallback(usernameTokenPrincipal); try { - this.validationCallbackHandler.handle(new Callback[] { callback }); + Objects.requireNonNull(this.validationCallbackHandler).handle(new Callback[] { callback }); } catch (IOException ex) { this.logger.warn("Principal callback resulted in IOException", ex); diff --git a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/Wss4jSecuritySecurementException.java b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/Wss4jSecuritySecurementException.java index 60a09521..e2a41637 100644 --- a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/Wss4jSecuritySecurementException.java +++ b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/Wss4jSecuritySecurementException.java @@ -16,6 +16,8 @@ package org.springframework.ws.soap.security.wss4j2; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.soap.security.WsSecuritySecurementException; /** @@ -33,7 +35,7 @@ public class Wss4jSecuritySecurementException extends WsSecuritySecurementExcept super(msg); } - public Wss4jSecuritySecurementException(String msg, Throwable ex) { + public Wss4jSecuritySecurementException(@Nullable String msg, Throwable ex) { super(msg, ex); } diff --git a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/Wss4jSecurityValidationException.java b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/Wss4jSecurityValidationException.java index d164f9d8..29c12f6a 100644 --- a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/Wss4jSecurityValidationException.java +++ b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/Wss4jSecurityValidationException.java @@ -16,6 +16,8 @@ package org.springframework.ws.soap.security.wss4j2; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.soap.security.WsSecurityValidationException; /** @@ -33,7 +35,7 @@ public class Wss4jSecurityValidationException extends WsSecurityValidationExcept super(msg); } - public Wss4jSecurityValidationException(String msg, Throwable ex) { + public Wss4jSecurityValidationException(@Nullable String msg, Throwable ex) { super(msg, ex); } diff --git a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/callback/KeyStoreCallbackHandler.java b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/callback/KeyStoreCallbackHandler.java index 6fd23e93..af35954a 100644 --- a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/callback/KeyStoreCallbackHandler.java +++ b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/callback/KeyStoreCallbackHandler.java @@ -22,10 +22,12 @@ import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; +import java.util.Objects; import javax.security.auth.callback.UnsupportedCallbackException; import org.apache.wss4j.common.ext.WSPasswordCallback; +import org.jspecify.annotations.Nullable; import org.springframework.beans.factory.InitializingBean; import org.springframework.ws.soap.security.support.KeyStoreUtils; @@ -43,10 +45,11 @@ import org.springframework.ws.soap.security.support.KeyStoreUtils; */ public class KeyStoreCallbackHandler extends AbstractWsPasswordCallbackHandler implements InitializingBean { - private String privateKeyPassword; + private @Nullable String privateKeyPassword; - private char[] symmetricKeyPassword; + private char @Nullable [] symmetricKeyPassword; + @SuppressWarnings("NullAway.Init") private KeyStore keyStore; /** @@ -75,7 +78,7 @@ public class KeyStoreCallbackHandler extends AbstractWsPasswordCallbackHandler i try { key = this.keyStore.getKey(id, (this.symmetricKeyPassword != null) ? this.symmetricKeyPassword - : this.privateKeyPassword.toCharArray()); + : Objects.requireNonNull(this.privateKeyPassword).toCharArray()); } catch (UnrecoverableKeyException | KeyStoreException | NoSuchAlgorithmException ex) { throw new IOException("Could not get key", ex); @@ -93,7 +96,7 @@ public class KeyStoreCallbackHandler extends AbstractWsPasswordCallbackHandler i * Sets the password used to retrieve private keys from the keystore. This property is * required for decryption based on private keys, and signing. */ - public void setPrivateKeyPassword(String privateKeyPassword) { + public void setPrivateKeyPassword(@Nullable String privateKeyPassword) { if (privateKeyPassword != null) { this.privateKeyPassword = privateKeyPassword; } @@ -104,7 +107,7 @@ public class KeyStoreCallbackHandler extends AbstractWsPasswordCallbackHandler i * property is not set, it defaults to the private key password. * @see #setPrivateKeyPassword(String) */ - public void setSymmetricKeyPassword(String symmetricKeyPassword) { + public void setSymmetricKeyPassword(@Nullable String symmetricKeyPassword) { if (symmetricKeyPassword != null) { this.symmetricKeyPassword = symmetricKeyPassword.toCharArray(); } @@ -116,7 +119,7 @@ public class KeyStoreCallbackHandler extends AbstractWsPasswordCallbackHandler i loadDefaultKeyStore(); } if (this.symmetricKeyPassword == null) { - this.symmetricKeyPassword = this.privateKeyPassword.toCharArray(); + this.symmetricKeyPassword = Objects.requireNonNull(this.privateKeyPassword).toCharArray(); } } diff --git a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/callback/SpringSecurityPasswordValidationCallbackHandler.java b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/callback/SpringSecurityPasswordValidationCallbackHandler.java index 0e4f8c72..3851814a 100644 --- a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/callback/SpringSecurityPasswordValidationCallbackHandler.java +++ b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/callback/SpringSecurityPasswordValidationCallbackHandler.java @@ -17,11 +17,13 @@ package org.springframework.ws.soap.security.wss4j2.callback; import java.io.IOException; +import java.util.Objects; import javax.security.auth.callback.UnsupportedCallbackException; import org.apache.wss4j.common.ext.WSPasswordCallback; import org.apache.wss4j.common.principal.WSUsernameTokenPrincipalImpl; +import org.jspecify.annotations.Nullable; import org.springframework.beans.factory.InitializingBean; import org.springframework.dao.DataAccessException; @@ -53,7 +55,7 @@ public class SpringSecurityPasswordValidationCallbackHandler extends AbstractWsP private UserCache userCache = new NullUserCache(); - private UserDetailsService userDetailsService; + private @Nullable UserDetailsService userDetailsService; /** Sets the users cache. Not required, but can benefit performance. */ public void setUserCache(UserCache userCache) { @@ -92,7 +94,7 @@ public class SpringSecurityPasswordValidationCallbackHandler extends AbstractWsP UserDetails user = loadUserDetails(callback.getPrincipal().getName()); WSUsernameTokenPrincipalImpl principal = callback.getPrincipal(); UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(principal, - principal.getPassword(), user.getAuthorities()); + principal.getPassword(), (user != null) ? user.getAuthorities() : null); if (this.logger.isDebugEnabled()) { this.logger.debug("Authentication success: " + authRequest); } @@ -105,12 +107,12 @@ public class SpringSecurityPasswordValidationCallbackHandler extends AbstractWsP SecurityContextHolder.clearContext(); } - private UserDetails loadUserDetails(String username) throws DataAccessException { + private @Nullable UserDetails loadUserDetails(String username) throws DataAccessException { UserDetails user = this.userCache.getUserFromCache(username); if (user == null) { try { - user = this.userDetailsService.loadUserByUsername(username); + user = Objects.requireNonNull(this.userDetailsService).loadUserByUsername(username); } catch (UsernameNotFoundException notFound) { if (this.logger.isDebugEnabled()) { diff --git a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/callback/package-info.java b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/callback/package-info.java index 36f8d35a..4c1cd15a 100644 --- a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/callback/package-info.java +++ b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/callback/package-info.java @@ -17,4 +17,7 @@ /** * Contains {@code CallbackHandler} implementations for WSS4J 2.0+. */ +@NullMarked package org.springframework.ws.soap.security.wss4j2.callback; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/package-info.java b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/package-info.java index e3313c8f..2ace1d4e 100644 --- a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/package-info.java +++ b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/package-info.java @@ -18,4 +18,7 @@ * Contains classes for using the Apache WSS4J * 2.0+ WS-Security implementation within Spring-WS. */ +@NullMarked package org.springframework.ws.soap.security.wss4j2; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/support/CryptoFactoryBean.java b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/support/CryptoFactoryBean.java index d50782bc..ee353aa6 100644 --- a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/support/CryptoFactoryBean.java +++ b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/support/CryptoFactoryBean.java @@ -22,6 +22,7 @@ import java.util.Properties; import org.apache.wss4j.common.crypto.Crypto; import org.apache.wss4j.common.crypto.CryptoFactory; import org.apache.wss4j.common.crypto.Merlin; +import org.jspecify.annotations.Nullable; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; @@ -46,7 +47,7 @@ public class CryptoFactoryBean implements FactoryBean, InitializingBean private final Properties configuration = new Properties(); - private Crypto crypto; + private @Nullable Crypto crypto; private static final String CRYPTO_PROVIDER_PROPERTY = "org.apache.wss4j.crypto.provider"; @@ -179,7 +180,7 @@ public class CryptoFactoryBean implements FactoryBean, InitializingBean } @Override - public Crypto getObject() throws Exception { + public @Nullable Crypto getObject() throws Exception { return this.crypto; } diff --git a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/support/package-info.java b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/support/package-info.java index b65aaa60..53704286 100644 --- a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/support/package-info.java +++ b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/wss4j2/support/package-info.java @@ -17,4 +17,7 @@ /** * Contains support classes for working with WSS4J 2.0+. */ +@NullMarked package org.springframework.ws.soap.security.wss4j2.support; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/X509AuthenticationProvider.java b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/X509AuthenticationProvider.java index a4058909..9c885356 100644 --- a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/X509AuthenticationProvider.java +++ b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/X509AuthenticationProvider.java @@ -20,6 +20,7 @@ import java.security.cert.X509Certificate; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.beans.factory.InitializingBean; import org.springframework.context.MessageSource; @@ -56,6 +57,7 @@ public class X509AuthenticationProvider implements AuthenticationProvider, Initi protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor(); + @SuppressWarnings("NullAway.Init") private X509AuthoritiesPopulator x509AuthoritiesPopulator; private X509UserCache userCache = new NullX509UserCache(); @@ -88,7 +90,7 @@ public class X509AuthenticationProvider implements AuthenticationProvider, Initi * authentication request. */ @Override - public Authentication authenticate(Authentication authentication) throws AuthenticationException { + public @Nullable Authentication authenticate(Authentication authentication) throws AuthenticationException { if (!supports(authentication.getClass())) { return null; } diff --git a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/X509AuthenticationToken.java b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/X509AuthenticationToken.java index 0661114e..97f7e500 100644 --- a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/X509AuthenticationToken.java +++ b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/X509AuthenticationToken.java @@ -20,6 +20,8 @@ import java.io.Serial; import java.security.cert.X509Certificate; import java.util.Collection; +import org.jspecify.annotations.Nullable; + import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.core.GrantedAuthority; @@ -39,7 +41,7 @@ public class X509AuthenticationToken extends AbstractAuthenticationToken { @Serial private static final long serialVersionUID = 1L; - private Object principal; + private @Nullable Object principal; private final X509Certificate credentials; @@ -82,7 +84,7 @@ public class X509AuthenticationToken extends AbstractAuthenticationToken { } @Override - public Object getPrincipal() { + public @Nullable Object getPrincipal() { return this.principal; } diff --git a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/cache/NullX509UserCache.java b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/cache/NullX509UserCache.java index 15c47b97..05cc0374 100644 --- a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/cache/NullX509UserCache.java +++ b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/cache/NullX509UserCache.java @@ -18,6 +18,8 @@ package org.springframework.ws.soap.security.x509.cache; import java.security.cert.X509Certificate; +import org.jspecify.annotations.Nullable; + import org.springframework.security.core.userdetails.UserDetails; /** @@ -34,7 +36,7 @@ public class NullX509UserCache implements X509UserCache { // ======================================================================================================== @Override - public UserDetails getUserFromCache(X509Certificate certificate) { + public @Nullable UserDetails getUserFromCache(X509Certificate certificate) { return null; } diff --git a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/cache/SpringBasedX509UserCache.java b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/cache/SpringBasedX509UserCache.java index 78ee5040..4a6a7a59 100644 --- a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/cache/SpringBasedX509UserCache.java +++ b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/cache/SpringBasedX509UserCache.java @@ -20,6 +20,7 @@ import java.security.cert.X509Certificate; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.beans.factory.InitializingBean; import org.springframework.cache.Cache; @@ -40,6 +41,7 @@ public class SpringBasedX509UserCache implements X509UserCache, InitializingBean private static final Log logger = LogFactory.getLog(SpringBasedX509UserCache.class); + @SuppressWarnings("NullAway.Init") private Cache cache; @Override @@ -48,13 +50,13 @@ public class SpringBasedX509UserCache implements X509UserCache, InitializingBean } @Override - public UserDetails getUserFromCache(X509Certificate userCert) { + public @Nullable UserDetails getUserFromCache(X509Certificate userCert) { if (logger.isDebugEnabled()) { String subjectDN = "unknown"; - if ((userCert != null) && (userCert.getSubjectX500Principal() != null)) { + if (userCert.getSubjectX500Principal() != null) { subjectDN = userCert.getSubjectX500Principal().toString(); } diff --git a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/cache/X509UserCache.java b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/cache/X509UserCache.java index f42fdb3f..ee41a248 100644 --- a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/cache/X509UserCache.java +++ b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/cache/X509UserCache.java @@ -18,6 +18,8 @@ package org.springframework.ws.soap.security.x509.cache; import java.security.cert.X509Certificate; +import org.jspecify.annotations.Nullable; + import org.springframework.security.core.userdetails.UserDetails; /** @@ -39,7 +41,7 @@ public interface X509UserCache { // ~ Methods // ======================================================================================================== - UserDetails getUserFromCache(X509Certificate userCertificate); + @Nullable UserDetails getUserFromCache(X509Certificate userCertificate); void putUserInCache(X509Certificate key, UserDetails user); diff --git a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/cache/package-info.java b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/cache/package-info.java index f7743d9a..00d23fe2 100644 --- a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/cache/package-info.java +++ b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/cache/package-info.java @@ -17,4 +17,7 @@ /** * Caching support for X.509 client certificates. */ +@NullMarked package org.springframework.ws.soap.security.x509.cache; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/package-info.java b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/package-info.java index c47e760f..8ceaf9d4 100644 --- a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/package-info.java +++ b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/package-info.java @@ -17,4 +17,7 @@ /** * X.509 client-certificate authentication support. */ +@NullMarked package org.springframework.ws.soap.security.x509; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/populator/DaoX509AuthoritiesPopulator.java b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/populator/DaoX509AuthoritiesPopulator.java index 29fbddc2..62ce45e6 100644 --- a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/populator/DaoX509AuthoritiesPopulator.java +++ b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/populator/DaoX509AuthoritiesPopulator.java @@ -50,10 +50,12 @@ public class DaoX509AuthoritiesPopulator implements X509AuthoritiesPopulator, In protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor(); + @SuppressWarnings("NullAway.Init") private Pattern subjectDNPattern; private String subjectDNRegex = "CN=(.*?),"; + @SuppressWarnings("NullAway.Init") private UserDetailsService userDetailsService; // ~ Methods diff --git a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/populator/package-info.java b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/populator/package-info.java index 1a7d85d3..367685f1 100644 --- a/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/populator/package-info.java +++ b/spring-ws-security/src/main/java/org/springframework/ws/soap/security/x509/populator/package-info.java @@ -17,4 +17,7 @@ /** * User details popular for X.509 client certificates. */ +@NullMarked package org.springframework.ws.soap.security.x509.populator; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-support/src/main/java/org/springframework/ws/transport/jms/JmsMessageReceiver.java b/spring-ws-support/src/main/java/org/springframework/ws/transport/jms/JmsMessageReceiver.java index f6d7ec60..9e37e17e 100644 --- a/spring-ws-support/src/main/java/org/springframework/ws/transport/jms/JmsMessageReceiver.java +++ b/spring-ws-support/src/main/java/org/springframework/ws/transport/jms/JmsMessageReceiver.java @@ -20,6 +20,7 @@ import jakarta.jms.BytesMessage; import jakarta.jms.Message; import jakarta.jms.Session; import jakarta.jms.TextMessage; +import org.jspecify.annotations.Nullable; import org.springframework.jms.core.MessagePostProcessor; import org.springframework.ws.transport.WebServiceMessageReceiver; @@ -44,7 +45,7 @@ public class JmsMessageReceiver extends SimpleWebServiceMessageReceiverObjectSup private String textMessageEncoding = DEFAULT_TEXT_MESSAGE_ENCODING; - private MessagePostProcessor postProcessor; + private @Nullable MessagePostProcessor postProcessor; /** * Sets the encoding used to read from and write to {@link TextMessage} messages. diff --git a/spring-ws-support/src/main/java/org/springframework/ws/transport/jms/JmsMessageSender.java b/spring-ws-support/src/main/java/org/springframework/ws/transport/jms/JmsMessageSender.java index 06e16c9b..61a1686e 100644 --- a/spring-ws-support/src/main/java/org/springframework/ws/transport/jms/JmsMessageSender.java +++ b/spring-ws-support/src/main/java/org/springframework/ws/transport/jms/JmsMessageSender.java @@ -27,11 +27,13 @@ import jakarta.jms.Message; import jakarta.jms.Queue; import jakarta.jms.Session; import jakarta.jms.Topic; +import org.jspecify.annotations.Nullable; import org.springframework.jms.connection.ConnectionFactoryUtils; import org.springframework.jms.core.MessagePostProcessor; import org.springframework.jms.support.JmsUtils; import org.springframework.jms.support.destination.JmsDestinationAccessor; +import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.ws.transport.WebServiceConnection; import org.springframework.ws.transport.WebServiceMessageSender; @@ -117,7 +119,7 @@ public class JmsMessageSender extends JmsDestinationAccessor implements WebServi private String textMessageEncoding = DEFAULT_TEXT_MESSAGE_ENCODING; - private MessagePostProcessor postProcessor; + private @Nullable MessagePostProcessor postProcessor; /** * Create a new {@code JmsMessageSender} @@ -165,6 +167,8 @@ public class JmsMessageSender extends JmsDestinationAccessor implements WebServi @Override public WebServiceConnection createConnection(URI uri) throws IOException { + ConnectionFactory connectionFactory = getConnectionFactory(); + Assert.notNull(connectionFactory, "ConnectionFactory is required"); Connection jmsConnection = null; Session jmsSession = null; try { @@ -172,8 +176,8 @@ public class JmsMessageSender extends JmsDestinationAccessor implements WebServi jmsSession = createSession(jmsConnection); Destination requestDestination = resolveRequestDestination(jmsSession, uri); Message requestMessage = createRequestMessage(jmsSession, uri); - JmsSenderConnection wsConnection = new JmsSenderConnection(getConnectionFactory(), jmsConnection, - jmsSession, requestDestination, requestMessage); + JmsSenderConnection wsConnection = new JmsSenderConnection(connectionFactory, jmsConnection, jmsSession, + requestDestination, requestMessage); wsConnection.setDeliveryMode(JmsTransportUtils.getDeliveryMode(uri)); wsConnection.setPriority(JmsTransportUtils.getPriority(uri)); wsConnection.setReceiveTimeout(this.receiveTimeout); @@ -197,10 +201,12 @@ public class JmsMessageSender extends JmsDestinationAccessor implements WebServi } private Destination resolveRequestDestination(Session session, URI uri) throws JMSException { - return resolveDestinationName(session, JmsTransportUtils.getDestinationName(uri)); + String destinationName = JmsTransportUtils.getDestinationName(uri); + Assert.notNull(destinationName, "No destination name found for URI [" + uri + "]"); + return resolveDestinationName(session, destinationName); } - private Destination resolveResponseDestination(Session session, URI uri) throws JMSException { + private @Nullable Destination resolveResponseDestination(Session session, URI uri) throws JMSException { String destinationName = JmsTransportUtils.getReplyToName(uri); return StringUtils.hasLength(destinationName) ? resolveDestinationName(session, destinationName) : null; } diff --git a/spring-ws-support/src/main/java/org/springframework/ws/transport/jms/JmsReceiverConnection.java b/spring-ws-support/src/main/java/org/springframework/ws/transport/jms/JmsReceiverConnection.java index 65ed4c57..a3443ded 100644 --- a/spring-ws-support/src/main/java/org/springframework/ws/transport/jms/JmsReceiverConnection.java +++ b/spring-ws-support/src/main/java/org/springframework/ws/transport/jms/JmsReceiverConnection.java @@ -29,6 +29,7 @@ import jakarta.jms.Message; import jakarta.jms.MessageProducer; import jakarta.jms.Session; import jakarta.jms.TextMessage; +import org.jspecify.annotations.Nullable; import org.springframework.jms.core.MessagePostProcessor; import org.springframework.jms.support.JmsUtils; @@ -57,11 +58,11 @@ public class JmsReceiverConnection extends AbstractReceiverConnection { private final Session session; - private Message responseMessage; + private @Nullable Message responseMessage; - private String textMessageEncoding; + private @Nullable String textMessageEncoding; - private MessagePostProcessor postProcessor; + private @Nullable MessagePostProcessor postProcessor; private JmsReceiverConnection(Message requestMessage, Session session) { Assert.notNull(requestMessage, "requestMessage must not be null"); @@ -89,7 +90,7 @@ public class JmsReceiverConnection extends AbstractReceiverConnection { this.textMessageEncoding = encoding; } - void setPostProcessor(MessagePostProcessor postProcessor) { + void setPostProcessor(@Nullable MessagePostProcessor postProcessor) { this.postProcessor = postProcessor; } @@ -105,7 +106,7 @@ public class JmsReceiverConnection extends AbstractReceiverConnection { * Returns the response message, if any, for this connection. Returns either a * {@link BytesMessage} or a {@link TextMessage}. */ - public Message getResponseMessage() { + public @Nullable Message getResponseMessage() { return this.responseMessage; } @@ -114,7 +115,7 @@ public class JmsReceiverConnection extends AbstractReceiverConnection { */ @Override - public URI getUri() throws URISyntaxException { + public @Nullable URI getUri() throws URISyntaxException { try { return JmsTransportUtils.toUri(this.requestMessage.getJMSDestination()); } @@ -128,7 +129,7 @@ public class JmsReceiverConnection extends AbstractReceiverConnection { */ @Override - public String getErrorMessage() throws IOException { + public @Nullable String getErrorMessage() throws IOException { return null; } @@ -167,6 +168,7 @@ public class JmsReceiverConnection extends AbstractReceiverConnection { return new BytesMessageInputStream((BytesMessage) this.requestMessage); } else if (this.requestMessage instanceof TextMessage) { + Assert.notNull(this.textMessageEncoding, "MessageEncoding for TextMessage is required"); return new TextMessageInputStream((TextMessage) this.requestMessage, this.textMessageEncoding); } else { @@ -181,15 +183,7 @@ public class JmsReceiverConnection extends AbstractReceiverConnection { @Override protected void onSendBeforeWrite(WebServiceMessage message) throws IOException { try { - if (this.requestMessage instanceof BytesMessage) { - this.responseMessage = this.session.createBytesMessage(); - } - else if (this.requestMessage instanceof TextMessage) { - this.responseMessage = this.session.createTextMessage(); - } - else { - throw new IllegalStateException("Unknown request message type [" + this.requestMessage + "]"); - } + this.responseMessage = createResponseMessage(); String correlation = this.requestMessage.getJMSCorrelationID(); if (correlation == null) { correlation = this.requestMessage.getJMSMessageID(); @@ -201,8 +195,21 @@ public class JmsReceiverConnection extends AbstractReceiverConnection { } } + private Message createResponseMessage() throws JMSException { + if (this.requestMessage instanceof BytesMessage) { + return this.session.createBytesMessage(); + } + else if (this.requestMessage instanceof TextMessage) { + return this.session.createTextMessage(); + } + else { + throw new IllegalStateException("Unknown request message type [" + this.requestMessage + "]"); + } + } + @Override public void addResponseHeader(String name, String value) throws IOException { + Assert.state(this.responseMessage != null, "Response message is not available"); try { JmsTransportUtils.addHeader(this.responseMessage, name, value); } @@ -217,6 +224,7 @@ public class JmsReceiverConnection extends AbstractReceiverConnection { return new BytesMessageOutputStream((BytesMessage) this.responseMessage); } else if (this.responseMessage instanceof TextMessage) { + Assert.notNull(this.textMessageEncoding, "MessageEncoding for TextMessage is required"); return new TextMessageOutputStream((TextMessage) this.responseMessage, this.textMessageEncoding); } else { @@ -226,6 +234,7 @@ public class JmsReceiverConnection extends AbstractReceiverConnection { @Override protected void onSendAfterWrite(WebServiceMessage message) throws IOException { + Assert.state(this.responseMessage != null, "Response message is not available"); MessageProducer messageProducer = null; try { if (this.requestMessage.getJMSReplyTo() != null) { diff --git a/spring-ws-support/src/main/java/org/springframework/ws/transport/jms/JmsSenderConnection.java b/spring-ws-support/src/main/java/org/springframework/ws/transport/jms/JmsSenderConnection.java index 258ab5a2..7470efda 100644 --- a/spring-ws-support/src/main/java/org/springframework/ws/transport/jms/JmsSenderConnection.java +++ b/spring-ws-support/src/main/java/org/springframework/ws/transport/jms/JmsSenderConnection.java @@ -34,6 +34,7 @@ import jakarta.jms.MessageProducer; import jakarta.jms.Session; import jakarta.jms.TemporaryQueue; import jakarta.jms.TextMessage; +import org.jspecify.annotations.Nullable; import org.springframework.jms.connection.ConnectionFactoryUtils; import org.springframework.jms.core.MessagePostProcessor; @@ -64,9 +65,9 @@ public class JmsSenderConnection extends AbstractSenderConnection { private Message requestMessage; - private Destination responseDestination; + private @Nullable Destination responseDestination; - private Message responseMessage; + private @Nullable Message responseMessage; private long receiveTimeout; @@ -76,9 +77,9 @@ public class JmsSenderConnection extends AbstractSenderConnection { private int priority; - private String textMessageEncoding; + private @Nullable String textMessageEncoding; - private MessagePostProcessor postProcessor; + private @Nullable MessagePostProcessor postProcessor; private boolean sessionTransacted = false; @@ -111,7 +112,7 @@ public class JmsSenderConnection extends AbstractSenderConnection { * Returns the response message, if any, for this connection. Returns either a * {@link BytesMessage} or a {@link TextMessage}. */ - public Message getResponseMessage() { + public @Nullable Message getResponseMessage() { return this.responseMessage; } @@ -119,7 +120,7 @@ public class JmsSenderConnection extends AbstractSenderConnection { * Package-friendly setters */ - void setResponseDestination(Destination responseDestination) { + void setResponseDestination(@Nullable Destination responseDestination) { this.responseDestination = responseDestination; } @@ -143,7 +144,7 @@ public class JmsSenderConnection extends AbstractSenderConnection { this.textMessageEncoding = textMessageEncoding; } - void setPostProcessor(MessagePostProcessor postProcessor) { + void setPostProcessor(@Nullable MessagePostProcessor postProcessor) { this.postProcessor = postProcessor; } @@ -156,7 +157,7 @@ public class JmsSenderConnection extends AbstractSenderConnection { */ @Override - public URI getUri() throws URISyntaxException { + public @Nullable URI getUri() throws URISyntaxException { try { return JmsTransportUtils.toUri(this.requestDestination); } @@ -175,7 +176,7 @@ public class JmsSenderConnection extends AbstractSenderConnection { } @Override - public String getErrorMessage() throws IOException { + public @Nullable String getErrorMessage() throws IOException { return null; } @@ -199,6 +200,7 @@ public class JmsSenderConnection extends AbstractSenderConnection { return new BytesMessageOutputStream((BytesMessage) this.requestMessage); } else if (this.requestMessage instanceof TextMessage) { + Assert.notNull(this.textMessageEncoding, "MessageEncoding for TextMessage is required"); return new TextMessageOutputStream((TextMessage) this.requestMessage, this.textMessageEncoding); } else { @@ -277,9 +279,10 @@ public class JmsSenderConnection extends AbstractSenderConnection { } finally { JmsUtils.closeMessageConsumer(messageConsumer); - if (this.temporaryResponseQueueCreated) { + if (this.temporaryResponseQueueCreated + && this.responseDestination instanceof TemporaryQueue temporaryQueue) { try { - ((TemporaryQueue) this.responseDestination).delete(); + temporaryQueue.delete(); } catch (JMSException ex) { // ignore @@ -296,6 +299,7 @@ public class JmsSenderConnection extends AbstractSenderConnection { @Override public Iterator getResponseHeaderNames() throws IOException { try { + Assert.state(this.responseMessage != null, "ResponseMessage is required"); return JmsTransportUtils.getHeaderNames(this.responseMessage); } catch (JMSException ex) { @@ -306,6 +310,7 @@ public class JmsSenderConnection extends AbstractSenderConnection { @Override public Iterator getResponseHeaders(String name) throws IOException { try { + Assert.state(this.responseMessage != null, "ResponseMessage is required"); return JmsTransportUtils.getHeaders(this.responseMessage, name); } catch (JMSException ex) { @@ -319,6 +324,7 @@ public class JmsSenderConnection extends AbstractSenderConnection { return new BytesMessageInputStream((BytesMessage) this.responseMessage); } else if (this.responseMessage instanceof TextMessage) { + Assert.notNull(this.textMessageEncoding, "MessageEncoding for TextMessage is required"); return new TextMessageInputStream((TextMessage) this.responseMessage, this.textMessageEncoding); } else { diff --git a/spring-ws-support/src/main/java/org/springframework/ws/transport/jms/package-info.java b/spring-ws-support/src/main/java/org/springframework/ws/transport/jms/package-info.java index cc815875..c2b6919d 100644 --- a/spring-ws-support/src/main/java/org/springframework/ws/transport/jms/package-info.java +++ b/spring-ws-support/src/main/java/org/springframework/ws/transport/jms/package-info.java @@ -17,4 +17,7 @@ /** * Package providing support for handling messages via JMS. */ +@NullMarked package org.springframework.ws.transport.jms; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-support/src/main/java/org/springframework/ws/transport/jms/support/JmsTransportUtils.java b/spring-ws-support/src/main/java/org/springframework/ws/transport/jms/support/JmsTransportUtils.java index 5470c0fc..cd8f7448 100644 --- a/spring-ws-support/src/main/java/org/springframework/ws/transport/jms/support/JmsTransportUtils.java +++ b/spring-ws-support/src/main/java/org/springframework/ws/transport/jms/support/JmsTransportUtils.java @@ -32,6 +32,7 @@ import jakarta.jms.JMSException; import jakarta.jms.Message; import jakarta.jms.Queue; import jakarta.jms.Topic; +import org.jspecify.annotations.Nullable; import org.springframework.ws.transport.jms.JmsTransportConstants; @@ -100,7 +101,7 @@ public abstract class JmsTransportUtils { * @param destination the destination * @return a jms URI */ - public static URI toUri(Destination destination) throws URISyntaxException, JMSException { + public static @Nullable URI toUri(@Nullable Destination destination) throws URISyntaxException, JMSException { if (destination == null) { return null; } @@ -118,7 +119,7 @@ public abstract class JmsTransportUtils { } /** Returns the destination name of the given URI. */ - public static String getDestinationName(URI uri) { + public static @Nullable String getDestinationName(URI uri) { return getStringParameter(DESTINATION_NAME_PATTERN, uri); } @@ -215,11 +216,11 @@ public abstract class JmsTransportUtils { * Returns the reply-to name of the given URI. * @see Message#setJMSReplyTo(Destination) */ - public static String getReplyToName(URI uri) { + public static @Nullable String getReplyToName(URI uri) { return getStringParameter(REPLY_TO_NAME_PATTERN, uri); } - private static String getStringParameter(Pattern pattern, URI uri) { + private static @Nullable String getStringParameter(Pattern pattern, URI uri) { Matcher matcher = pattern.matcher(uri.getSchemeSpecificPart()); if (matcher.find() && matcher.groupCount() == 1) { return matcher.group(1); diff --git a/spring-ws-support/src/main/java/org/springframework/ws/transport/jms/support/package-info.java b/spring-ws-support/src/main/java/org/springframework/ws/transport/jms/support/package-info.java index c21354fc..e7b5db05 100644 --- a/spring-ws-support/src/main/java/org/springframework/ws/transport/jms/support/package-info.java +++ b/spring-ws-support/src/main/java/org/springframework/ws/transport/jms/support/package-info.java @@ -17,4 +17,7 @@ /** * Classes supporting the org.springframework.ws.transport.jms package. */ +@NullMarked package org.springframework.ws.transport.jms.support; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/MailMessageReceiver.java b/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/MailMessageReceiver.java index df65e92b..6c7b4d4d 100644 --- a/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/MailMessageReceiver.java +++ b/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/MailMessageReceiver.java @@ -16,6 +16,7 @@ package org.springframework.ws.transport.mail; +import java.util.Objects; import java.util.Properties; import jakarta.mail.Folder; @@ -27,6 +28,7 @@ import jakarta.mail.Store; import jakarta.mail.URLName; import jakarta.mail.internet.AddressException; import jakarta.mail.internet.InternetAddress; +import org.jspecify.annotations.Nullable; import org.springframework.scheduling.SchedulingAwareRunnable; import org.springframework.util.Assert; @@ -58,18 +60,21 @@ public class MailMessageReceiver extends AbstractAsyncStandaloneMessageReceiver private Session session = Session.getInstance(new Properties(), null); + @SuppressWarnings("NullAway.Init") private URLName storeUri; + @SuppressWarnings("NullAway.Init") private URLName transportUri; - private Folder folder; - - private Store store; - - private InternetAddress from; - + @SuppressWarnings("NullAway.Init") private MonitoringStrategy monitoringStrategy; + private @Nullable Folder folder; + + private @Nullable Store store; + + private @Nullable InternetAddress from; + /** Sets the from address to use when sending response messages. */ public void setFrom(String from) throws AddressException { this.from = new InternetAddress(from); @@ -201,7 +206,7 @@ public class MailMessageReceiver extends AbstractAsyncStandaloneMessageReceiver if (this.folder != null && this.folder.isOpen()) { return; } - this.folder = this.store.getFolder(this.storeUri); + this.folder = Objects.requireNonNull(this.store).getFolder(this.storeUri); if (this.folder == null || !this.folder.exists()) { throw new IllegalStateException("No default folder to receive from"); } @@ -228,7 +233,7 @@ public class MailMessageReceiver extends AbstractAsyncStandaloneMessageReceiver while (isRunning()) { try { Message[] messages = MailMessageReceiver.this.monitoringStrategy - .monitor(MailMessageReceiver.this.folder); + .monitor(Objects.requireNonNull(MailMessageReceiver.this.folder)); for (Message message : messages) { MessageHandler handler = new MessageHandler(message); execute(handler); @@ -274,7 +279,7 @@ public class MailMessageReceiver extends AbstractAsyncStandaloneMessageReceiver MailReceiverConnection connection = new MailReceiverConnection(this.message, MailMessageReceiver.this.session); connection.setTransportUri(MailMessageReceiver.this.transportUri); - connection.setFrom(MailMessageReceiver.this.from); + connection.setFrom(Objects.requireNonNull(MailMessageReceiver.this.from)); try { handleConnection(connection); } diff --git a/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/MailMessageSender.java b/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/MailMessageSender.java index 4f56c3f8..9a2aaffa 100644 --- a/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/MailMessageSender.java +++ b/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/MailMessageSender.java @@ -25,6 +25,7 @@ import jakarta.mail.URLName; import jakarta.mail.internet.AddressException; import jakarta.mail.internet.InternetAddress; import jakarta.mail.internet.MimeMessage; +import org.jspecify.annotations.Nullable; import org.springframework.beans.factory.InitializingBean; import org.springframework.util.Assert; @@ -83,11 +84,11 @@ public class MailMessageSender implements WebServiceMessageSender, InitializingB private Session session = Session.getInstance(new Properties(), null); - private URLName storeUri; + private @Nullable URLName storeUri; - private URLName transportUri; + private @Nullable URLName transportUri; - private InternetAddress from; + private @Nullable InternetAddress from; /** * Sets the from address to use when sending request messages. @@ -163,7 +164,10 @@ public class MailMessageSender implements WebServiceMessageSender, InitializingB @Override public WebServiceConnection createConnection(URI uri) throws IOException { + Assert.notNull(this.transportUri, "'transportUri' is required"); + Assert.notNull(this.storeUri, "'storeUri' is required"); InternetAddress to = MailTransportUtils.getTo(uri); + Assert.notNull(to, "No TO address found for '" + uri + "'"); MailSenderConnection connection = new MailSenderConnection(this.session, this.transportUri, this.storeUri, to, this.receiveSleepTime); if (this.from != null) { diff --git a/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/MailReceiverConnection.java b/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/MailReceiverConnection.java index aa4187b1..80323fd8 100644 --- a/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/MailReceiverConnection.java +++ b/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/MailReceiverConnection.java @@ -39,6 +39,7 @@ import jakarta.mail.Session; import jakarta.mail.Transport; import jakarta.mail.URLName; import jakarta.mail.internet.InternetAddress; +import org.jspecify.annotations.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -62,15 +63,15 @@ public class MailReceiverConnection extends AbstractReceiverConnection { private final Session session; - private Message responseMessage; + private @Nullable Message responseMessage; - private ByteArrayOutputStream responseBuffer; + private @Nullable ByteArrayOutputStream responseBuffer; - private String responseContentType; + private @Nullable String responseContentType; - private URLName transportUri; + private @Nullable URLName transportUri; - private InternetAddress from; + private @Nullable InternetAddress from; /** Constructs a new Mail connection with the given parameters. */ protected MailReceiverConnection(Message requestMessage, Session session) { @@ -87,6 +88,7 @@ public class MailReceiverConnection extends AbstractReceiverConnection { /** Returns the response message, if any, for this connection. */ public Message getResponseMessage() { + Assert.notNull(this.responseMessage, "ResponseMessage is not available"); return this.responseMessage; } @@ -125,7 +127,7 @@ public class MailReceiverConnection extends AbstractReceiverConnection { */ @Override - public String getErrorMessage() throws IOException { + public @Nullable String getErrorMessage() throws IOException { return null; } @@ -178,7 +180,7 @@ public class MailReceiverConnection extends AbstractReceiverConnection { @Override public void addResponseHeader(String name, String value) throws IOException { try { - this.responseMessage.addHeader(name, value); + getResponseMessage().addHeader(name, value); if (TransportConstants.HEADER_CONTENT_TYPE.equals(name)) { this.responseContentType = value; } @@ -190,6 +192,7 @@ public class MailReceiverConnection extends AbstractReceiverConnection { @Override protected OutputStream getResponseOutputStream() throws IOException { + Assert.state(this.responseBuffer != null, "onSendBeforeWrite has not been called"); return this.responseBuffer; } @@ -213,9 +216,12 @@ public class MailReceiverConnection extends AbstractReceiverConnection { @Override protected void onSendAfterWrite(WebServiceMessage message) throws IOException { Transport transport = null; + Assert.state(this.responseMessage != null, "onSendAfterWrite has not been called"); + Assert.state(this.responseBuffer != null, "onSendAfterWrite has not been called"); + Assert.notNull(this.transportUri, "'transportUri' must not be null"); try { this.responseMessage.setDataHandler(new DataHandler( - new ByteArrayDataSource(this.responseContentType, this.responseBuffer.toByteArray()))); + new ByteArrayDataSource(this.responseBuffer.toByteArray(), this.responseContentType))); transport = this.session.getTransport(this.transportUri); transport.connect(); this.responseMessage.saveChanges(); @@ -235,9 +241,9 @@ public class MailReceiverConnection extends AbstractReceiverConnection { private final byte[] data; - ByteArrayDataSource(String contentType, byte[] data) { + ByteArrayDataSource(byte[] data, @Nullable String contentType) { this.data = data; - this.contentType = contentType; + this.contentType = (contentType != null) ? contentType : "application/octet-stream"; } @Override diff --git a/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/MailSenderConnection.java b/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/MailSenderConnection.java index 036ef0e8..7d8305b5 100644 --- a/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/MailSenderConnection.java +++ b/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/MailSenderConnection.java @@ -47,6 +47,7 @@ import jakarta.mail.search.HeaderTerm; import jakarta.mail.search.SearchTerm; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.util.Assert; import org.springframework.ws.WebServiceMessage; @@ -70,11 +71,11 @@ public class MailSenderConnection extends AbstractSenderConnection { private final Session session; - private MimeMessage requestMessage; + private @Nullable MimeMessage requestMessage; - private Message responseMessage; + private @Nullable Message responseMessage; - private String requestContentType; + private @Nullable String requestContentType; private boolean deleteAfterReceive = false; @@ -82,19 +83,19 @@ public class MailSenderConnection extends AbstractSenderConnection { private final URLName transportUri; - private ByteArrayOutputStream requestBuffer; + private @Nullable ByteArrayOutputStream requestBuffer; - private InternetAddress from; + private @Nullable InternetAddress from; private final InternetAddress to; - private String subject; + private @Nullable String subject; private final long receiveTimeout; - private Store store; + private @Nullable Store store; - private Folder folder; + private @Nullable Folder folder; /** Constructs a new Mail connection with the given parameters. */ protected MailSenderConnection(Session session, URLName transportUri, URLName storeUri, InternetAddress to, @@ -111,12 +112,14 @@ public class MailSenderConnection extends AbstractSenderConnection { } /** Returns the request message for this connection. */ - public Message getRequestMessage() { + public MimeMessage getRequestMessage() { + Assert.notNull(this.requestMessage, "RequestMessage is not available"); return this.requestMessage; } /** Returns the response message, if any, for this connection. */ public Message getResponseMessage() { + Assert.notNull(this.responseMessage, "ResponseMessage is not available"); return this.responseMessage; } @@ -165,7 +168,7 @@ public class MailSenderConnection extends AbstractSenderConnection { @Override public void addRequestHeader(String name, String value) throws IOException { try { - this.requestMessage.addHeader(name, value); + getRequestMessage().addHeader(name, value); if (TransportConstants.HEADER_CONTENT_TYPE.equals(name)) { this.requestContentType = value; } @@ -177,15 +180,18 @@ public class MailSenderConnection extends AbstractSenderConnection { @Override protected OutputStream getRequestOutputStream() throws IOException { + Assert.notNull(this.requestBuffer, "Request OutputStream is not available"); return this.requestBuffer; } @Override protected void onSendAfterWrite(WebServiceMessage message) throws IOException { + Assert.state(this.requestMessage != null, "onSendBeforeWrite has not been called"); + Assert.state(this.requestBuffer != null, "onSendBeforeWrite has not been called"); Transport transport = null; try { this.requestMessage.setDataHandler(new DataHandler( - new ByteArrayDataSource(this.requestContentType, this.requestBuffer.toByteArray()))); + new ByteArrayDataSource(this.requestBuffer.toByteArray(), this.requestContentType))); transport = this.session.getTransport(this.transportUri); transport.connect(); this.requestMessage.saveChanges(); @@ -195,7 +201,9 @@ public class MailSenderConnection extends AbstractSenderConnection { throw new MailTransportException(ex); } finally { - MailTransportUtils.closeService(transport); + if (transport != null) { + MailTransportUtils.closeService(transport); + } } } @@ -205,6 +213,7 @@ public class MailSenderConnection extends AbstractSenderConnection { @Override protected void onReceiveBeforeRead() throws IOException { + Assert.state(this.requestMessage != null, "onSendBeforeWrite has not been called"); try { String requestMessageId = this.requestMessage.getMessageID(); Assert.hasLength(requestMessageId, "No Message-ID found on request message [" + this.requestMessage + "]"); @@ -215,7 +224,7 @@ public class MailSenderConnection extends AbstractSenderConnection { // Re-interrupt current thread, to allow other threads to react. Thread.currentThread().interrupt(); } - openFolder(); + this.folder = openFolder(); SearchTerm searchTerm = new HeaderTerm(MailTransportConstants.HEADER_IN_REPLY_TO, requestMessageId); Message[] responses = this.folder.search(searchTerm); if (responses.length > 0) { @@ -224,7 +233,7 @@ public class MailSenderConnection extends AbstractSenderConnection { } this.responseMessage = responses[0]; } - if (this.deleteAfterReceive) { + if (this.deleteAfterReceive && this.responseMessage != null) { this.responseMessage.setFlag(Flags.Flag.DELETED, true); } } @@ -233,19 +242,20 @@ public class MailSenderConnection extends AbstractSenderConnection { } } - private void openFolder() throws MessagingException { + private Folder openFolder() throws MessagingException { this.store = this.session.getStore(this.storeUri); this.store.connect(); - this.folder = this.store.getFolder(this.storeUri); - if (this.folder == null || !this.folder.exists()) { + Folder folder = this.store.getFolder(this.storeUri); + if (folder == null || !folder.exists()) { throw new IllegalStateException("No default folder to receive from"); } if (this.deleteAfterReceive) { - this.folder.open(Folder.READ_WRITE); + folder.open(Folder.READ_WRITE); } else { - this.folder.open(Folder.READ_ONLY); + folder.open(Folder.READ_ONLY); } + return folder; } @Override @@ -257,7 +267,7 @@ public class MailSenderConnection extends AbstractSenderConnection { public Iterator getResponseHeaderNames() throws IOException { try { List headers = new ArrayList<>(); - Enumeration enumeration = this.responseMessage.getAllHeaders(); + Enumeration enumeration = getResponseMessage().getAllHeaders(); while (enumeration.hasMoreElements()) { Header header = (Header) enumeration.nextElement(); headers.add(header.getName()); @@ -272,7 +282,7 @@ public class MailSenderConnection extends AbstractSenderConnection { @Override public Iterator getResponseHeaders(String name) throws IOException { try { - String[] headers = this.responseMessage.getHeader(name); + String[] headers = getResponseMessage().getHeader(name); return Arrays.asList(headers).iterator(); } catch (MessagingException ex) { @@ -284,7 +294,7 @@ public class MailSenderConnection extends AbstractSenderConnection { @Override protected InputStream getResponseInputStream() throws IOException { try { - return this.responseMessage.getDataHandler().getInputStream(); + return getResponseMessage().getDataHandler().getInputStream(); } catch (MessagingException ex) { throw new MailTransportException(ex); @@ -297,14 +307,18 @@ public class MailSenderConnection extends AbstractSenderConnection { } @Override - public String getErrorMessage() throws IOException { + public @Nullable String getErrorMessage() throws IOException { return null; } @Override public void onClose() throws IOException { - MailTransportUtils.closeFolder(this.folder, this.deleteAfterReceive); - MailTransportUtils.closeService(this.store); + if (this.folder != null) { + MailTransportUtils.closeFolder(this.folder, this.deleteAfterReceive); + } + if (this.store != null) { + MailTransportUtils.closeService(this.store); + } } private static final class ByteArrayDataSource implements DataSource { @@ -313,9 +327,9 @@ public class MailSenderConnection extends AbstractSenderConnection { private final byte[] data; - ByteArrayDataSource(String contentType, byte[] data) { + ByteArrayDataSource(byte[] data, @Nullable String contentType) { this.data = data; - this.contentType = contentType; + this.contentType = (contentType != null) ? contentType : "application/octet-stream"; } @Override diff --git a/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/monitor/ImapIdleMonitoringStrategy.java b/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/monitor/ImapIdleMonitoringStrategy.java index 3ca9502d..2ac02156 100644 --- a/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/monitor/ImapIdleMonitoringStrategy.java +++ b/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/monitor/ImapIdleMonitoringStrategy.java @@ -23,6 +23,7 @@ import jakarta.mail.event.MessageCountAdapter; import jakarta.mail.event.MessageCountEvent; import jakarta.mail.event.MessageCountListener; import org.eclipse.angus.mail.imap.IMAPFolder; +import org.jspecify.annotations.Nullable; import org.springframework.util.Assert; @@ -38,7 +39,7 @@ import org.springframework.util.Assert; */ public class ImapIdleMonitoringStrategy extends AbstractMonitoringStrategy { - private MessageCountListener messageCountListener; + private @Nullable MessageCountListener messageCountListener; @Override protected void waitForNewMessages(Folder folder) throws MessagingException, InterruptedException { diff --git a/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/monitor/package-info.java b/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/monitor/package-info.java index d3d3f0d2..f9635b1d 100644 --- a/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/monitor/package-info.java +++ b/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/monitor/package-info.java @@ -18,4 +18,7 @@ * Provides the MonitoringStrategy interface and implementations. Used for monitoring a * JavaMail Folder for new email messages. */ +@NullMarked package org.springframework.ws.transport.mail.monitor; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/package-info.java b/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/package-info.java index 79b2082c..63b261a1 100644 --- a/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/package-info.java +++ b/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/package-info.java @@ -17,4 +17,7 @@ /** * Package providing support for handling messages via email. */ +@NullMarked package org.springframework.ws.transport.mail; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/support/MailTransportUtils.java b/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/support/MailTransportUtils.java index 60cc82e5..40155dd9 100644 --- a/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/support/MailTransportUtils.java +++ b/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/support/MailTransportUtils.java @@ -29,6 +29,7 @@ import jakarta.mail.internet.AddressException; import jakarta.mail.internet.InternetAddress; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.util.StringUtils; import org.springframework.ws.transport.mail.MailTransportConstants; @@ -50,7 +51,7 @@ public abstract class MailTransportUtils { private MailTransportUtils() { } - public static InternetAddress getTo(URI uri) { + public static @Nullable InternetAddress getTo(URI uri) { Matcher matcher = TO_PATTERN.matcher(uri.getSchemeSpecificPart()); if (matcher.find()) { for (int i = 1; i <= matcher.groupCount(); i++) { @@ -68,7 +69,7 @@ public abstract class MailTransportUtils { return null; } - public static String getSubject(URI uri) { + public static @Nullable String getSubject(URI uri) { Matcher matcher = SUBJECT_PATTERN.matcher(uri.getSchemeSpecificPart()); if (matcher.find()) { return matcher.group(1); @@ -83,7 +84,7 @@ public abstract class MailTransportUtils { * @see jakarta.mail.Transport * @see jakarta.mail.Store */ - public static void closeService(Service service) { + public static void closeService(@Nullable Service service) { if (service != null) { try { service.close(); @@ -110,7 +111,7 @@ public abstract class MailTransportUtils { * @param folder the JavaMail Folder to close (may be {@code null}) * @param expunge whether all deleted messages should be expunged from the folder */ - public static void closeFolder(Folder folder, boolean expunge) { + public static void closeFolder(@Nullable Folder folder, boolean expunge) { if (folder != null && folder.isOpen()) { try { folder.close(expunge); @@ -172,7 +173,7 @@ public abstract class MailTransportUtils { * @param subject the subject, may be {@code null} * @return a mailto URI */ - public static URI toUri(InternetAddress to, String subject) throws URISyntaxException { + public static URI toUri(InternetAddress to, @Nullable String subject) throws URISyntaxException { if (StringUtils.hasLength(subject)) { return new URI(MailTransportConstants.MAIL_URI_SCHEME, to.getAddress() + "?subject=" + subject, null); } diff --git a/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/support/package-info.java b/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/support/package-info.java index 2a9024ff..e495bea1 100644 --- a/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/support/package-info.java +++ b/spring-ws-support/src/main/java/org/springframework/ws/transport/mail/support/package-info.java @@ -17,4 +17,7 @@ /** * Classes supporting the org.springframework.ws.transport.mail package. */ +@NullMarked package org.springframework.ws.transport.mail.support; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-support/src/main/java/org/springframework/ws/transport/xmpp/XmppMessageReceiver.java b/spring-ws-support/src/main/java/org/springframework/ws/transport/xmpp/XmppMessageReceiver.java index 1c43da60..3823f47f 100644 --- a/spring-ws-support/src/main/java/org/springframework/ws/transport/xmpp/XmppMessageReceiver.java +++ b/spring-ws-support/src/main/java/org/springframework/ws/transport/xmpp/XmppMessageReceiver.java @@ -26,7 +26,9 @@ import org.jivesoftware.smack.filter.StanzaTypeFilter; import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smack.tcp.XMPPTCPConnection; +import org.jspecify.annotations.Nullable; +import org.springframework.util.Assert; import org.springframework.ws.transport.support.AbstractStandaloneMessageReceiver; /** @@ -51,9 +53,9 @@ public class XmppMessageReceiver extends AbstractStandaloneMessageReceiver { */ public static final String DEFAULT_MESSAGE_ENCODING = "UTF-8"; - private XMPPTCPConnection connection; + private @Nullable XMPPTCPConnection connection; - private WebServicePacketListener packetListener; + private @Nullable WebServicePacketListener packetListener; private final String messageEncoding = DEFAULT_MESSAGE_ENCODING; @@ -65,11 +67,16 @@ public class XmppMessageReceiver extends AbstractStandaloneMessageReceiver { this.connection = connection; } + private XMPPTCPConnection getConnection() { + Assert.state(this.connection != null, "Connection is required"); + return this.connection; + } + @Override protected void onActivate() throws XMPPException, IOException, SmackException { - if (!this.connection.isConnected()) { + if (!getConnection().isConnected()) { try { - this.connection.connect(); + getConnection().connect(); } catch (InterruptedException ex) { throw new IOException(ex); @@ -80,29 +87,29 @@ public class XmppMessageReceiver extends AbstractStandaloneMessageReceiver { @Override protected void onStart() { if (this.logger.isInfoEnabled()) { - this.logger.info("Starting XMPP receiver [" + this.connection.getUser() + "]"); + this.logger.info("Starting XMPP receiver [" + getConnection().getUser() + "]"); } this.packetListener = new WebServicePacketListener(); StanzaFilter packetFilter = new StanzaTypeFilter(Message.class); - this.connection.addAsyncStanzaListener(this.packetListener, packetFilter); + getConnection().addAsyncStanzaListener(this.packetListener, packetFilter); } @Override protected void onStop() { if (this.logger.isInfoEnabled()) { - this.logger.info("Stopping XMPP receiver [" + this.connection.getUser() + "]"); + this.logger.info("Stopping XMPP receiver [" + getConnection().getUser() + "]"); } - this.connection.removeAsyncStanzaListener(this.packetListener); + getConnection().removeAsyncStanzaListener(this.packetListener); this.packetListener = null; } @Override protected void onShutdown() { if (this.logger.isInfoEnabled()) { - this.logger.info("Shutting down XMPP receiver [" + this.connection.getUser() + "]"); + this.logger.info("Shutting down XMPP receiver [" + getConnection().getUser() + "]"); } - if (this.connection.isConnected()) { - this.connection.disconnect(); + if (getConnection().isConnected()) { + getConnection().disconnect(); } } @@ -113,8 +120,7 @@ public class XmppMessageReceiver extends AbstractStandaloneMessageReceiver { XmppMessageReceiver.this.logger.info("Received " + packet); if (packet instanceof Message message) { try { - XmppReceiverConnection wsConnection = new XmppReceiverConnection( - XmppMessageReceiver.this.connection, message); + XmppReceiverConnection wsConnection = new XmppReceiverConnection(getConnection(), message); wsConnection.setMessageEncoding(XmppMessageReceiver.this.messageEncoding); handleConnection(wsConnection); } diff --git a/spring-ws-support/src/main/java/org/springframework/ws/transport/xmpp/XmppMessageSender.java b/spring-ws-support/src/main/java/org/springframework/ws/transport/xmpp/XmppMessageSender.java index 50e5a64b..920f8dd0 100644 --- a/spring-ws-support/src/main/java/org/springframework/ws/transport/xmpp/XmppMessageSender.java +++ b/spring-ws-support/src/main/java/org/springframework/ws/transport/xmpp/XmppMessageSender.java @@ -18,9 +18,11 @@ package org.springframework.ws.transport.xmpp; import java.io.IOException; import java.net.URI; +import java.util.Objects; import java.util.UUID; import org.jivesoftware.smack.XMPPConnection; +import org.jspecify.annotations.Nullable; import org.springframework.beans.factory.InitializingBean; import org.springframework.util.Assert; @@ -58,7 +60,7 @@ public class XmppMessageSender implements WebServiceMessageSender, InitializingB private String messageEncoding = DEFAULT_MESSAGE_ENCODING; - private XMPPConnection connection; + private @Nullable XMPPConnection connection; /** * Sets the {@code XMPPConnection}. Setting this property is required. @@ -93,7 +95,7 @@ public class XmppMessageSender implements WebServiceMessageSender, InitializingB public WebServiceConnection createConnection(URI uri) throws IOException { String to = XmppTransportUtils.getTo(uri); String thread = createThread(); - XmppSenderConnection connection = new XmppSenderConnection(this.connection, to, thread); + XmppSenderConnection connection = new XmppSenderConnection(Objects.requireNonNull(this.connection), to, thread); connection.setReceiveTimeout(this.receiveTimeout); connection.setMessageEncoding(this.messageEncoding); return connection; diff --git a/spring-ws-support/src/main/java/org/springframework/ws/transport/xmpp/XmppReceiverConnection.java b/spring-ws-support/src/main/java/org/springframework/ws/transport/xmpp/XmppReceiverConnection.java index 6139ebf2..46c73a4d 100644 --- a/spring-ws-support/src/main/java/org/springframework/ws/transport/xmpp/XmppReceiverConnection.java +++ b/spring-ws-support/src/main/java/org/springframework/ws/transport/xmpp/XmppReceiverConnection.java @@ -22,10 +22,12 @@ import java.io.OutputStream; import java.net.URI; import java.net.URISyntaxException; import java.util.Iterator; +import java.util.Objects; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.packet.Message; +import org.jspecify.annotations.Nullable; import org.springframework.util.Assert; import org.springframework.ws.WebServiceMessage; @@ -48,9 +50,9 @@ public class XmppReceiverConnection extends AbstractReceiverConnection { private final Message requestMessage; - private Message responseMessage; + private @Nullable Message responseMessage; - private String messageEncoding; + private String messageEncoding = XmppMessageReceiver.DEFAULT_MESSAGE_ENCODING; public XmppReceiverConnection(XMPPConnection connection, Message requestMessage) { Assert.notNull(connection, "'connection' must not be null"); @@ -65,7 +67,7 @@ public class XmppReceiverConnection extends AbstractReceiverConnection { } /** Returns the response message, if any, for this connection. */ - public Message getResponseMessage() { + public @Nullable Message getResponseMessage() { return this.responseMessage; } @@ -96,7 +98,7 @@ public class XmppReceiverConnection extends AbstractReceiverConnection { } @Override - public String getErrorMessage() { + public @Nullable String getErrorMessage() { return XmppTransportUtils.getErrorMessage(this.responseMessage); } @@ -132,12 +134,12 @@ public class XmppReceiverConnection extends AbstractReceiverConnection { @Override public void addResponseHeader(String name, String value) throws IOException { - XmppTransportUtils.addHeader(this.responseMessage, name, value); + XmppTransportUtils.addHeader(Objects.requireNonNull(this.responseMessage), name, value); } @Override protected OutputStream getResponseOutputStream() throws IOException { - return new MessageOutputStream(this.responseMessage, this.messageEncoding); + return new MessageOutputStream(Objects.requireNonNull(this.responseMessage), this.messageEncoding); } @Override diff --git a/spring-ws-support/src/main/java/org/springframework/ws/transport/xmpp/XmppSenderConnection.java b/spring-ws-support/src/main/java/org/springframework/ws/transport/xmpp/XmppSenderConnection.java index f7bd8f24..0c56ced6 100644 --- a/spring-ws-support/src/main/java/org/springframework/ws/transport/xmpp/XmppSenderConnection.java +++ b/spring-ws-support/src/main/java/org/springframework/ws/transport/xmpp/XmppSenderConnection.java @@ -22,6 +22,7 @@ import java.io.OutputStream; import java.net.URI; import java.net.URISyntaxException; import java.util.Iterator; +import java.util.Objects; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.StanzaCollector; @@ -32,6 +33,7 @@ import org.jivesoftware.smack.filter.StanzaTypeFilter; import org.jivesoftware.smack.filter.ThreadFilter; import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Stanza; +import org.jspecify.annotations.Nullable; import org.jxmpp.jid.impl.JidCreate; import org.jxmpp.stringprep.XmppStringprepException; @@ -56,9 +58,9 @@ public class XmppSenderConnection extends AbstractSenderConnection { private final XMPPConnection connection; - private Message responseMessage; + private @Nullable Message responseMessage; - private String messageEncoding; + private String messageEncoding = XmppMessageReceiver.DEFAULT_MESSAGE_ENCODING; private long receiveTimeout; @@ -82,7 +84,7 @@ public class XmppSenderConnection extends AbstractSenderConnection { } /** Returns the response message, if any, for this connection. */ - public Message getResponseMessage() { + public @Nullable Message getResponseMessage() { return this.responseMessage; } @@ -117,7 +119,7 @@ public class XmppSenderConnection extends AbstractSenderConnection { } @Override - public String getErrorMessage() { + public @Nullable String getErrorMessage() { return XmppTransportUtils.getErrorMessage(this.responseMessage); } @@ -185,17 +187,17 @@ public class XmppSenderConnection extends AbstractSenderConnection { @Override public Iterator getResponseHeaderNames() { - return XmppTransportUtils.getHeaderNames(this.responseMessage); + return XmppTransportUtils.getHeaderNames(Objects.requireNonNull(this.responseMessage)); } @Override public Iterator getResponseHeaders(String name) throws IOException { - return XmppTransportUtils.getHeaders(this.responseMessage, name); + return XmppTransportUtils.getHeaders(Objects.requireNonNull(this.responseMessage), name); } @Override protected InputStream getResponseInputStream() throws IOException { - return new MessageInputStream(this.responseMessage, this.messageEncoding); + return new MessageInputStream(Objects.requireNonNull(this.responseMessage), this.messageEncoding); } } diff --git a/spring-ws-support/src/main/java/org/springframework/ws/transport/xmpp/package-info.java b/spring-ws-support/src/main/java/org/springframework/ws/transport/xmpp/package-info.java index fafabfb6..95fa5b50 100644 --- a/spring-ws-support/src/main/java/org/springframework/ws/transport/xmpp/package-info.java +++ b/spring-ws-support/src/main/java/org/springframework/ws/transport/xmpp/package-info.java @@ -17,4 +17,7 @@ /** * Package providing support for handling messages via XMPP. */ +@NullMarked package org.springframework.ws.transport.xmpp; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-support/src/main/java/org/springframework/ws/transport/xmpp/support/XmppConnectionFactoryBean.java b/spring-ws-support/src/main/java/org/springframework/ws/transport/xmpp/support/XmppConnectionFactoryBean.java index bd774a20..d1d53ef5 100644 --- a/spring-ws-support/src/main/java/org/springframework/ws/transport/xmpp/support/XmppConnectionFactoryBean.java +++ b/spring-ws-support/src/main/java/org/springframework/ws/transport/xmpp/support/XmppConnectionFactoryBean.java @@ -17,11 +17,13 @@ package org.springframework.ws.transport.xmpp.support; import java.io.IOException; +import java.util.Objects; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.tcp.XMPPTCPConnection; import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration; +import org.jspecify.annotations.Nullable; import org.jxmpp.jid.parts.Resourcepart; import org.jxmpp.stringprep.XmppStringprepException; @@ -43,19 +45,19 @@ public class XmppConnectionFactoryBean implements FactoryBean private static final int DEFAULT_PORT = 5222; - private XMPPTCPConnection connection; + private @Nullable XMPPTCPConnection connection; - private String host; + private @Nullable String host; private int port = DEFAULT_PORT; - private String serviceName; + private @Nullable String serviceName; - private String username; + private @Nullable String username; - private String password; + private @Nullable String password; - private String resource; + private @Nullable String resource; /** Sets the server host to connect to. */ public void setHost(String host) { @@ -91,6 +93,7 @@ public class XmppConnectionFactoryBean implements FactoryBean @Override public void afterPropertiesSet() throws XMPPException, IOException, SmackException { + Assert.hasText(this.host, "'host' must not be empty"); XMPPTCPConnectionConfiguration configuration = createConnectionConfiguration(this.host, this.port, this.serviceName); Assert.notNull(configuration, "'configuration' must not be null"); @@ -114,12 +117,12 @@ public class XmppConnectionFactoryBean implements FactoryBean @Override public void destroy() { - this.connection.disconnect(); + Objects.requireNonNull(this.connection).disconnect(); } @Override public XMPPTCPConnection getObject() { - return this.connection; + return Objects.requireNonNull(this.connection); } @Override @@ -138,8 +141,8 @@ public class XmppConnectionFactoryBean implements FactoryBean * @param port the port to connect to * @param serviceName the name of the service to connect to. May be {@code null} */ - protected XMPPTCPConnectionConfiguration createConnectionConfiguration(String host, int port, String serviceName) - throws XmppStringprepException { + protected XMPPTCPConnectionConfiguration createConnectionConfiguration(String host, int port, + @Nullable String serviceName) throws XmppStringprepException { Assert.hasText(host, "'host' must not be empty"); if (StringUtils.hasText(serviceName)) { return XMPPTCPConnectionConfiguration.builder() diff --git a/spring-ws-support/src/main/java/org/springframework/ws/transport/xmpp/support/XmppTransportUtils.java b/spring-ws-support/src/main/java/org/springframework/ws/transport/xmpp/support/XmppTransportUtils.java index 6e730804..e555e40a 100644 --- a/spring-ws-support/src/main/java/org/springframework/ws/transport/xmpp/support/XmppTransportUtils.java +++ b/spring-ws-support/src/main/java/org/springframework/ws/transport/xmpp/support/XmppTransportUtils.java @@ -23,6 +23,7 @@ import java.util.Iterator; import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smackx.jiveproperties.JivePropertiesManager; +import org.jspecify.annotations.Nullable; import org.springframework.util.Assert; import org.springframework.ws.transport.xmpp.XmppTransportConstants; @@ -49,11 +50,11 @@ public abstract class XmppTransportUtils { return uri.getSchemeSpecificPart(); } - public static boolean hasError(Message message) { + public static boolean hasError(@Nullable Message message) { return message != null && Message.Type.error.equals(message.getType()); } - public static String getErrorMessage(Message message) { + public static @Nullable String getErrorMessage(@Nullable Message message) { if (message == null || !Message.Type.error.equals(message.getType())) { return null; } diff --git a/spring-ws-support/src/main/java/org/springframework/ws/transport/xmpp/support/package-info.java b/spring-ws-support/src/main/java/org/springframework/ws/transport/xmpp/support/package-info.java index 4bfed310..47e1b38a 100644 --- a/spring-ws-support/src/main/java/org/springframework/ws/transport/xmpp/support/package-info.java +++ b/spring-ws-support/src/main/java/org/springframework/ws/transport/xmpp/support/package-info.java @@ -17,4 +17,7 @@ /** * Support classes for handling messages via XMPP. */ +@NullMarked package org.springframework.ws.transport.xmpp.support; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-test/src/main/java/org/springframework/ws/test/client/ErrorResponseCreator.java b/spring-ws-test/src/main/java/org/springframework/ws/test/client/ErrorResponseCreator.java index 8a3498a1..6f33a048 100644 --- a/spring-ws-test/src/main/java/org/springframework/ws/test/client/ErrorResponseCreator.java +++ b/spring-ws-test/src/main/java/org/springframework/ws/test/client/ErrorResponseCreator.java @@ -40,8 +40,7 @@ class ErrorResponseCreator implements ResponseCreator { @Override public WebServiceMessage createResponse(URI uri, WebServiceMessage request, WebServiceMessageFactory factory) throws IOException { - // Do nothing - return null; + throw new UnsupportedOperationException(); } String getErrorMessage() { diff --git a/spring-ws-test/src/main/java/org/springframework/ws/test/client/MockSenderConnection.java b/spring-ws-test/src/main/java/org/springframework/ws/test/client/MockSenderConnection.java index 958b5d4c..fcce18a6 100644 --- a/spring-ws-test/src/main/java/org/springframework/ws/test/client/MockSenderConnection.java +++ b/spring-ws-test/src/main/java/org/springframework/ws/test/client/MockSenderConnection.java @@ -20,6 +20,9 @@ import java.io.IOException; import java.net.URI; import java.util.LinkedList; import java.util.List; +import java.util.Objects; + +import org.jspecify.annotations.Nullable; import org.springframework.util.Assert; import org.springframework.ws.WebServiceMessage; @@ -38,11 +41,11 @@ class MockSenderConnection implements WebServiceConnection, ResponseActions { private final List requestMatchers = new LinkedList<>(); - private URI uri; + private @Nullable URI uri; - private WebServiceMessage request; + private @Nullable WebServiceMessage request; - private ResponseCreator responseCreator; + private @Nullable ResponseCreator responseCreator; void addRequestMatcher(RequestMatcher requestMatcher) { Assert.notNull(requestMatcher, "'requestMatcher' must not be null"); @@ -74,7 +77,7 @@ class MockSenderConnection implements WebServiceConnection, ResponseActions { public void send(WebServiceMessage message) throws IOException { if (!this.requestMatchers.isEmpty()) { for (RequestMatcher requestMatcher : this.requestMatchers) { - requestMatcher.match(this.uri, message); + requestMatcher.match(Objects.requireNonNull(this.uri), message); } } else { @@ -84,9 +87,10 @@ class MockSenderConnection implements WebServiceConnection, ResponseActions { } @Override - public WebServiceMessage receive(WebServiceMessageFactory messageFactory) throws IOException { + public @Nullable WebServiceMessage receive(WebServiceMessageFactory messageFactory) throws IOException { if (this.responseCreator != null) { - return this.responseCreator.createResponse(this.uri, this.request, messageFactory); + return this.responseCreator.createResponse(Objects.requireNonNull(this.uri), + Objects.requireNonNull(this.request), messageFactory); } else { return null; @@ -94,7 +98,7 @@ class MockSenderConnection implements WebServiceConnection, ResponseActions { } @Override - public URI getUri() { + public @Nullable URI getUri() { return this.uri; } @@ -104,7 +108,7 @@ class MockSenderConnection implements WebServiceConnection, ResponseActions { } @Override - public String getErrorMessage() throws IOException { + public @Nullable String getErrorMessage() throws IOException { if (this.responseCreator instanceof ErrorResponseCreator) { return ((ErrorResponseCreator) this.responseCreator).getErrorMessage(); } diff --git a/spring-ws-test/src/main/java/org/springframework/ws/test/client/MockWebServiceMessageSender.java b/spring-ws-test/src/main/java/org/springframework/ws/test/client/MockWebServiceMessageSender.java index c752dce7..e2c75b16 100644 --- a/spring-ws-test/src/main/java/org/springframework/ws/test/client/MockWebServiceMessageSender.java +++ b/spring-ws-test/src/main/java/org/springframework/ws/test/client/MockWebServiceMessageSender.java @@ -22,6 +22,8 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; import org.springframework.ws.transport.WebServiceMessageSender; @@ -38,7 +40,7 @@ public class MockWebServiceMessageSender implements WebServiceMessageSender { private final List expectedConnections = new LinkedList<>(); - private Iterator connectionIterator; + private @Nullable Iterator connectionIterator; @Override public MockSenderConnection createConnection(URI uri) throws IOException { diff --git a/spring-ws-test/src/main/java/org/springframework/ws/test/client/XPathExpectationsHelperAdapter.java b/spring-ws-test/src/main/java/org/springframework/ws/test/client/XPathExpectationsHelperAdapter.java index 8d5384e8..7cba27e6 100644 --- a/spring-ws-test/src/main/java/org/springframework/ws/test/client/XPathExpectationsHelperAdapter.java +++ b/spring-ws-test/src/main/java/org/springframework/ws/test/client/XPathExpectationsHelperAdapter.java @@ -18,6 +18,8 @@ package org.springframework.ws.test.client; import java.util.Map; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.test.support.matcher.XPathExpectationsHelper; /** @@ -31,7 +33,7 @@ class XPathExpectationsHelperAdapter implements RequestXPathExpectations { private final XPathExpectationsHelper helper; - XPathExpectationsHelperAdapter(String expression, Map namespaces) { + XPathExpectationsHelperAdapter(String expression, @Nullable Map namespaces) { this.helper = new XPathExpectationsHelper(expression, namespaces); } diff --git a/spring-ws-test/src/main/java/org/springframework/ws/test/client/package-info.java b/spring-ws-test/src/main/java/org/springframework/ws/test/client/package-info.java index 2e9632c9..170df3f2 100644 --- a/spring-ws-test/src/main/java/org/springframework/ws/test/client/package-info.java +++ b/spring-ws-test/src/main/java/org/springframework/ws/test/client/package-info.java @@ -19,4 +19,7 @@ * the {@link org.springframework.ws.test.client.MockWebServiceServer}, and various * related test interfaces. */ +@NullMarked package org.springframework.ws.test.client; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-test/src/main/java/org/springframework/ws/test/server/MockWebServiceClient.java b/spring-ws-test/src/main/java/org/springframework/ws/test/server/MockWebServiceClient.java index baac4b3d..e9b0050e 100644 --- a/spring-ws-test/src/main/java/org/springframework/ws/test/server/MockWebServiceClient.java +++ b/spring-ws-test/src/main/java/org/springframework/ws/test/server/MockWebServiceClient.java @@ -29,7 +29,6 @@ import org.springframework.ws.context.DefaultMessageContext; import org.springframework.ws.context.MessageContext; import org.springframework.ws.soap.saaj.SaajSoapMessageFactory; import org.springframework.ws.soap.server.SoapMessageDispatcher; -import org.springframework.ws.test.support.AssertionErrors; import org.springframework.ws.test.support.MockStrategiesHelper; import org.springframework.ws.transport.WebServiceMessageReceiver; @@ -185,8 +184,7 @@ public final class MockWebServiceClient { } catch (Exception ex) { logger.error("Could not send request", ex); - AssertionErrors.fail(ex.getMessage()); - return null; + throw new AssertionError(ex.getMessage()); } } @@ -206,8 +204,7 @@ public final class MockWebServiceClient { WebServiceMessage request = this.messageContext.getRequest(); WebServiceMessage response = this.messageContext.getResponse(); if (response == null) { - AssertionErrors.fail("No response received"); - return null; + throw new AssertionError("No response received"); } try { responseMatcher.match(request, response); @@ -215,8 +212,7 @@ public final class MockWebServiceClient { } catch (IOException ex) { logger.error("Could not match request", ex); - AssertionErrors.fail(ex.getMessage()); - return null; + throw new AssertionError(ex.getMessage()); } } diff --git a/spring-ws-test/src/main/java/org/springframework/ws/test/server/ResponseMatchers.java b/spring-ws-test/src/main/java/org/springframework/ws/test/server/ResponseMatchers.java index 748cbf6a..c855ba07 100644 --- a/spring-ws-test/src/main/java/org/springframework/ws/test/server/ResponseMatchers.java +++ b/spring-ws-test/src/main/java/org/springframework/ws/test/server/ResponseMatchers.java @@ -23,6 +23,8 @@ import java.util.Map; import javax.xml.namespace.QName; import javax.xml.transform.Source; +import org.jspecify.annotations.Nullable; + import org.springframework.core.io.Resource; import org.springframework.util.Assert; import org.springframework.ws.FaultAwareWebServiceMessage; @@ -160,7 +162,7 @@ public abstract class ResponseMatchers { * {@code null} the fault string or reason text will not be verified * @see org.springframework.ws.soap.SoapBody#addMustUnderstandFault(String, Locale) */ - public static ResponseMatcher mustUnderstandFault(String faultStringOrReason) { + public static ResponseMatcher mustUnderstandFault(@Nullable String faultStringOrReason) { return new SoapFaultResponseMatcher(faultStringOrReason) { @Override protected QName getExpectedFaultCode(SoapVersion version) { @@ -184,7 +186,7 @@ public abstract class ResponseMatchers { * {@code null} the fault string or reason text will not be verified * @see org.springframework.ws.soap.SoapBody#addClientOrSenderFault(String, Locale) */ - public static ResponseMatcher clientOrSenderFault(String faultStringOrReason) { + public static ResponseMatcher clientOrSenderFault(@Nullable String faultStringOrReason) { return new SoapFaultResponseMatcher(faultStringOrReason) { @Override protected QName getExpectedFaultCode(SoapVersion version) { @@ -209,7 +211,7 @@ public abstract class ResponseMatchers { * {@code null} the fault string or reason text will not be verified * @see org.springframework.ws.soap.SoapBody#addClientOrSenderFault(String, Locale) */ - public static ResponseMatcher serverOrReceiverFault(String faultStringOrReason) { + public static ResponseMatcher serverOrReceiverFault(@Nullable String faultStringOrReason) { return new SoapFaultResponseMatcher(faultStringOrReason) { @Override protected QName getExpectedFaultCode(SoapVersion version) { @@ -233,7 +235,7 @@ public abstract class ResponseMatchers { * {@code null} the fault string or reason text will not be verified * @see org.springframework.ws.soap.SoapBody#addClientOrSenderFault(String, Locale) */ - public static ResponseMatcher versionMismatchFault(String faultStringOrReason) { + public static ResponseMatcher versionMismatchFault(@Nullable String faultStringOrReason) { return new SoapFaultResponseMatcher(faultStringOrReason) { @Override protected QName getExpectedFaultCode(SoapVersion version) { diff --git a/spring-ws-test/src/main/java/org/springframework/ws/test/server/SoapFaultResponseMatcher.java b/spring-ws-test/src/main/java/org/springframework/ws/test/server/SoapFaultResponseMatcher.java index b57a441f..274a61d1 100644 --- a/spring-ws-test/src/main/java/org/springframework/ws/test/server/SoapFaultResponseMatcher.java +++ b/spring-ws-test/src/main/java/org/springframework/ws/test/server/SoapFaultResponseMatcher.java @@ -20,6 +20,8 @@ import java.io.IOException; import javax.xml.namespace.QName; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.WebServiceMessage; import org.springframework.ws.soap.SoapBody; import org.springframework.ws.soap.SoapFault; @@ -35,9 +37,9 @@ import org.springframework.ws.test.support.AssertionErrors; */ abstract class SoapFaultResponseMatcher implements ResponseMatcher { - private final String expectedFaultStringOrReason; + private final @Nullable String expectedFaultStringOrReason; - SoapFaultResponseMatcher(String expectedFaultStringOrReason) { + SoapFaultResponseMatcher(@Nullable String expectedFaultStringOrReason) { this.expectedFaultStringOrReason = expectedFaultStringOrReason; } @@ -50,10 +52,11 @@ abstract class SoapFaultResponseMatcher implements ResponseMatcher { AssertionErrors.assertTrue("Response has no SOAP Fault", responseBody.hasFault()); SoapFault soapFault = responseBody.getFault(); QName expectedFaultCode = getExpectedFaultCode(soapResponse.getVersion()); - AssertionErrors.assertEquals("Invalid SOAP Fault code", expectedFaultCode, soapFault.getFaultCode()); + AssertionErrors.assertEquals("Invalid SOAP Fault code", expectedFaultCode, + (soapFault != null) ? soapFault.getFaultCode() : null); if (this.expectedFaultStringOrReason != null) { AssertionErrors.assertEquals("Invalid SOAP Fault string/reason", this.expectedFaultStringOrReason, - soapFault.getFaultStringOrReason()); + (soapFault != null) ? soapFault.getFaultStringOrReason() : null); } } diff --git a/spring-ws-test/src/main/java/org/springframework/ws/test/server/XPathExpectationsHelperAdapter.java b/spring-ws-test/src/main/java/org/springframework/ws/test/server/XPathExpectationsHelperAdapter.java index 01232535..5e9b87aa 100644 --- a/spring-ws-test/src/main/java/org/springframework/ws/test/server/XPathExpectationsHelperAdapter.java +++ b/spring-ws-test/src/main/java/org/springframework/ws/test/server/XPathExpectationsHelperAdapter.java @@ -18,6 +18,8 @@ package org.springframework.ws.test.server; import java.util.Map; +import org.jspecify.annotations.Nullable; + import org.springframework.ws.test.support.matcher.XPathExpectationsHelper; /** @@ -31,7 +33,7 @@ class XPathExpectationsHelperAdapter implements ResponseXPathExpectations { private final XPathExpectationsHelper helper; - XPathExpectationsHelperAdapter(String expression, Map namespaces) { + XPathExpectationsHelperAdapter(String expression, @Nullable Map namespaces) { this.helper = new XPathExpectationsHelper(expression, namespaces); } diff --git a/spring-ws-test/src/main/java/org/springframework/ws/test/server/package-info.java b/spring-ws-test/src/main/java/org/springframework/ws/test/server/package-info.java index 8b068324..87f9b0fd 100644 --- a/spring-ws-test/src/main/java/org/springframework/ws/test/server/package-info.java +++ b/spring-ws-test/src/main/java/org/springframework/ws/test/server/package-info.java @@ -19,4 +19,7 @@ * the {@link org.springframework.ws.test.server.MockWebServiceClient}, and various * related test interfaces. */ +@NullMarked package org.springframework.ws.test.server; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-test/src/main/java/org/springframework/ws/test/support/AssertionErrors.java b/spring-ws-test/src/main/java/org/springframework/ws/test/support/AssertionErrors.java index 4f89ce50..f6364111 100644 --- a/spring-ws-test/src/main/java/org/springframework/ws/test/support/AssertionErrors.java +++ b/spring-ws-test/src/main/java/org/springframework/ws/test/support/AssertionErrors.java @@ -18,6 +18,10 @@ package org.springframework.ws.test.support; import javax.xml.transform.Source; +import org.jspecify.annotations.Nullable; + +import org.springframework.lang.Contract; + /** * JUnit independent assertion class. * @@ -34,7 +38,8 @@ public abstract class AssertionErrors { * Fails a test with the given message. * @param message the message */ - public static void fail(String message) { + @Contract("_ -> fail") + public static void fail(@Nullable String message) { throw new AssertionError(message); } @@ -43,7 +48,7 @@ public abstract class AssertionErrors { * @param message the message * @param source the source */ - public static void fail(String message, String sourceLabel, Source source) { + public static void fail(String message, @Nullable String sourceLabel, @Nullable Source source) { if (source != null) { throw new SourceAssertionError(message, sourceLabel, source); } @@ -68,7 +73,8 @@ public abstract class AssertionErrors { * @param message the message * @param condition the condition to test for */ - public static void assertTrue(String message, boolean condition, String sourceLabel, Source source) { + public static void assertTrue(String message, boolean condition, @Nullable String sourceLabel, + @Nullable Source source) { if (!condition) { fail(message, sourceLabel, source); } @@ -81,7 +87,7 @@ public abstract class AssertionErrors { * @param expected the expected value * @param actual the actual value */ - public static void assertEquals(String message, Object expected, Object actual) { + public static void assertEquals(String message, @Nullable Object expected, @Nullable Object actual) { assertEquals(message, expected, actual, null, null); } @@ -93,7 +99,8 @@ public abstract class AssertionErrors { * @param actual the actual value * @param source the source */ - public static void assertEquals(String message, Object expected, Object actual, String sourceLabel, Source source) { + public static void assertEquals(String message, @Nullable Object expected, @Nullable Object actual, + @Nullable String sourceLabel, @Nullable Source source) { if (expected == null && actual == null) { return; } diff --git a/spring-ws-test/src/main/java/org/springframework/ws/test/support/MockStrategiesHelper.java b/spring-ws-test/src/main/java/org/springframework/ws/test/support/MockStrategiesHelper.java index d0f06c5e..313105ef 100644 --- a/spring-ws-test/src/main/java/org/springframework/ws/test/support/MockStrategiesHelper.java +++ b/spring-ws-test/src/main/java/org/springframework/ws/test/support/MockStrategiesHelper.java @@ -20,6 +20,7 @@ import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.BeanCreationException; @@ -65,7 +66,7 @@ public class MockStrategiesHelper { * @return the bean, or {@code null} if no bean of the given type can be found * @throws BeanInitializationException if there is more than 1 beans of the given type */ - public T getStrategy(Class type) { + public @Nullable T getStrategy(Class type) { Assert.notNull(type, "'type' must not be null"); Map map = this.applicationContext.getBeansOfType(type); if (map.isEmpty()) { diff --git a/spring-ws-test/src/main/java/org/springframework/ws/test/support/SourceAssertionError.java b/spring-ws-test/src/main/java/org/springframework/ws/test/support/SourceAssertionError.java index 6c287789..ba5c706d 100644 --- a/spring-ws-test/src/main/java/org/springframework/ws/test/support/SourceAssertionError.java +++ b/spring-ws-test/src/main/java/org/springframework/ws/test/support/SourceAssertionError.java @@ -22,6 +22,8 @@ import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; +import org.jspecify.annotations.Nullable; + import org.springframework.xml.transform.StringResult; import org.springframework.xml.transform.TransformerHelper; @@ -36,9 +38,9 @@ import org.springframework.xml.transform.TransformerHelper; @SuppressWarnings("serial") public class SourceAssertionError extends AssertionError { - private final String sourceLabel; + private final @Nullable String sourceLabel; - private final Source source; + private final @Nullable Source source; private final TransformerHelper transformerHelper = new TransformerHelper(); @@ -46,7 +48,7 @@ public class SourceAssertionError extends AssertionError { * Creates a new instance of the {@code SourceAssertionError} class with the given * parameters. */ - public SourceAssertionError(String detailMessage, String sourceLabel, Source source) { + public SourceAssertionError(String detailMessage, @Nullable String sourceLabel, @Nullable Source source) { super(detailMessage); this.sourceLabel = sourceLabel; this.source = source; @@ -56,7 +58,7 @@ public class SourceAssertionError extends AssertionError { * Returns the source context of this error. * @return the source */ - public Source getSource() { + public @Nullable Source getSource() { return this.source; } @@ -76,7 +78,7 @@ public class SourceAssertionError extends AssertionError { return builder.toString(); } - private String getSourceString() { + private @Nullable String getSourceString() { if (this.source != null) { try { StringResult result = new StringResult(); diff --git a/spring-ws-test/src/main/java/org/springframework/ws/test/support/creator/package-info.java b/spring-ws-test/src/main/java/org/springframework/ws/test/support/creator/package-info.java index c61ce908..8085a85f 100644 --- a/spring-ws-test/src/main/java/org/springframework/ws/test/support/creator/package-info.java +++ b/spring-ws-test/src/main/java/org/springframework/ws/test/support/creator/package-info.java @@ -19,4 +19,7 @@ * {@link org.springframework.ws.test.support.creator.WebServiceMessageCreator * WebServiceMessageCreator} interface, and implementations. */ +@NullMarked package org.springframework.ws.test.support.creator; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-test/src/main/java/org/springframework/ws/test/support/matcher/SchemaValidatingMatcher.java b/spring-ws-test/src/main/java/org/springframework/ws/test/support/matcher/SchemaValidatingMatcher.java index 0e849f58..b293a810 100644 --- a/spring-ws-test/src/main/java/org/springframework/ws/test/support/matcher/SchemaValidatingMatcher.java +++ b/spring-ws-test/src/main/java/org/springframework/ws/test/support/matcher/SchemaValidatingMatcher.java @@ -18,6 +18,7 @@ package org.springframework.ws.test.support.matcher; import java.io.IOException; import java.util.Arrays; +import java.util.Objects; import org.xml.sax.SAXParseException; @@ -57,7 +58,7 @@ public class SchemaValidatingMatcher implements WebServiceMessageMatcher { @Override public void match(WebServiceMessage message) throws IOException, AssertionError { - SAXParseException[] exceptions = this.xmlValidator.validate(message.getPayloadSource()); + SAXParseException[] exceptions = this.xmlValidator.validate(Objects.requireNonNull(message.getPayloadSource())); if (!ObjectUtils.isEmpty(exceptions)) { AssertionErrors.fail("XML is not valid: " + Arrays.toString(exceptions), "Payload", message.getPayloadSource()); diff --git a/spring-ws-test/src/main/java/org/springframework/ws/test/support/matcher/SoapHeaderMatcher.java b/spring-ws-test/src/main/java/org/springframework/ws/test/support/matcher/SoapHeaderMatcher.java index 87b1152b..6f837f41 100644 --- a/spring-ws-test/src/main/java/org/springframework/ws/test/support/matcher/SoapHeaderMatcher.java +++ b/spring-ws-test/src/main/java/org/springframework/ws/test/support/matcher/SoapHeaderMatcher.java @@ -53,13 +53,15 @@ public class SoapHeaderMatcher extends AbstractSoapMessageMatcher { AssertionErrors.assertTrue("SOAP message [" + soapMessage + "] does not contain SOAP header", soapHeader != null, "Envelope", soapMessage.getEnvelope().getSource()); - Iterator soapHeaderElementIterator = soapHeader.examineAllHeaderElements(); boolean found = false; - while (soapHeaderElementIterator.hasNext()) { - SoapHeaderElement soapHeaderElement = soapHeaderElementIterator.next(); - if (this.soapHeaderName.equals(soapHeaderElement.getName())) { - found = true; - break; + if (soapHeader != null) { + Iterator soapHeaderElementIterator = soapHeader.examineAllHeaderElements(); + while (soapHeaderElementIterator.hasNext()) { + SoapHeaderElement soapHeaderElement = soapHeaderElementIterator.next(); + if (this.soapHeaderName.equals(soapHeaderElement.getName())) { + found = true; + break; + } } } AssertionErrors.assertTrue("SOAP header [" + this.soapHeaderName + "] not found", found, "Envelope", diff --git a/spring-ws-test/src/main/java/org/springframework/ws/test/support/matcher/XPathExpectationsHelper.java b/spring-ws-test/src/main/java/org/springframework/ws/test/support/matcher/XPathExpectationsHelper.java index 3ffbc9ad..e438466f 100644 --- a/spring-ws-test/src/main/java/org/springframework/ws/test/support/matcher/XPathExpectationsHelper.java +++ b/spring-ws-test/src/main/java/org/springframework/ws/test/support/matcher/XPathExpectationsHelper.java @@ -18,10 +18,12 @@ package org.springframework.ws.test.support.matcher; import java.io.IOException; import java.util.Map; +import java.util.Objects; import javax.xml.transform.TransformerException; import javax.xml.transform.dom.DOMResult; +import org.jspecify.annotations.Nullable; import org.w3c.dom.Node; import org.springframework.util.Assert; @@ -61,7 +63,7 @@ public class XPathExpectationsHelper { * @param expression the XPath expression * @param namespaces the namespaces, can be empty or {@code null} */ - public XPathExpectationsHelper(String expression, Map namespaces) { + public XPathExpectationsHelper(String expression, @Nullable Map namespaces) { Assert.hasLength(expression, "'expression' must not be empty"); this.expression = XPathExpressionFactory.createXPathExpression(expression, namespaces); this.expressionString = expression; @@ -139,12 +141,11 @@ public class XPathExpectationsHelper { private Node transformToNode(WebServiceMessage request) { DOMResult domResult = new DOMResult(); try { - this.transformerHelper.transform(request.getPayloadSource(), domResult); + this.transformerHelper.transform(Objects.requireNonNull(request.getPayloadSource()), domResult); return domResult.getNode(); } catch (TransformerException ex) { - AssertionErrors.fail("Could not transform request payload: " + ex.getMessage()); - return null; + throw new AssertionError("Could not transform request payload: " + ex.getMessage()); } } diff --git a/spring-ws-test/src/main/java/org/springframework/ws/test/support/matcher/package-info.java b/spring-ws-test/src/main/java/org/springframework/ws/test/support/matcher/package-info.java index 4183720b..46f4fa57 100644 --- a/spring-ws-test/src/main/java/org/springframework/ws/test/support/matcher/package-info.java +++ b/spring-ws-test/src/main/java/org/springframework/ws/test/support/matcher/package-info.java @@ -19,4 +19,7 @@ * {@link org.springframework.ws.test.support.matcher.WebServiceMessageMatcher * WebServiceMessageMatcher} interface, and implementations. */ +@NullMarked package org.springframework.ws.test.support.matcher; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-test/src/main/java/org/springframework/ws/test/support/matcher/xmlunit/PayloadDiffMatcher.java b/spring-ws-test/src/main/java/org/springframework/ws/test/support/matcher/xmlunit/PayloadDiffMatcher.java index b55f6751..e1f32de5 100644 --- a/spring-ws-test/src/main/java/org/springframework/ws/test/support/matcher/xmlunit/PayloadDiffMatcher.java +++ b/spring-ws-test/src/main/java/org/springframework/ws/test/support/matcher/xmlunit/PayloadDiffMatcher.java @@ -85,8 +85,7 @@ public class PayloadDiffMatcher extends DiffMatcher { return (Document) result.getNode(); } catch (TransformerException ex) { - AssertionErrors.fail("Could not transform source to DOMResult" + ex.getMessage()); - return null; + throw new AssertionError("Could not transform source to DOMResult" + ex.getMessage()); } } diff --git a/spring-ws-test/src/main/java/org/springframework/ws/test/support/matcher/xmlunit/SoapEnvelopeDiffMatcher.java b/spring-ws-test/src/main/java/org/springframework/ws/test/support/matcher/xmlunit/SoapEnvelopeDiffMatcher.java index a788ac0d..ff29f8bd 100644 --- a/spring-ws-test/src/main/java/org/springframework/ws/test/support/matcher/xmlunit/SoapEnvelopeDiffMatcher.java +++ b/spring-ws-test/src/main/java/org/springframework/ws/test/support/matcher/xmlunit/SoapEnvelopeDiffMatcher.java @@ -75,8 +75,7 @@ public class SoapEnvelopeDiffMatcher extends AbstractSoapMessageMatcher { return (Document) result.getNode(); } catch (TransformerException ex) { - AssertionErrors.fail("Could not transform source to DOMResult" + ex.getMessage()); - return null; + throw new AssertionError("Could not transform source to DOMResult" + ex.getMessage()); } } diff --git a/spring-ws-test/src/main/java/org/springframework/ws/test/support/matcher/xmlunit/package-info.java b/spring-ws-test/src/main/java/org/springframework/ws/test/support/matcher/xmlunit/package-info.java index df976cbd..ba1f087f 100644 --- a/spring-ws-test/src/main/java/org/springframework/ws/test/support/matcher/xmlunit/package-info.java +++ b/spring-ws-test/src/main/java/org/springframework/ws/test/support/matcher/xmlunit/package-info.java @@ -17,4 +17,7 @@ /** * Matcher support for XMLUnit. */ +@NullMarked package org.springframework.ws.test.support.matcher.xmlunit; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-test/src/main/java/org/springframework/ws/test/support/package-info.java b/spring-ws-test/src/main/java/org/springframework/ws/test/support/package-info.java index 73000dcf..c886c337 100644 --- a/spring-ws-test/src/main/java/org/springframework/ws/test/support/package-info.java +++ b/spring-ws-test/src/main/java/org/springframework/ws/test/support/package-info.java @@ -19,4 +19,7 @@ * {@link org.springframework.ws.test.client} and * {@link org.springframework.ws.test.server} packages. */ +@NullMarked package org.springframework.ws.test.support; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-ws-test/src/test/java/org/springframework/ws/test/client/ErrorResponseCreatorTests.java b/spring-ws-test/src/test/java/org/springframework/ws/test/client/ErrorResponseCreatorTests.java deleted file mode 100644 index 5c7e3d3f..00000000 --- a/spring-ws-test/src/test/java/org/springframework/ws/test/client/ErrorResponseCreatorTests.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2005-2025 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.ws.test.client; - -import java.io.IOException; - -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -class ErrorResponseCreatorTests { - - @Test - void callback() throws IOException { - - String errorMessage = "Error message"; - ErrorResponseCreator callback = new ErrorResponseCreator(errorMessage); - callback.createResponse(null, null, null); - - assertThat(callback.getErrorMessage()).isEqualTo(errorMessage); - } - -} diff --git a/spring-xml/src/main/java/org/springframework/xml/XmlException.java b/spring-xml/src/main/java/org/springframework/xml/XmlException.java index 690d38eb..5c700859 100644 --- a/spring-xml/src/main/java/org/springframework/xml/XmlException.java +++ b/spring-xml/src/main/java/org/springframework/xml/XmlException.java @@ -16,6 +16,8 @@ package org.springframework.xml; +import org.jspecify.annotations.Nullable; + import org.springframework.core.NestedRuntimeException; /** @@ -42,7 +44,7 @@ public abstract class XmlException extends NestedRuntimeException { * @param message the detail message * @param throwable the wrapped exception */ - protected XmlException(String message, Throwable throwable) { + protected XmlException(@Nullable String message, Throwable throwable) { super(message, throwable); } diff --git a/spring-xml/src/main/java/org/springframework/xml/dom/package-info.java b/spring-xml/src/main/java/org/springframework/xml/dom/package-info.java index 458bd77f..7889a702 100644 --- a/spring-xml/src/main/java/org/springframework/xml/dom/package-info.java +++ b/spring-xml/src/main/java/org/springframework/xml/dom/package-info.java @@ -18,4 +18,7 @@ * Provides classes that help with DOM: the Document Object Model. Mostly for internal use * by the framework. */ +@NullMarked package org.springframework.xml.dom; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-xml/src/main/java/org/springframework/xml/namespace/QNameUtils.java b/spring-xml/src/main/java/org/springframework/xml/namespace/QNameUtils.java index 46bb78a6..71cc2dfe 100644 --- a/spring-xml/src/main/java/org/springframework/xml/namespace/QNameUtils.java +++ b/spring-xml/src/main/java/org/springframework/xml/namespace/QNameUtils.java @@ -18,6 +18,7 @@ package org.springframework.xml.namespace; import javax.xml.namespace.QName; +import org.jspecify.annotations.Nullable; import org.w3c.dom.Node; import org.springframework.util.Assert; @@ -37,7 +38,7 @@ public abstract class QNameUtils { * @param text the qualified name * @return {@code true} if valid, {@code false} otherwise */ - public static boolean validateQName(String text) { + public static boolean validateQName(@Nullable String text) { if (!StringUtils.hasLength(text)) { return false; } diff --git a/spring-xml/src/main/java/org/springframework/xml/namespace/SimpleNamespaceContext.java b/spring-xml/src/main/java/org/springframework/xml/namespace/SimpleNamespaceContext.java index 11bfd279..1965e2d3 100644 --- a/spring-xml/src/main/java/org/springframework/xml/namespace/SimpleNamespaceContext.java +++ b/spring-xml/src/main/java/org/springframework/xml/namespace/SimpleNamespaceContext.java @@ -27,6 +27,8 @@ import java.util.Set; import javax.xml.XMLConstants; import javax.xml.namespace.NamespaceContext; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; /** @@ -59,7 +61,7 @@ public class SimpleNamespaceContext implements NamespaceContext { } @Override - public String getPrefix(String namespaceUri) { + public @Nullable String getPrefix(String namespaceUri) { Iterator iterator = getPrefixes(namespaceUri); return iterator.hasNext() ? iterator.next() : null; } diff --git a/spring-xml/src/main/java/org/springframework/xml/namespace/package-info.java b/spring-xml/src/main/java/org/springframework/xml/namespace/package-info.java index 9a4a8d72..3469c9f1 100644 --- a/spring-xml/src/main/java/org/springframework/xml/namespace/package-info.java +++ b/spring-xml/src/main/java/org/springframework/xml/namespace/package-info.java @@ -18,4 +18,7 @@ * Provides classes that help with XML Namespace processing. Mostly for internal use by * the framework. */ +@NullMarked package org.springframework.xml.namespace; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-xml/src/main/java/org/springframework/xml/package-info.java b/spring-xml/src/main/java/org/springframework/xml/package-info.java index 86c03b43..b26411d7 100644 --- a/spring-xml/src/main/java/org/springframework/xml/package-info.java +++ b/spring-xml/src/main/java/org/springframework/xml/package-info.java @@ -18,4 +18,7 @@ * Provides classes for XML handling: version detection and a base XML exception class. * Mostly for internal use by the framework. */ +@NullMarked package org.springframework.xml; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-xml/src/main/java/org/springframework/xml/sax/AbstractXmlReader.java b/spring-xml/src/main/java/org/springframework/xml/sax/AbstractXmlReader.java index f2d33282..32fd32ff 100644 --- a/spring-xml/src/main/java/org/springframework/xml/sax/AbstractXmlReader.java +++ b/spring-xml/src/main/java/org/springframework/xml/sax/AbstractXmlReader.java @@ -16,6 +16,7 @@ package org.springframework.xml.sax; +import org.jspecify.annotations.Nullable; import org.xml.sax.ContentHandler; import org.xml.sax.DTDHandler; import org.xml.sax.EntityResolver; @@ -38,18 +39,18 @@ import org.xml.sax.ext.LexicalHandler; */ public abstract class AbstractXmlReader implements XMLReader { - private DTDHandler dtdHandler; + private @Nullable DTDHandler dtdHandler; - private ContentHandler contentHandler; + private @Nullable ContentHandler contentHandler; - private EntityResolver entityResolver; + private @Nullable EntityResolver entityResolver; - private ErrorHandler errorHandler; + private @Nullable ErrorHandler errorHandler; - private LexicalHandler lexicalHandler; + private @Nullable LexicalHandler lexicalHandler; @Override - public ContentHandler getContentHandler() { + public @Nullable ContentHandler getContentHandler() { return this.contentHandler; } @@ -64,12 +65,12 @@ public abstract class AbstractXmlReader implements XMLReader { } @Override - public DTDHandler getDTDHandler() { + public @Nullable DTDHandler getDTDHandler() { return this.dtdHandler; } @Override - public EntityResolver getEntityResolver() { + public @Nullable EntityResolver getEntityResolver() { return this.entityResolver; } @@ -79,7 +80,7 @@ public abstract class AbstractXmlReader implements XMLReader { } @Override - public ErrorHandler getErrorHandler() { + public @Nullable ErrorHandler getErrorHandler() { return this.errorHandler; } @@ -88,7 +89,7 @@ public abstract class AbstractXmlReader implements XMLReader { this.errorHandler = errorHandler; } - protected LexicalHandler getLexicalHandler() { + protected @Nullable LexicalHandler getLexicalHandler() { return this.lexicalHandler; } @@ -116,7 +117,7 @@ public abstract class AbstractXmlReader implements XMLReader { * {@code http://xml.org/sax/properties/lexical-handler}. */ @Override - public Object getProperty(String name) throws SAXNotRecognizedException, SAXNotSupportedException { + public @Nullable Object getProperty(String name) throws SAXNotRecognizedException, SAXNotSupportedException { if ("http://xml.org/sax/properties/lexical-handler".equals(name)) { return this.lexicalHandler; } diff --git a/spring-xml/src/main/java/org/springframework/xml/sax/SaxUtils.java b/spring-xml/src/main/java/org/springframework/xml/sax/SaxUtils.java index 09e9feca..67b90d20 100644 --- a/spring-xml/src/main/java/org/springframework/xml/sax/SaxUtils.java +++ b/spring-xml/src/main/java/org/springframework/xml/sax/SaxUtils.java @@ -25,6 +25,7 @@ import javax.xml.parsers.SAXParserFactory; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; @@ -76,7 +77,7 @@ public abstract class SaxUtils { * Retrieves the URL from the given resource as System ID. Returns {@code null} if it * cannot be opened. */ - public static String getSystemId(Resource resource) { + public static @Nullable String getSystemId(Resource resource) { try { return new URI(resource.getURL().toExternalForm()).toString(); } diff --git a/spring-xml/src/main/java/org/springframework/xml/sax/package-info.java b/spring-xml/src/main/java/org/springframework/xml/sax/package-info.java index d9b72eb2..727f74c4 100644 --- a/spring-xml/src/main/java/org/springframework/xml/sax/package-info.java +++ b/spring-xml/src/main/java/org/springframework/xml/sax/package-info.java @@ -18,4 +18,7 @@ * Provides classes that help with SAX: the Simple API for XML. Mostly for internal use by * the framework. */ +@NullMarked package org.springframework.xml.sax; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-xml/src/main/java/org/springframework/xml/transform/StringSource.java b/spring-xml/src/main/java/org/springframework/xml/transform/StringSource.java index e2719253..ab72b23d 100644 --- a/spring-xml/src/main/java/org/springframework/xml/transform/StringSource.java +++ b/spring-xml/src/main/java/org/springframework/xml/transform/StringSource.java @@ -22,6 +22,8 @@ import java.io.StringReader; import javax.xml.transform.stream.StreamSource; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; /** @@ -64,7 +66,7 @@ public class StringSource extends StreamSource { * @return {@code null} */ @Override - public InputStream getInputStream() { + public @Nullable InputStream getInputStream() { return null; } diff --git a/spring-xml/src/main/java/org/springframework/xml/transform/TransformerHelper.java b/spring-xml/src/main/java/org/springframework/xml/transform/TransformerHelper.java index 2d5b2fa9..3455224d 100644 --- a/spring-xml/src/main/java/org/springframework/xml/transform/TransformerHelper.java +++ b/spring-xml/src/main/java/org/springframework/xml/transform/TransformerHelper.java @@ -23,6 +23,8 @@ import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; /** @@ -34,9 +36,9 @@ import org.springframework.util.Assert; */ public class TransformerHelper { - private volatile TransformerFactory transformerFactory; + private volatile @Nullable TransformerFactory transformerFactory; - private Class transformerFactoryClass; + private @Nullable Class transformerFactoryClass; /** * Initializes a new instance of the {@code TransformerHelper}. @@ -81,7 +83,8 @@ public class TransformerHelper { * @see #setTransformerFactoryClass * @see #getTransformerFactory() */ - protected TransformerFactory newTransformerFactory(Class transformerFactoryClass) { + protected TransformerFactory newTransformerFactory( + @Nullable Class transformerFactoryClass) { if (transformerFactoryClass != null) { return TransformerFactoryUtils.newInstance(transformerFactoryClass); } diff --git a/spring-xml/src/main/java/org/springframework/xml/transform/TraxUtils.java b/spring-xml/src/main/java/org/springframework/xml/transform/TraxUtils.java index fd5f2bf5..dba4ef64 100644 --- a/spring-xml/src/main/java/org/springframework/xml/transform/TraxUtils.java +++ b/spring-xml/src/main/java/org/springframework/xml/transform/TraxUtils.java @@ -36,6 +36,7 @@ import javax.xml.transform.stax.StAXSource; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; +import org.jspecify.annotations.Nullable; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.xml.sax.ContentHandler; @@ -59,7 +60,7 @@ public abstract class TraxUtils { * @param source the DOM source * @return the document */ - public static Document getDocument(DOMSource source) { + public static @Nullable Document getDocument(DOMSource source) { Node node = source.getNode(); if (node instanceof Document) { return (Document) node; diff --git a/spring-xml/src/main/java/org/springframework/xml/transform/package-info.java b/spring-xml/src/main/java/org/springframework/xml/transform/package-info.java index b0233ae5..d723aae0 100644 --- a/spring-xml/src/main/java/org/springframework/xml/transform/package-info.java +++ b/spring-xml/src/main/java/org/springframework/xml/transform/package-info.java @@ -18,4 +18,7 @@ * Provides classes that help with XML transformations. Mostly for internal use by the * framework. */ +@NullMarked package org.springframework.xml.transform; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-xml/src/main/java/org/springframework/xml/validation/Jaxp13ValidatorFactory.java b/spring-xml/src/main/java/org/springframework/xml/validation/Jaxp13ValidatorFactory.java index aedf9320..9379c68f 100644 --- a/spring-xml/src/main/java/org/springframework/xml/validation/Jaxp13ValidatorFactory.java +++ b/spring-xml/src/main/java/org/springframework/xml/validation/Jaxp13ValidatorFactory.java @@ -24,6 +24,7 @@ import javax.xml.transform.Source; import javax.xml.validation.Schema; import javax.xml.validation.Validator; +import org.jspecify.annotations.Nullable; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; @@ -62,7 +63,8 @@ abstract class Jaxp13ValidatorFactory { } @Override - public SAXParseException[] validate(Source source, ValidationErrorHandler errorHandler) throws IOException { + public SAXParseException[] validate(Source source, @Nullable ValidationErrorHandler errorHandler) + throws IOException { if (errorHandler == null) { errorHandler = new DefaultValidationErrorHandler(); } diff --git a/spring-xml/src/main/java/org/springframework/xml/validation/Jaxp15ValidatorFactory.java b/spring-xml/src/main/java/org/springframework/xml/validation/Jaxp15ValidatorFactory.java index 29ffb2b1..fdcec4ce 100644 --- a/spring-xml/src/main/java/org/springframework/xml/validation/Jaxp15ValidatorFactory.java +++ b/spring-xml/src/main/java/org/springframework/xml/validation/Jaxp15ValidatorFactory.java @@ -27,6 +27,7 @@ import javax.xml.validation.Validator; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.xml.sax.SAXException; import org.xml.sax.SAXNotRecognizedException; import org.xml.sax.SAXNotSupportedException; @@ -70,7 +71,8 @@ abstract class Jaxp15ValidatorFactory { } @Override - public SAXParseException[] validate(Source source, ValidationErrorHandler errorHandler) throws IOException { + public SAXParseException[] validate(Source source, @Nullable ValidationErrorHandler errorHandler) + throws IOException { if (errorHandler == null) { errorHandler = new DefaultValidationErrorHandler(); } diff --git a/spring-xml/src/main/java/org/springframework/xml/validation/SchemaLoaderUtils.java b/spring-xml/src/main/java/org/springframework/xml/validation/SchemaLoaderUtils.java index 1955bed7..b732e93d 100644 --- a/spring-xml/src/main/java/org/springframework/xml/validation/SchemaLoaderUtils.java +++ b/spring-xml/src/main/java/org/springframework/xml/validation/SchemaLoaderUtils.java @@ -22,6 +22,7 @@ import javax.xml.transform.Source; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; +import org.jspecify.annotations.Nullable; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; @@ -91,7 +92,7 @@ public abstract class SchemaLoaderUtils { * Retrieves the URL from the given resource as System ID. Returns {@code null} if it * cannot be opened. */ - public static String getSystemId(Resource resource) { + public static @Nullable String getSystemId(Resource resource) { try { return resource.getURL().toString(); } diff --git a/spring-xml/src/main/java/org/springframework/xml/validation/XmlValidator.java b/spring-xml/src/main/java/org/springframework/xml/validation/XmlValidator.java index 6ec5b07b..ce0531d2 100644 --- a/spring-xml/src/main/java/org/springframework/xml/validation/XmlValidator.java +++ b/spring-xml/src/main/java/org/springframework/xml/validation/XmlValidator.java @@ -20,6 +20,7 @@ import java.io.IOException; import javax.xml.transform.Source; +import org.jspecify.annotations.Nullable; import org.xml.sax.SAXParseException; /** @@ -56,6 +57,6 @@ public interface XmlValidator { * @throws IOException if the {@code source} cannot be read * @throws XmlValidationException if the {@code source} cannot be validated */ - SAXParseException[] validate(Source source, ValidationErrorHandler errorHandler) throws IOException; + SAXParseException[] validate(Source source, @Nullable ValidationErrorHandler errorHandler) throws IOException; } diff --git a/spring-xml/src/main/java/org/springframework/xml/validation/package-info.java b/spring-xml/src/main/java/org/springframework/xml/validation/package-info.java index ea3da014..f6bfbd00 100644 --- a/spring-xml/src/main/java/org/springframework/xml/validation/package-info.java +++ b/spring-xml/src/main/java/org/springframework/xml/validation/package-info.java @@ -18,4 +18,7 @@ * Provides classes for XML validation in JAXP 1.0 and JAXP 1.3. Mostly for internal use * by the framework. */ +@NullMarked package org.springframework.xml.validation; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-xml/src/main/java/org/springframework/xml/xpath/AbstractXPathTemplate.java b/spring-xml/src/main/java/org/springframework/xml/xpath/AbstractXPathTemplate.java index 2146dd22..75d5c1a6 100644 --- a/spring-xml/src/main/java/org/springframework/xml/xpath/AbstractXPathTemplate.java +++ b/spring-xml/src/main/java/org/springframework/xml/xpath/AbstractXPathTemplate.java @@ -16,12 +16,14 @@ package org.springframework.xml.xpath; +import java.util.Collections; import java.util.Map; import javax.xml.transform.Source; import javax.xml.transform.TransformerException; import javax.xml.transform.dom.DOMResult; +import org.jspecify.annotations.Nullable; import org.w3c.dom.DOMException; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -38,7 +40,7 @@ import org.springframework.xml.transform.TransformerObjectSupport; */ public abstract class AbstractXPathTemplate extends TransformerObjectSupport implements XPathOperations { - private Map namespaces; + private Map namespaces = Collections.emptyMap(); /** Returns namespaces used in the XPath expression. */ public Map getNamespaces() { @@ -81,7 +83,7 @@ public abstract class AbstractXPathTemplate extends TransformerObjectSupport imp } @Override - public Object mapNode(Node node, int nodeNum) throws DOMException { + public @Nullable Object mapNode(Node node, int nodeNum) throws DOMException { this.callbackHandler.processNode(node); return null; } diff --git a/spring-xml/src/main/java/org/springframework/xml/xpath/JaxenXPathExpressionFactory.java b/spring-xml/src/main/java/org/springframework/xml/xpath/JaxenXPathExpressionFactory.java index d2d1c344..a3983ec0 100644 --- a/spring-xml/src/main/java/org/springframework/xml/xpath/JaxenXPathExpressionFactory.java +++ b/spring-xml/src/main/java/org/springframework/xml/xpath/JaxenXPathExpressionFactory.java @@ -24,6 +24,7 @@ import org.jaxen.JaxenException; import org.jaxen.SimpleNamespaceContext; import org.jaxen.XPath; import org.jaxen.dom.DOMXPath; +import org.jspecify.annotations.Nullable; import org.w3c.dom.DOMException; import org.w3c.dom.Node; @@ -92,7 +93,7 @@ abstract class JaxenXPathExpressionFactory { } @Override - public Node evaluateAsNode(Node node) { + public @Nullable Node evaluateAsNode(Node node) { try { return (Node) this.xpath.selectSingleNode(node); } @@ -125,7 +126,7 @@ abstract class JaxenXPathExpressionFactory { } @Override - public String evaluateAsString(Node node) { + public @Nullable String evaluateAsString(Node node) { try { return this.xpath.stringValueOf(node); } @@ -148,7 +149,7 @@ abstract class JaxenXPathExpressionFactory { } @Override - public T evaluateAsObject(Node context, NodeMapper nodeMapper) throws XPathException { + public @Nullable T evaluateAsObject(Node context, NodeMapper nodeMapper) throws XPathException { try { Node result = (Node) this.xpath.selectSingleNode(context); if (result != null) { diff --git a/spring-xml/src/main/java/org/springframework/xml/xpath/JaxenXPathTemplate.java b/spring-xml/src/main/java/org/springframework/xml/xpath/JaxenXPathTemplate.java index e9c13660..b9fceb45 100644 --- a/spring-xml/src/main/java/org/springframework/xml/xpath/JaxenXPathTemplate.java +++ b/spring-xml/src/main/java/org/springframework/xml/xpath/JaxenXPathTemplate.java @@ -18,6 +18,7 @@ package org.springframework.xml.xpath; import java.util.ArrayList; import java.util.List; +import java.util.Map; import javax.xml.transform.Source; import javax.xml.transform.TransformerException; @@ -26,6 +27,7 @@ import org.jaxen.JaxenException; import org.jaxen.SimpleNamespaceContext; import org.jaxen.XPath; import org.jaxen.dom.DOMXPath; +import org.jspecify.annotations.Nullable; import org.w3c.dom.DOMException; import org.w3c.dom.Element; import org.w3c.dom.Node; @@ -118,7 +120,8 @@ public class JaxenXPathTemplate extends AbstractXPathTemplate { } @Override - public T evaluateAsObject(String expression, Source context, NodeMapper nodeMapper) throws XPathException { + public @Nullable T evaluateAsObject(String expression, Source context, NodeMapper nodeMapper) + throws XPathException { try { XPath xpath = createXPath(expression); Element element = getRootElement(context); @@ -172,8 +175,9 @@ public class JaxenXPathTemplate extends AbstractXPathTemplate { private XPath createXPath(String expression) throws JaxenException { XPath xpath = new DOMXPath(expression); - if (getNamespaces() != null && !getNamespaces().isEmpty()) { - xpath.setNamespaceContext(new SimpleNamespaceContext(getNamespaces())); + Map namespaces = getNamespaces(); + if (!namespaces.isEmpty()) { + xpath.setNamespaceContext(new SimpleNamespaceContext(namespaces)); } return xpath; } diff --git a/spring-xml/src/main/java/org/springframework/xml/xpath/Jaxp13XPathExpressionFactory.java b/spring-xml/src/main/java/org/springframework/xml/xpath/Jaxp13XPathExpressionFactory.java index af0ee90c..f9b26210 100644 --- a/spring-xml/src/main/java/org/springframework/xml/xpath/Jaxp13XPathExpressionFactory.java +++ b/spring-xml/src/main/java/org/springframework/xml/xpath/Jaxp13XPathExpressionFactory.java @@ -26,6 +26,7 @@ import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; +import org.jspecify.annotations.Nullable; import org.w3c.dom.DOMException; import org.w3c.dom.Node; import org.w3c.dom.NodeList; @@ -153,18 +154,13 @@ abstract class Jaxp13XPathExpressionFactory { } @Override - public T evaluateAsObject(Node node, NodeMapper nodeMapper) throws XPathException { + public @Nullable T evaluateAsObject(Node node, NodeMapper nodeMapper) throws XPathException { Node result = (Node) evaluate(node, XPathConstants.NODE); - if (result != null) { - try { - return nodeMapper.mapNode(result, 0); - } - catch (DOMException ex) { - throw new XPathException("Mapping resulted in DOMException", ex); - } + try { + return nodeMapper.mapNode(result, 0); } - else { - return null; + catch (DOMException ex) { + throw new XPathException("Mapping resulted in DOMException", ex); } } diff --git a/spring-xml/src/main/java/org/springframework/xml/xpath/Jaxp13XPathTemplate.java b/spring-xml/src/main/java/org/springframework/xml/xpath/Jaxp13XPathTemplate.java index 8299082a..46fa7f65 100644 --- a/spring-xml/src/main/java/org/springframework/xml/xpath/Jaxp13XPathTemplate.java +++ b/spring-xml/src/main/java/org/springframework/xml/xpath/Jaxp13XPathTemplate.java @@ -20,6 +20,7 @@ import java.io.InputStream; import java.io.Reader; import java.util.ArrayList; import java.util.List; +import java.util.Map; import javax.xml.namespace.QName; import javax.xml.stream.XMLEventReader; @@ -34,6 +35,7 @@ import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import javax.xml.xpath.XPathFactoryConfigurationException; +import org.jspecify.annotations.Nullable; import org.w3c.dom.DOMException; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -81,16 +83,18 @@ public class Jaxp13XPathTemplate extends AbstractXPathTemplate { } @Override - public Node evaluateAsNode(String expression, Source context) throws XPathException { + public @Nullable Node evaluateAsNode(String expression, Source context) throws XPathException { return (Node) evaluate(expression, context, XPathConstants.NODE); } @Override public List evaluateAsNodeList(String expression, Source context) throws XPathException { NodeList result = (NodeList) evaluate(expression, context, XPathConstants.NODESET); - List nodes = new ArrayList<>(result.getLength()); - for (int i = 0; i < result.getLength(); i++) { - nodes.add(result.item(i)); + List nodes = new ArrayList<>(); + if (result != null) { + for (int i = 0; i < result.getLength(); i++) { + nodes.add(result.item(i)); + } } return nodes; } @@ -102,46 +106,45 @@ public class Jaxp13XPathTemplate extends AbstractXPathTemplate { } @Override - public String evaluateAsString(String expression, Source context) throws XPathException { + public @Nullable String evaluateAsString(String expression, Source context) throws XPathException { return (String) evaluate(expression, context, XPathConstants.STRING); } @Override - public T evaluateAsObject(String expression, Source context, NodeMapper nodeMapper) throws XPathException { + public @Nullable T evaluateAsObject(String expression, Source context, NodeMapper nodeMapper) + throws XPathException { Node node = evaluateAsNode(expression, context); - if (node != null) { - try { - return nodeMapper.mapNode(node, 0); - } - catch (DOMException ex) { - throw new XPathException("Mapping resulted in DOMException", ex); - } + try { + return (node != null) ? nodeMapper.mapNode(node, 0) : null; } - else { - return null; + catch (DOMException ex) { + throw new XPathException("Mapping resulted in DOMException", ex); } } @Override public List evaluate(String expression, Source context, NodeMapper nodeMapper) throws XPathException { NodeList nodes = (NodeList) evaluate(expression, context, XPathConstants.NODESET); - List results = new ArrayList<>(nodes.getLength()); - for (int i = 0; i < nodes.getLength(); i++) { - try { - results.add(nodeMapper.mapNode(nodes.item(i), i)); - } - catch (DOMException ex) { - throw new XPathException("Mapping resulted in DOMException", ex); + List results = new ArrayList<>(); + if (nodes != null) { + for (int i = 0; i < nodes.getLength(); i++) { + try { + results.add(nodeMapper.mapNode(nodes.item(i), i)); + } + catch (DOMException ex) { + throw new XPathException("Mapping resulted in DOMException", ex); + } } } return results; } - private Object evaluate(String expression, Source context, QName returnType) throws XPathException { + private @Nullable Object evaluate(String expression, Source context, QName returnType) throws XPathException { XPath xpath = createXPath(); - if (getNamespaces() != null && !getNamespaces().isEmpty()) { + Map namespaces = getNamespaces(); + if (!namespaces.isEmpty()) { SimpleNamespaceContext namespaceContext = new SimpleNamespaceContext(); - namespaceContext.setBindings(getNamespaces()); + namespaceContext.setBindings(namespaces); xpath.setNamespaceContext(namespaceContext); } try { @@ -174,7 +177,7 @@ public class Jaxp13XPathTemplate extends AbstractXPathTemplate { private final TransformerHelper transformerHelper = new TransformerHelper(); - private Object result; + private @Nullable Object result; private EvaluationCallback(XPath xpath, String expression, QName returnType) { this.xpath = xpath; diff --git a/spring-xml/src/main/java/org/springframework/xml/xpath/NodeMapper.java b/spring-xml/src/main/java/org/springframework/xml/xpath/NodeMapper.java index 46d01369..4a56864e 100644 --- a/spring-xml/src/main/java/org/springframework/xml/xpath/NodeMapper.java +++ b/spring-xml/src/main/java/org/springframework/xml/xpath/NodeMapper.java @@ -16,6 +16,7 @@ package org.springframework.xml.xpath; +import org.jspecify.annotations.Nullable; import org.w3c.dom.DOMException; import org.w3c.dom.Node; @@ -42,6 +43,6 @@ public interface NodeMapper { * @return object for the current node * @throws DOMException in case of DOM errors */ - T mapNode(Node node, int nodeNum) throws DOMException; + @Nullable T mapNode(Node node, int nodeNum) throws DOMException; } diff --git a/spring-xml/src/main/java/org/springframework/xml/xpath/XPathException.java b/spring-xml/src/main/java/org/springframework/xml/xpath/XPathException.java index c9e45a4c..e71d03b5 100644 --- a/spring-xml/src/main/java/org/springframework/xml/xpath/XPathException.java +++ b/spring-xml/src/main/java/org/springframework/xml/xpath/XPathException.java @@ -16,6 +16,8 @@ package org.springframework.xml.xpath; +import org.jspecify.annotations.Nullable; + import org.springframework.xml.XmlException; /** @@ -42,7 +44,7 @@ public class XPathException extends XmlException { * @param message the detail message * @param throwable the wrapped exception */ - public XPathException(String message, Throwable throwable) { + public XPathException(@Nullable String message, Throwable throwable) { super(message, throwable); } diff --git a/spring-xml/src/main/java/org/springframework/xml/xpath/XPathExpression.java b/spring-xml/src/main/java/org/springframework/xml/xpath/XPathExpression.java index cd4babfa..61f199f5 100644 --- a/spring-xml/src/main/java/org/springframework/xml/xpath/XPathExpression.java +++ b/spring-xml/src/main/java/org/springframework/xml/xpath/XPathExpression.java @@ -18,6 +18,7 @@ package org.springframework.xml.xpath; import java.util.List; +import org.jspecify.annotations.Nullable; import org.w3c.dom.Node; /** @@ -58,7 +59,7 @@ public interface XPathExpression { * @throws XPathException in case of XPath errors * @see XPath specification */ - Node evaluateAsNode(Node node) throws XPathException; + @Nullable Node evaluateAsNode(Node node) throws XPathException; /** * Evaluates the given expression, and returns all {@link Node} objects that conform @@ -98,7 +99,7 @@ public interface XPathExpression { * @see XPath specification - * string() function */ - String evaluateAsString(Node node) throws XPathException; + @Nullable String evaluateAsString(Node node) throws XPathException; /** * Evaluates the given expression, mapping a single {@link Node} result to a Java @@ -109,7 +110,7 @@ public interface XPathExpression { * @throws XPathException in case of XPath errors * @see XPath specification */ - T evaluateAsObject(Node node, NodeMapper nodeMapper) throws XPathException; + @Nullable T evaluateAsObject(Node node, NodeMapper nodeMapper) throws XPathException; /** * Evaluates the given expression, mapping each result {@link Node} objects to a Java diff --git a/spring-xml/src/main/java/org/springframework/xml/xpath/XPathExpressionFactory.java b/spring-xml/src/main/java/org/springframework/xml/xpath/XPathExpressionFactory.java index 45c67420..ff2737a1 100644 --- a/spring-xml/src/main/java/org/springframework/xml/xpath/XPathExpressionFactory.java +++ b/spring-xml/src/main/java/org/springframework/xml/xpath/XPathExpressionFactory.java @@ -21,6 +21,7 @@ import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.util.Assert; @@ -61,7 +62,7 @@ public abstract class XPathExpressionFactory { * @throws IllegalStateException if neither JAXP 1.3+, or Jaxen are available * @throws XPathParseException if the given expression cannot be parsed */ - public static XPathExpression createXPathExpression(String expression, Map namespaces) + public static XPathExpression createXPathExpression(String expression, @Nullable Map namespaces) throws IllegalStateException, XPathParseException { Assert.hasLength(expression, "expression is empty"); if (namespaces == null) { diff --git a/spring-xml/src/main/java/org/springframework/xml/xpath/XPathExpressionFactoryBean.java b/spring-xml/src/main/java/org/springframework/xml/xpath/XPathExpressionFactoryBean.java index cf0f04eb..c407e0c2 100644 --- a/spring-xml/src/main/java/org/springframework/xml/xpath/XPathExpressionFactoryBean.java +++ b/spring-xml/src/main/java/org/springframework/xml/xpath/XPathExpressionFactoryBean.java @@ -36,10 +36,13 @@ import org.springframework.util.CollectionUtils; */ public class XPathExpressionFactoryBean implements FactoryBean, InitializingBean { + @SuppressWarnings("NullAway.Init") private Map namespaces; + @SuppressWarnings("NullAway.Init") private String expressionString; + @SuppressWarnings("NullAway.Init") private XPathExpression expression; /** Sets the XPath expression. Setting this property is required. */ diff --git a/spring-xml/src/main/java/org/springframework/xml/xpath/XPathOperations.java b/spring-xml/src/main/java/org/springframework/xml/xpath/XPathOperations.java index fec2f066..f6640a7b 100644 --- a/spring-xml/src/main/java/org/springframework/xml/xpath/XPathOperations.java +++ b/spring-xml/src/main/java/org/springframework/xml/xpath/XPathOperations.java @@ -20,6 +20,7 @@ import java.util.List; import javax.xml.transform.Source; +import org.jspecify.annotations.Nullable; import org.w3c.dom.Node; /** @@ -65,7 +66,7 @@ public interface XPathOperations { * @throws XPathException in case of XPath errors * @see XPath specification */ - Node evaluateAsNode(String expression, Source context) throws XPathException; + @Nullable Node evaluateAsNode(String expression, Source context) throws XPathException; /** * Evaluates the given expression as a list of {@link Node} objects. Returns the @@ -108,7 +109,7 @@ public interface XPathOperations { * @see XPath specification - * string() function */ - String evaluateAsString(String expression, Source context) throws XPathException; + @Nullable String evaluateAsString(String expression, Source context) throws XPathException; /** * Evaluates the given expression, mapping a single {@link Node} result to a Java @@ -120,7 +121,7 @@ public interface XPathOperations { * @throws XPathException in case of XPath errors * @see XPath specification */ - T evaluateAsObject(String expression, Source context, NodeMapper nodeMapper) throws XPathException; + @Nullable T evaluateAsObject(String expression, Source context, NodeMapper nodeMapper) throws XPathException; /** * Evaluates the given expression, mapping each result {@link Node} objects to a Java diff --git a/spring-xml/src/main/java/org/springframework/xml/xpath/package-info.java b/spring-xml/src/main/java/org/springframework/xml/xpath/package-info.java index 8114c57d..a1578538 100644 --- a/spring-xml/src/main/java/org/springframework/xml/xpath/package-info.java +++ b/spring-xml/src/main/java/org/springframework/xml/xpath/package-info.java @@ -18,4 +18,7 @@ * Provides XPathTemplate implementations, and various classes for XPath evaluation using * JAXP 1.3, and Jaxen. */ +@NullMarked package org.springframework.xml.xpath; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-xml/src/main/java/org/springframework/xml/xsd/SimpleXsdSchema.java b/spring-xml/src/main/java/org/springframework/xml/xsd/SimpleXsdSchema.java index 62b46cc7..ebad670e 100644 --- a/spring-xml/src/main/java/org/springframework/xml/xsd/SimpleXsdSchema.java +++ b/spring-xml/src/main/java/org/springframework/xml/xsd/SimpleXsdSchema.java @@ -24,6 +24,7 @@ import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.Source; +import org.jspecify.annotations.Nullable; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.SAXException; @@ -56,9 +57,9 @@ public class SimpleXsdSchema implements XsdSchema, InitializingBean { private static final QName SCHEMA_NAME = new QName(SCHEMA_NAMESPACE, "schema", "xsd"); - private Resource xsdResource; + private @Nullable Resource xsdResource; - private String targetNamespace; + private @Nullable String targetNamespace; static { documentBuilderFactory.setNamespaceAware(true); @@ -127,20 +128,21 @@ public class SimpleXsdSchema implements XsdSchema, InitializingBean { Assert.notNull(this.xsdResource, "'xsd' is required"); Assert.isTrue(this.xsdResource.exists(), "xsd '" + this.xsdResource + "' does not exist"); DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); - loadSchema(documentBuilder); + this.targetNamespace = loadSchema(documentBuilder, this.xsdResource); } - private void loadSchema(DocumentBuilder documentBuilder) throws SAXException, IOException { - Document schemaDocument = documentBuilder.parse(SaxUtils.createInputSource(this.xsdResource)); + private static String loadSchema(DocumentBuilder documentBuilder, Resource resource) + throws SAXException, IOException { + Document schemaDocument = documentBuilder.parse(SaxUtils.createInputSource(resource)); Element schemaElement = schemaDocument.getDocumentElement(); - Assert.isTrue(SCHEMA_NAME.getLocalPart().equals(schemaElement.getLocalName()), this.xsdResource - + " has invalid root element : [" + schemaElement.getLocalName() + "] instead of [schema]"); + Assert.isTrue(SCHEMA_NAME.getLocalPart().equals(schemaElement.getLocalName()), + resource + " has invalid root element : [" + schemaElement.getLocalName() + "] instead of [schema]"); Assert.isTrue(SCHEMA_NAME.getNamespaceURI().equals(schemaElement.getNamespaceURI()), - this.xsdResource + " has invalid root element: [" + schemaElement.getNamespaceURI() + "] instead of [" + resource + " has invalid root element: [" + schemaElement.getNamespaceURI() + "] instead of [" + SCHEMA_NAME.getNamespaceURI() + "]"); String targetNamespace = schemaElement.getAttribute("targetNamespace"); - Assert.hasText(targetNamespace, this.xsdResource + " has no targetNamespace"); - this.targetNamespace = targetNamespace; + Assert.hasText(targetNamespace, resource + " has no targetNamespace"); + return targetNamespace; } public String toString() { diff --git a/spring-xml/src/main/java/org/springframework/xml/xsd/XsdSchemaException.java b/spring-xml/src/main/java/org/springframework/xml/xsd/XsdSchemaException.java index 082bee79..71f14999 100644 --- a/spring-xml/src/main/java/org/springframework/xml/xsd/XsdSchemaException.java +++ b/spring-xml/src/main/java/org/springframework/xml/xsd/XsdSchemaException.java @@ -16,6 +16,8 @@ package org.springframework.xml.xsd; +import org.jspecify.annotations.Nullable; + import org.springframework.xml.XmlException; /** @@ -32,7 +34,7 @@ public class XsdSchemaException extends XmlException { super(message); } - public XsdSchemaException(String message, Throwable throwable) { + public XsdSchemaException(@Nullable String message, Throwable throwable) { super(message, throwable); } diff --git a/spring-xml/src/main/java/org/springframework/xml/xsd/commons/CommonsXsdSchema.java b/spring-xml/src/main/java/org/springframework/xml/xsd/commons/CommonsXsdSchema.java index f669a814..2ea926dc 100644 --- a/spring-xml/src/main/java/org/springframework/xml/xsd/commons/CommonsXsdSchema.java +++ b/spring-xml/src/main/java/org/springframework/xml/xsd/commons/CommonsXsdSchema.java @@ -31,6 +31,7 @@ import javax.xml.transform.stream.StreamSource; import org.apache.ws.commons.schema.XmlSchema; import org.apache.ws.commons.schema.XmlSchemaCollection; import org.apache.ws.commons.schema.XmlSchemaSerializer; +import org.jspecify.annotations.Nullable; import org.w3c.dom.Document; import org.springframework.beans.BeanInstantiationException; @@ -54,7 +55,7 @@ public class CommonsXsdSchema implements XsdSchema { private final XmlSchema schema; - private final XmlSchemaCollection collection; + private final @Nullable XmlSchemaCollection collection; /** * Create a new instance of the {@code CommonsXsdSchema} class with the specified @@ -74,7 +75,7 @@ public class CommonsXsdSchema implements XsdSchema { * {@code null} * @throws IllegalArgumentException if the supplied {@code schema} is {@code null} */ - protected CommonsXsdSchema(XmlSchema schema, XmlSchemaCollection collection) { + protected CommonsXsdSchema(XmlSchema schema, @Nullable XmlSchemaCollection collection) { Assert.notNull(schema, "'schema' must not be null"); this.schema = schema; this.collection = collection; diff --git a/spring-xml/src/main/java/org/springframework/xml/xsd/commons/CommonsXsdSchemaCollection.java b/spring-xml/src/main/java/org/springframework/xml/xsd/commons/CommonsXsdSchemaCollection.java index 3f06c499..7cd18263 100644 --- a/spring-xml/src/main/java/org/springframework/xml/xsd/commons/CommonsXsdSchemaCollection.java +++ b/spring-xml/src/main/java/org/springframework/xml/xsd/commons/CommonsXsdSchemaCollection.java @@ -32,6 +32,7 @@ import org.apache.ws.commons.schema.XmlSchemaInclude; import org.apache.ws.commons.schema.XmlSchemaObject; import org.apache.ws.commons.schema.resolver.DefaultURIResolver; import org.apache.ws.commons.schema.resolver.URIResolver; +import org.jspecify.annotations.Nullable; import org.xml.sax.InputSource; import org.springframework.beans.factory.InitializingBean; @@ -74,7 +75,7 @@ public class CommonsXsdSchemaCollection implements XsdSchemaCollection, Initiali private URIResolver uriResolver = new ClasspathUriResolver(); - private ResourceLoader resourceLoader; + private @Nullable ResourceLoader resourceLoader; /** * Constructs a new, empty instance of the {@code CommonsXsdSchemaCollection}. @@ -82,6 +83,7 @@ public class CommonsXsdSchemaCollection implements XsdSchemaCollection, Initiali * A subsequent call to the {@link #setXsds(Resource[])} is required. */ public CommonsXsdSchemaCollection() { + this(new Resource[0]); } /** diff --git a/spring-xml/src/main/java/org/springframework/xml/xsd/commons/CommonsXsdSchemaException.java b/spring-xml/src/main/java/org/springframework/xml/xsd/commons/CommonsXsdSchemaException.java index 6bcaf14d..35449cde 100644 --- a/spring-xml/src/main/java/org/springframework/xml/xsd/commons/CommonsXsdSchemaException.java +++ b/spring-xml/src/main/java/org/springframework/xml/xsd/commons/CommonsXsdSchemaException.java @@ -16,6 +16,8 @@ package org.springframework.xml.xsd.commons; +import org.jspecify.annotations.Nullable; + import org.springframework.xml.xsd.XsdSchemaException; /** @@ -31,7 +33,7 @@ public class CommonsXsdSchemaException extends XsdSchemaException { super(message); } - public CommonsXsdSchemaException(String message, Throwable exception) { + public CommonsXsdSchemaException(@Nullable String message, Throwable exception) { super(message, exception); } diff --git a/spring-xml/src/main/java/org/springframework/xml/xsd/commons/package-info.java b/spring-xml/src/main/java/org/springframework/xml/xsd/commons/package-info.java index a126cf07..aa579869 100644 --- a/spring-xml/src/main/java/org/springframework/xml/xsd/commons/package-info.java +++ b/spring-xml/src/main/java/org/springframework/xml/xsd/commons/package-info.java @@ -18,4 +18,7 @@ * Contains a implementation of the {@code XsdSchema} interfaces that uses Apache * WS-Commons XML Schema. */ +@NullMarked package org.springframework.xml.xsd.commons; + +import org.jspecify.annotations.NullMarked; diff --git a/spring-xml/src/main/java/org/springframework/xml/xsd/package-info.java b/spring-xml/src/main/java/org/springframework/xml/xsd/package-info.java index 91cfca19..01352650 100644 --- a/spring-xml/src/main/java/org/springframework/xml/xsd/package-info.java +++ b/spring-xml/src/main/java/org/springframework/xml/xsd/package-info.java @@ -18,4 +18,7 @@ * Provides an abstraction over XSD XML schemas. Contains the {@code XsdSchema} and * related interfaces. */ +@NullMarked package org.springframework.xml.xsd; + +import org.jspecify.annotations.NullMarked; diff --git a/src/checkstyle/checkstyle-suppressions.xml b/src/checkstyle/checkstyle-suppressions.xml index eb2c567f..a41d9018 100644 --- a/src/checkstyle/checkstyle-suppressions.xml +++ b/src/checkstyle/checkstyle-suppressions.xml @@ -8,4 +8,6 @@ + + \ No newline at end of file