Review nullability of spring-xml

See gh-1562
This commit is contained in:
Stéphane Nicoll
2025-05-16 09:31:39 +02:00
parent d3f96824d6
commit 5798f5e4ac
37 changed files with 162 additions and 92 deletions

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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<String> iterator = getPrefixes(namespaceUri);
return iterator.hasNext() ? iterator.next() : null;
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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();
}

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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<? extends TransformerFactory> transformerFactoryClass;
private @Nullable Class<? extends TransformerFactory> transformerFactoryClass;
/**
* Initializes a new instance of the {@code TransformerHelper}.
@@ -81,7 +83,8 @@ public class TransformerHelper {
* @see #setTransformerFactoryClass
* @see #getTransformerFactory()
*/
protected TransformerFactory newTransformerFactory(Class<? extends TransformerFactory> transformerFactoryClass) {
protected TransformerFactory newTransformerFactory(
@Nullable Class<? extends TransformerFactory> transformerFactoryClass) {
if (transformerFactoryClass != null) {
return TransformerFactoryUtils.newInstance(transformerFactoryClass);
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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<String, String> namespaces;
private Map<String, String> namespaces = Collections.emptyMap();
/** Returns namespaces used in the XPath expression. */
public Map<String, String> 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;
}

View File

@@ -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> T evaluateAsObject(Node context, NodeMapper<T> nodeMapper) throws XPathException {
public <T> @Nullable T evaluateAsObject(Node context, NodeMapper<T> nodeMapper) throws XPathException {
try {
Node result = (Node) this.xpath.selectSingleNode(context);
if (result != null) {

View File

@@ -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> T evaluateAsObject(String expression, Source context, NodeMapper<T> nodeMapper) throws XPathException {
public <T> @Nullable T evaluateAsObject(String expression, Source context, NodeMapper<T> 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<String, String> namespaces = getNamespaces();
if (!namespaces.isEmpty()) {
xpath.setNamespaceContext(new SimpleNamespaceContext(namespaces));
}
return xpath;
}

View File

@@ -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> T evaluateAsObject(Node node, NodeMapper<T> nodeMapper) throws XPathException {
public <T> @Nullable T evaluateAsObject(Node node, NodeMapper<T> 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);
}
}

View File

@@ -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<Node> evaluateAsNodeList(String expression, Source context) throws XPathException {
NodeList result = (NodeList) evaluate(expression, context, XPathConstants.NODESET);
List<Node> nodes = new ArrayList<>(result.getLength());
for (int i = 0; i < result.getLength(); i++) {
nodes.add(result.item(i));
List<Node> 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> T evaluateAsObject(String expression, Source context, NodeMapper<T> nodeMapper) throws XPathException {
public <T> @Nullable T evaluateAsObject(String expression, Source context, NodeMapper<T> 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 <T> List<T> evaluate(String expression, Source context, NodeMapper<T> nodeMapper) throws XPathException {
NodeList nodes = (NodeList) evaluate(expression, context, XPathConstants.NODESET);
List<T> 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<T> 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<String, String> 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;

View File

@@ -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<T> {
* @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;
}

View File

@@ -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);
}

View File

@@ -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 <a href="http://www.w3.org/TR/xpath#node-sets">XPath specification</a>
*/
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 <a href="http://www.w3.org/TR/xpath/#function-string">XPath specification -
* string() function</a>
*/
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 <a href="http://www.w3.org/TR/xpath#node-sets">XPath specification</a>
*/
<T> T evaluateAsObject(Node node, NodeMapper<T> nodeMapper) throws XPathException;
<T> @Nullable T evaluateAsObject(Node node, NodeMapper<T> nodeMapper) throws XPathException;
/**
* Evaluates the given expression, mapping each result {@link Node} objects to a Java

View File

@@ -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<String, String> namespaces)
public static XPathExpression createXPathExpression(String expression, @Nullable Map<String, String> namespaces)
throws IllegalStateException, XPathParseException {
Assert.hasLength(expression, "expression is empty");
if (namespaces == null) {

View File

@@ -36,10 +36,13 @@ import org.springframework.util.CollectionUtils;
*/
public class XPathExpressionFactoryBean implements FactoryBean<XPathExpression>, InitializingBean {
@SuppressWarnings("NullAway.Init")
private Map<String, String> namespaces;
@SuppressWarnings("NullAway.Init")
private String expressionString;
@SuppressWarnings("NullAway.Init")
private XPathExpression expression;
/** Sets the XPath expression. Setting this property is required. */

View File

@@ -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 <a href="http://www.w3.org/TR/xpath#node-sets">XPath specification</a>
*/
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 <a href="http://www.w3.org/TR/xpath/#function-string">XPath specification -
* string() function</a>
*/
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 <a href="http://www.w3.org/TR/xpath#node-sets">XPath specification</a>
*/
<T> T evaluateAsObject(String expression, Source context, NodeMapper<T> nodeMapper) throws XPathException;
<T> @Nullable T evaluateAsObject(String expression, Source context, NodeMapper<T> nodeMapper) throws XPathException;
/**
* Evaluates the given expression, mapping each result {@link Node} objects to a Java

View File

@@ -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;

View File

@@ -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() {

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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]);
}
/**

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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;