Switch to JSpecify annotations

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

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

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

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

View File

@@ -1,9 +1,7 @@
/**
* Provides an namespace handler for the Spring Object/XML namespace.
*/
@NonNullApi
@NonNullFields
@NullMarked
package org.springframework.oxm.config;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
import org.jspecify.annotations.NullMarked;

View File

@@ -25,6 +25,7 @@ import jakarta.xml.bind.annotation.XmlRegistry;
import jakarta.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.annotation.XmlSeeAlso;
import jakarta.xml.bind.annotation.XmlType;
import org.jspecify.annotations.Nullable;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
@@ -34,7 +35,6 @@ import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.lang.Nullable;
import org.springframework.oxm.UncategorizedMappingException;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;

View File

@@ -77,6 +77,7 @@ import jakarta.xml.bind.attachment.AttachmentMarshaller;
import jakarta.xml.bind.attachment.AttachmentUnmarshaller;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.w3c.dom.ls.LSResourceResolver;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
@@ -87,7 +88,6 @@ import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.io.Resource;
import org.springframework.lang.Nullable;
import org.springframework.oxm.GenericMarshaller;
import org.springframework.oxm.GenericUnmarshaller;
import org.springframework.oxm.MarshallingFailureException;
@@ -142,43 +142,31 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi
/** Logger available to subclasses. */
protected final Log logger = LogFactory.getLog(getClass());
@Nullable
private String contextPath;
private @Nullable String contextPath;
@Nullable
private Class<?>[] classesToBeBound;
private Class<?> @Nullable [] classesToBeBound;
@Nullable
private String[] packagesToScan;
private String @Nullable [] packagesToScan;
@Nullable
private Map<String, ?> jaxbContextProperties;
private @Nullable Map<String, ?> jaxbContextProperties;
@Nullable
private Map<String, ?> marshallerProperties;
private @Nullable Map<String, ?> marshallerProperties;
@Nullable
private Map<String, ?> unmarshallerProperties;
private @Nullable Map<String, ?> unmarshallerProperties;
@Nullable
private Marshaller.Listener marshallerListener;
private Marshaller.@Nullable Listener marshallerListener;
@Nullable
private Unmarshaller.Listener unmarshallerListener;
private Unmarshaller.@Nullable Listener unmarshallerListener;
@Nullable
private ValidationEventHandler validationEventHandler;
private @Nullable ValidationEventHandler validationEventHandler;
@Nullable
private XmlAdapter<?, ?>[] adapters;
private XmlAdapter<?, ?> @Nullable [] adapters;
@Nullable
private Resource[] schemaResources;
private Resource @Nullable [] schemaResources;
private String schemaLanguage = XMLConstants.W3C_XML_SCHEMA_NS_URI;
@Nullable
private LSResourceResolver schemaResourceResolver;
private @Nullable LSResourceResolver schemaResourceResolver;
private boolean lazyInit = false;
@@ -188,29 +176,23 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi
private boolean checkForXmlRootElement = true;
@Nullable
private Class<?> mappedClass;
private @Nullable Class<?> mappedClass;
@Nullable
private ClassLoader beanClassLoader;
private @Nullable ClassLoader beanClassLoader;
private final Lock jaxbContextLock = new ReentrantLock();
@Nullable
private volatile JAXBContext jaxbContext;
private volatile @Nullable JAXBContext jaxbContext;
@Nullable
private Schema schema;
private @Nullable Schema schema;
private boolean supportDtd = false;
private boolean processExternalEntities = false;
@Nullable
private volatile SAXParserFactory schemaParserFactory;
private volatile @Nullable SAXParserFactory schemaParserFactory;
@Nullable
private volatile SAXParserFactory sourceParserFactory;
private volatile @Nullable SAXParserFactory sourceParserFactory;
/**
@@ -234,8 +216,7 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi
/**
* Return the JAXB context path.
*/
@Nullable
public String getContextPath() {
public @Nullable String getContextPath() {
return this.contextPath;
}
@@ -244,15 +225,14 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi
* <p>Setting either this property, {@link #setContextPath "contextPath"}
* or {@link #setPackagesToScan "packagesToScan"} is required.
*/
public void setClassesToBeBound(@Nullable Class<?>... classesToBeBound) {
public void setClassesToBeBound(Class<?> @Nullable ... classesToBeBound) {
this.classesToBeBound = classesToBeBound;
}
/**
* Return the list of Java classes to be recognized by a newly created JAXBContext.
*/
@Nullable
public Class<?>[] getClassesToBeBound() {
public Class<?> @Nullable [] getClassesToBeBound() {
return this.classesToBeBound;
}
@@ -263,15 +243,14 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi
* <p>Setting either this property, {@link #setContextPath "contextPath"} or
* {@link #setClassesToBeBound "classesToBeBound"} is required.
*/
public void setPackagesToScan(@Nullable String... packagesToScan) {
public void setPackagesToScan(String @Nullable ... packagesToScan) {
this.packagesToScan = packagesToScan;
}
/**
* Return the packages to search for JAXB2 annotations.
*/
@Nullable
public String[] getPackagesToScan() {
public String @Nullable [] getPackagesToScan() {
return this.packagesToScan;
}

View File

@@ -2,9 +2,7 @@
* Package providing integration of <a href="https://java.sun.com/webservices/jaxb/">JAXB</a>
* with Spring's O/X Mapping support.
*/
@NonNullApi
@NonNullFields
@NullMarked
package org.springframework.oxm.jaxb;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
import org.jspecify.annotations.NullMarked;

View File

@@ -17,8 +17,7 @@
package org.springframework.oxm.mime;
import jakarta.activation.DataHandler;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* Represents a container for MIME attachments
@@ -58,7 +57,6 @@ public interface MimeContainer {
* @param contentId the content id
* @return the attachment, as a data handler
*/
@Nullable
DataHandler getAttachment(String contentId);
@Nullable DataHandler getAttachment(String contentId);
}

View File

@@ -20,7 +20,8 @@ import java.io.IOException;
import javax.xml.transform.Result;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.XmlMappingException;

View File

@@ -20,7 +20,8 @@ import java.io.IOException;
import javax.xml.transform.Source;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.oxm.Unmarshaller;
import org.springframework.oxm.XmlMappingException;

View File

@@ -1,9 +1,7 @@
/**
* Contains (un)marshallers optimized to store binary data in MIME attachments.
*/
@NonNullApi
@NonNullFields
@NullMarked
package org.springframework.oxm.mime;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
import org.jspecify.annotations.NullMarked;

View File

@@ -3,9 +3,7 @@
* Contains generic Marshaller and Unmarshaller interfaces,
* and XmlMappingExceptions related to O/X Mapping
*/
@NonNullApi
@NonNullFields
@NullMarked
package org.springframework.oxm;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
import org.jspecify.annotations.NullMarked;

View File

@@ -44,6 +44,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.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.ContentHandler;
@@ -53,7 +54,6 @@ import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.ext.LexicalHandler;
import org.springframework.lang.Nullable;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.Unmarshaller;
import org.springframework.oxm.UnmarshallingFailureException;
@@ -82,11 +82,9 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller {
private boolean processExternalEntities = false;
@Nullable
private volatile DocumentBuilderFactory documentBuilderFactory;
private volatile @Nullable DocumentBuilderFactory documentBuilderFactory;
@Nullable
private volatile SAXParserFactory saxParserFactory;
private volatile @Nullable SAXParserFactory saxParserFactory;
/**
@@ -220,8 +218,7 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller {
* a byte stream, or {@code null} if none.
* <p>The default implementation returns {@code null}.
*/
@Nullable
protected String getDefaultEncoding() {
protected @Nullable String getDefaultEncoding() {
return null;
}

View File

@@ -22,6 +22,7 @@ import javax.xml.transform.Source;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.sax.SAXSource;
import org.jspecify.annotations.Nullable;
import org.xml.sax.ContentHandler;
import org.xml.sax.DTDHandler;
import org.xml.sax.EntityResolver;
@@ -33,7 +34,6 @@ import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.ext.LexicalHandler;
import org.springframework.lang.Nullable;
import org.springframework.oxm.Marshaller;
import org.springframework.util.Assert;
@@ -109,20 +109,15 @@ public class MarshallingSource extends SAXSource {
private final Object content;
@Nullable
private DTDHandler dtdHandler;
private @Nullable DTDHandler dtdHandler;
@Nullable
private ContentHandler contentHandler;
private @Nullable ContentHandler contentHandler;
@Nullable
private EntityResolver entityResolver;
private @Nullable EntityResolver entityResolver;
@Nullable
private ErrorHandler errorHandler;
private @Nullable ErrorHandler errorHandler;
@Nullable
private LexicalHandler lexicalHandler;
private @Nullable LexicalHandler lexicalHandler;
private MarshallingXMLReader(Marshaller marshaller, Object content) {
Assert.notNull(marshaller, "'marshaller' must not be null");
@@ -137,8 +132,7 @@ public class MarshallingSource extends SAXSource {
}
@Override
@Nullable
public ContentHandler getContentHandler() {
public @Nullable ContentHandler getContentHandler() {
return this.contentHandler;
}
@@ -148,8 +142,7 @@ public class MarshallingSource extends SAXSource {
}
@Override
@Nullable
public DTDHandler getDTDHandler() {
public @Nullable DTDHandler getDTDHandler() {
return this.dtdHandler;
}
@@ -159,8 +152,7 @@ public class MarshallingSource extends SAXSource {
}
@Override
@Nullable
public EntityResolver getEntityResolver() {
public @Nullable EntityResolver getEntityResolver() {
return this.entityResolver;
}
@@ -170,13 +162,11 @@ public class MarshallingSource extends SAXSource {
}
@Override
@Nullable
public ErrorHandler getErrorHandler() {
public @Nullable ErrorHandler getErrorHandler() {
return this.errorHandler;
}
@Nullable
protected LexicalHandler getLexicalHandler() {
protected @Nullable LexicalHandler getLexicalHandler() {
return this.lexicalHandler;
}
@@ -191,8 +181,7 @@ public class MarshallingSource extends SAXSource {
}
@Override
@Nullable
public Object getProperty(String name) throws SAXNotRecognizedException {
public @Nullable Object getProperty(String name) throws SAXNotRecognizedException {
if ("http://xml.org/sax/properties/lexical-handler".equals(name)) {
return this.lexicalHandler;
}

View File

@@ -18,10 +18,10 @@ package org.springframework.oxm.support;
import java.io.IOException;
import org.jspecify.annotations.Nullable;
import org.xml.sax.InputSource;
import org.springframework.core.io.Resource;
import org.springframework.lang.Nullable;
/**
* Convenient utility methods for dealing with SAX.
@@ -51,8 +51,7 @@ public abstract class SaxResourceUtils {
* Retrieve the URL from the given resource as System ID.
* <p>Returns {@code null} if it cannot be opened.
*/
@Nullable
private static String getSystemId(Resource resource) {
private static @Nullable String getSystemId(Resource resource) {
try {
return resource.getURI().toString();
}

View File

@@ -4,9 +4,7 @@
* with TrAX, MarshallingView for use within Spring Web MVC, and the
* MarshallingMessageConverter for use within Spring's JMS support.
*/
@NonNullApi
@NonNullFields
@NullMarked
package org.springframework.oxm.support;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
import org.jspecify.annotations.NullMarked;

View File

@@ -66,6 +66,7 @@ import com.thoughtworks.xstream.mapper.Mapper;
import com.thoughtworks.xstream.mapper.MapperWrapper;
import com.thoughtworks.xstream.security.ForbiddenClassException;
import com.thoughtworks.xstream.security.TypePermission;
import org.jspecify.annotations.Nullable;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
@@ -76,7 +77,6 @@ import org.xml.sax.ext.LexicalHandler;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.lang.Nullable;
import org.springframework.oxm.MarshallingFailureException;
import org.springframework.oxm.UncategorizedMappingException;
import org.springframework.oxm.UnmarshallingFailureException;
@@ -130,60 +130,43 @@ public class XStreamMarshaller extends AbstractMarshaller implements BeanClassLo
public static final String DEFAULT_ENCODING = "UTF-8";
@Nullable
private ReflectionProvider reflectionProvider;
private @Nullable ReflectionProvider reflectionProvider;
@Nullable
private HierarchicalStreamDriver streamDriver;
private @Nullable HierarchicalStreamDriver streamDriver;
@Nullable
private HierarchicalStreamDriver defaultDriver;
private @Nullable HierarchicalStreamDriver defaultDriver;
@Nullable
private Mapper mapper;
private @Nullable Mapper mapper;
@Nullable
private Class<? extends MapperWrapper>[] mapperWrappers;
private Class<? extends MapperWrapper> @Nullable [] mapperWrappers;
private ConverterLookup converterLookup = new DefaultConverterLookup();
private ConverterRegistry converterRegistry = (ConverterRegistry) this.converterLookup;
@Nullable
private ConverterMatcher[] converters;
private ConverterMatcher @Nullable [] converters;
@Nullable
private TypePermission[] typePermissions;
private TypePermission @Nullable [] typePermissions;
@Nullable
private MarshallingStrategy marshallingStrategy;
private @Nullable MarshallingStrategy marshallingStrategy;
@Nullable
private Integer mode;
private @Nullable Integer mode;
@Nullable
private Map<String, ?> aliases;
private @Nullable Map<String, ?> aliases;
@Nullable
private Map<String, ?> aliasesByType;
private @Nullable Map<String, ?> aliasesByType;
@Nullable
private Map<String, String> fieldAliases;
private @Nullable Map<String, String> fieldAliases;
@Nullable
private Class<?>[] useAttributeForTypes;
private Class<?> @Nullable [] useAttributeForTypes;
@Nullable
private Map<?, ?> useAttributeFor;
private @Nullable Map<?, ?> useAttributeFor;
@Nullable
private Map<Class<?>, String> implicitCollections;
private @Nullable Map<Class<?>, String> implicitCollections;
@Nullable
private Map<Class<?>, String> omittedFields;
private @Nullable Map<Class<?>, String> omittedFields;
@Nullable
private Class<?>[] annotatedClasses;
private Class<?> @Nullable [] annotatedClasses;
private boolean autodetectAnnotations;
@@ -191,11 +174,9 @@ public class XStreamMarshaller extends AbstractMarshaller implements BeanClassLo
private NameCoder nameCoder = new XmlFriendlyNameCoder();
@Nullable
private Class<?>[] supportedClasses;
private Class<?> @Nullable [] supportedClasses;
@Nullable
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
private @Nullable ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
private final SingletonSupplier<XStream> xstream = SingletonSupplier.of(this::buildXStream);

View File

@@ -2,9 +2,7 @@
* Package providing integration of <a href="https://x-stream.github.io/">XStream</a>
* with Spring's O/X Mapping support.
*/
@NonNullApi
@NonNullFields
@NullMarked
package org.springframework.oxm.xstream;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
import org.jspecify.annotations.NullMarked;