@Nullable all the way: null-safety at field level

This commits extends nullability declarations to the field level, formalizing the interaction between methods and their underlying fields and therefore avoiding any nullability mismatch.

Issue: SPR-15720
This commit is contained in:
Juergen Hoeller
2017-06-30 01:53:45 +02:00
parent c4694c3f5c
commit cc74a2891a
936 changed files with 6090 additions and 2806 deletions

View File

@@ -60,6 +60,7 @@ import org.springframework.oxm.ValidationFailureException;
import org.springframework.oxm.XmlMappingException;
import org.springframework.oxm.support.AbstractMarshaller;
import org.springframework.oxm.support.SaxResourceUtils;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.xml.DomUtils;
import org.springframework.util.xml.StaxUtils;
@@ -94,12 +95,15 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing
public static final String DEFAULT_ENCODING = "UTF-8";
@Nullable
private Resource[] mappingLocations;
private String encoding = DEFAULT_ENCODING;
@Nullable
private Class<?>[] targetClasses;
@Nullable
private String[] targetPackages;
private boolean validating = false;
@@ -112,10 +116,13 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing
private boolean marshalExtendedType = true;
@Nullable
private String rootElement;
@Nullable
private String noNamespaceSchemaLocation;
@Nullable
private String schemaLocation;
private boolean useXSITypeAtRoot = false;
@@ -126,32 +133,44 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing
private boolean ignoreExtraElements = false;
@Nullable
private Object rootObject;
private boolean reuseObjects = false;
private boolean clearCollections = false;
@Nullable
private Map<String, String> castorProperties;
@Nullable
private Map<String, String> doctypes;
@Nullable
private Map<String, String> processingInstructions;
@Nullable
private Map<String, String> namespaceMappings;
@Nullable
private Map<String, String> namespaceToPackageMapping;
@Nullable
private EntityResolver entityResolver;
@Nullable
private XMLClassDescriptorResolver classDescriptorResolver;
@Nullable
private IDResolver idResolver;
@Nullable
private ObjectFactory objectFactory;
@Nullable
private ClassLoader beanClassLoader;
@Nullable
private XMLContext xmlContext;
@@ -456,8 +475,9 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing
* @see XMLContext#addMapping(org.exolab.castor.mapping.Mapping)
* @see XMLContext#addClass(Class)
*/
protected XMLContext createXMLContext(Resource[] mappingLocations, Class<?>[] targetClasses,
String[] targetPackages) throws MappingException, ResolverException, IOException {
protected XMLContext createXMLContext(@Nullable Resource[] mappingLocations,
@Nullable Class<?>[] targetClasses, @Nullable String[] targetPackages)
throws MappingException, ResolverException, IOException {
XMLContext context = new XMLContext();
if (!ObjectUtils.isEmpty(mappingLocations)) {
@@ -520,7 +540,8 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing
protected void marshalSaxHandlers(Object graph, ContentHandler contentHandler, @Nullable LexicalHandler lexicalHandler)
throws XmlMappingException {
Marshaller marshaller = xmlContext.createMarshaller();
Assert.state(this.xmlContext != null, "CastorMarshaller not initialized");
Marshaller marshaller = this.xmlContext.createMarshaller();
marshaller.setContentHandler(contentHandler);
doMarshal(graph, marshaller);
}
@@ -532,7 +553,8 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing
@Override
protected void marshalWriter(Object graph, Writer writer) throws XmlMappingException, IOException {
Marshaller marshaller = xmlContext.createMarshaller();
Assert.state(this.xmlContext != null, "CastorMarshaller not initialized");
Marshaller marshaller = this.xmlContext.createMarshaller();
marshaller.setWriter(writer);
doMarshal(graph, marshaller);
}
@@ -641,6 +663,7 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing
}
private Unmarshaller createUnmarshaller() {
Assert.state(this.xmlContext != null, "CastorMarshaller not initialized");
Unmarshaller unmarshaller = this.xmlContext.createUnmarshaller();
customizeUnmarshaller(unmarshaller);
return unmarshaller;

View File

@@ -33,6 +33,7 @@ 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;
@@ -64,7 +65,7 @@ class ClassPathJaxb2TypeScanner {
private final String[] packagesToScan;
public ClassPathJaxb2TypeScanner(ClassLoader classLoader, String... packagesToScan) {
public ClassPathJaxb2TypeScanner(@Nullable ClassLoader classLoader, String... packagesToScan) {
Assert.notEmpty(packagesToScan, "'packagesToScan' must not be empty");
this.resourcePatternResolver = new PathMatchingResourcePatternResolver(classLoader);
this.packagesToScan = packagesToScan;

View File

@@ -131,30 +131,42 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi
/** Logger available to subclasses */
protected final Log logger = LogFactory.getLog(getClass());
@Nullable
private String contextPath;
@Nullable
private Class<?>[] classesToBeBound;
@Nullable
private String[] packagesToScan;
@Nullable
private Map<String, ?> jaxbContextProperties;
@Nullable
private Map<String, ?> marshallerProperties;
@Nullable
private Map<String, ?> unmarshallerProperties;
@Nullable
private Marshaller.Listener marshallerListener;
@Nullable
private Unmarshaller.Listener unmarshallerListener;
@Nullable
private ValidationEventHandler validationEventHandler;
@Nullable
private XmlAdapter<?, ?>[] adapters;
@Nullable
private Resource[] schemaResources;
private String schemaLanguage = XMLConstants.W3C_XML_SCHEMA_NS_URI;
@Nullable
private LSResourceResolver schemaResourceResolver;
private boolean lazyInit = false;
@@ -165,14 +177,18 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi
private boolean checkForXmlRootElement = true;
@Nullable
private Class<?> mappedClass;
@Nullable
private ClassLoader beanClassLoader;
private final Object jaxbContextMonitor = new Object();
@Nullable
private volatile JAXBContext jaxbContext;
@Nullable
private Schema schema;
private boolean supportDtd = false;
@@ -202,6 +218,7 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi
/**
* Return the JAXB context path.
*/
@Nullable
public String getContextPath() {
return this.contextPath;
}
@@ -219,6 +236,7 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi
/**
* Return the list of Java classes to be recognized by a newly created JAXBContext.
*/
@Nullable
public Class<?>[] getClassesToBeBound() {
return this.classesToBeBound;
}
@@ -237,6 +255,7 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi
/**
* Return the packages to search for JAXB2 annotations.
*/
@Nullable
public String[] getPackagesToScan() {
return this.packagesToScan;
}
@@ -464,27 +483,33 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi
* Return the JAXBContext used by this marshaller, lazily building it if necessary.
*/
public JAXBContext getJaxbContext() {
if (this.jaxbContext != null) {
return this.jaxbContext;
JAXBContext context = this.jaxbContext;
if (context != null) {
return context;
}
synchronized (this.jaxbContextMonitor) {
if (this.jaxbContext == null) {
context = this.jaxbContext;
if (context == null) {
try {
if (StringUtils.hasLength(this.contextPath)) {
this.jaxbContext = createJaxbContextFromContextPath();
context = createJaxbContextFromContextPath();
}
else if (!ObjectUtils.isEmpty(this.classesToBeBound)) {
this.jaxbContext = createJaxbContextFromClasses();
context = createJaxbContextFromClasses(this.classesToBeBound);
}
else if (!ObjectUtils.isEmpty(this.packagesToScan)) {
this.jaxbContext = createJaxbContextFromPackages();
context = createJaxbContextFromPackages(this.packagesToScan);
}
else {
context = JAXBContext.newInstance();
}
this.jaxbContext = context;
}
catch (JAXBException ex) {
throw convertJaxbException(ex);
}
}
return this.jaxbContext;
return context;
}
}
@@ -512,25 +537,25 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi
}
}
private JAXBContext createJaxbContextFromClasses() throws JAXBException {
private JAXBContext createJaxbContextFromClasses(Class<?>... classesToBeBound) throws JAXBException {
if (logger.isInfoEnabled()) {
logger.info("Creating JAXBContext with classes to be bound [" +
StringUtils.arrayToCommaDelimitedString(this.classesToBeBound) + "]");
StringUtils.arrayToCommaDelimitedString(classesToBeBound) + "]");
}
if (this.jaxbContextProperties != null) {
return JAXBContext.newInstance(this.classesToBeBound, this.jaxbContextProperties);
return JAXBContext.newInstance(classesToBeBound, this.jaxbContextProperties);
}
else {
return JAXBContext.newInstance(this.classesToBeBound);
return JAXBContext.newInstance(classesToBeBound);
}
}
private JAXBContext createJaxbContextFromPackages() throws JAXBException {
private JAXBContext createJaxbContextFromPackages(String... packagesToScan) throws JAXBException {
if (logger.isInfoEnabled()) {
logger.info("Creating JAXBContext by scanning packages [" +
StringUtils.arrayToCommaDelimitedString(this.packagesToScan) + "]");
StringUtils.arrayToCommaDelimitedString(packagesToScan) + "]");
}
ClassPathJaxb2TypeScanner scanner = new ClassPathJaxb2TypeScanner(this.beanClassLoader, this.packagesToScan);
ClassPathJaxb2TypeScanner scanner = new ClassPathJaxb2TypeScanner(this.beanClassLoader, packagesToScan);
Class<?>[] jaxb2Classes = scanner.scanPackages();
if (logger.isDebugEnabled()) {
logger.debug("Found JAXB2 classes: [" + StringUtils.arrayToCommaDelimitedString(jaxb2Classes) + "]");

View File

@@ -87,26 +87,35 @@ public class JibxMarshaller extends AbstractMarshaller implements InitializingBe
private static final String DEFAULT_BINDING_NAME = "binding";
@Nullable
private Class<?> targetClass;
@Nullable
private String targetPackage;
@Nullable
private String bindingName;
private int indent = -1;
private String encoding = "UTF-8";
@Nullable
private Boolean standalone;
@Nullable
private String docTypeRootElementName;
@Nullable
private String docTypeSystemId;
@Nullable
private String docTypePublicId;
@Nullable
private String docTypeInternalSubset;
@Nullable
private IBindingFactory bindingFactory;
private final TransformerFactory transformerFactory = TransformerFactory.newInstance();
@@ -241,6 +250,7 @@ public class JibxMarshaller extends AbstractMarshaller implements InitializingBe
if (this.targetClass != null) {
return (this.targetClass == clazz);
}
Assert.state(this.bindingFactory != null, "JibxMarshaller not initialized");
String[] mappedClasses = this.bindingFactory.getMappedClasses();
String className = clazz.getName();
for (String mappedClass : mappedClasses) {
@@ -443,6 +453,7 @@ public class JibxMarshaller extends AbstractMarshaller implements InitializingBe
* @throws JiBXException in case of errors
*/
protected IMarshallingContext createMarshallingContext() throws JiBXException {
Assert.state(this.bindingFactory != null, "JibxMarshaller not initialized");
IMarshallingContext marshallingContext = this.bindingFactory.createMarshallingContext();
marshallingContext.setIndent(this.indent);
return marshallingContext;
@@ -454,6 +465,7 @@ public class JibxMarshaller extends AbstractMarshaller implements InitializingBe
* @throws JiBXException in case of errors
*/
protected IUnmarshallingContext createUnmarshallingContext() throws JiBXException {
Assert.state(this.bindingFactory != null, "JibxMarshaller not initialized");
return this.bindingFactory.createUnmarshallingContext();
}

View File

@@ -77,6 +77,7 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller {
private boolean processExternalEntities = false;
@Nullable
private DocumentBuilderFactory documentBuilderFactory;
private final Object documentBuilderFactoryMonitor = new Object();

View File

@@ -122,40 +122,56 @@ public class XStreamMarshaller extends AbstractMarshaller implements BeanClassLo
public static final String DEFAULT_ENCODING = "UTF-8";
@Nullable
private ReflectionProvider reflectionProvider;
@Nullable
private HierarchicalStreamDriver streamDriver;
@Nullable
private HierarchicalStreamDriver defaultDriver;
@Nullable
private Mapper mapper;
@Nullable
private Class<? extends MapperWrapper>[] mapperWrappers;
private ConverterLookup converterLookup = new DefaultConverterLookup();
private ConverterRegistry converterRegistry = (ConverterRegistry) this.converterLookup;
@Nullable
private ConverterMatcher[] converters;
@Nullable
private MarshallingStrategy marshallingStrategy;
@Nullable
private Integer mode;
@Nullable
private Map<String, ?> aliases;
@Nullable
private Map<String, ?> aliasesByType;
@Nullable
private Map<String, String> fieldAliases;
@Nullable
private Class<?>[] useAttributeForTypes;
@Nullable
private Map<?, ?> useAttributeFor;
@Nullable
private Map<Class<?>, String> implicitCollections;
@Nullable
private Map<Class<?>, String> omittedFields;
@Nullable
private Class<?>[] annotatedClasses;
private boolean autodetectAnnotations;
@@ -164,10 +180,12 @@ public class XStreamMarshaller extends AbstractMarshaller implements BeanClassLo
private NameCoder nameCoder = new XmlFriendlyNameCoder();
@Nullable
private Class<?>[] supportedClasses;
private ClassLoader beanClassLoader = new CompositeClassLoader();
@Nullable
private XStream xstream;