Details
-
Bug
-
Resolution: Not an Issue
-
P4
-
None
-
11, 15, 16
-
x86_64
-
windows_10
Description
ADDITIONAL SYSTEM INFORMATION :
openjdk version "15" 2020-09-15
OpenJDK Runtime Environment (build 15+36-1562)
OpenJDK 64-Bit Server VM (build 15+36-1562, mixed mode, sharing)
A DESCRIPTION OF THE PROBLEM :
The method java.xml/javax.xml.catalog.CatalogResolverImpl.resolveEntity checks if systemId is null and if so reports the problem "JAXP09020006: The argument 'systemId' can not be null.". The thing is that when using a catalog file the systemId parameter is always set to null and this in turn triggers JAXP09020006. However if a wrapper class is introduced that implement the CatalogResolver interface and intercepts any systemId null values (replacing them with the empty string "") validation in combination with a catalog file magically start to work as expected.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Use a catalog file in combination with validation.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Validation should be able to work together with a catalog file.
ACTUAL -
(Source code for foo/Foo.java provided in the test case)
java.lang.NullPointerException: JAXP09020006: The argument 'systemId' can not be null.
at java.xml/javax.xml.catalog.CatalogMessages.reportNPEOnNull(CatalogMessages.java:129)
at java.xml/javax.xml.catalog.CatalogResolverImpl.resolveEntity(CatalogResolverImpl.java:70)
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLEntityManager.resolveEntity(XMLEntityManager.java:1154)
at java.xml/com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.resolveDocument(XMLSchemaLoader.java:662)
at java.xml/com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.findSchemaGrammar(XMLSchemaValidator.java:2694)
at java.xml/com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.handleStartElement(XMLSchemaValidator.java:2069)
at java.xml/com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.startElement(XMLSchemaValidator.java:829)
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(XMLNSDocumentScannerImpl.java:374)
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl$NSContentDriver.scanRootElementHook(XMLNSDocumentScannerImpl.java:613)
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:3078)
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:836)
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:605)
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:112)
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:541)
at java.xml/com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:888)
at java.xml/com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:824)
at java.xml/com.sun.org.apache.xerces.internal.jaxp.validation.StreamValidatorHelper.validate(StreamValidatorHelper.java:176)
at java.xml/com.sun.org.apache.xerces.internal.jaxp.validation.ValidatorImpl.validate(ValidatorImpl.java:115)
at foo.Foo.main(Foo.java:45)
---------- BEGIN SOURCE ----------
package foo;
import java.io.File;
import java.io.StringWriter;
import java.net.URL;
import java.net.URI;
import java.net.URISyntaxException;
import javax.xml.XMLConstants;
import javax.xml.catalog.CatalogFeatures;
import javax.xml.transform.stream.StreamSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Schema;
import javax.xml.validation.Validator;
public class Foo
{
public static void main(String[] args)
{
final String catalogFile = CatalogFeatures.Feature.FILES.getPropertyName();
final String catalogPath = "foo/catalog.xml";
final ClassLoader classLoader = Foo.class.getClassLoader();
try
{
final URL catalogUrl = classLoader.getResource(catalogPath);
final URI catalog = catalogUrl.toURI();
if (catalog != null)
{
SchemaFactory schemaFactory =
SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema();
StreamSource source = new StreamSource(new File("xyzzy.xml"));
Validator validator = schema.newValidator();
validator.setProperty(catalogFile, catalog.toString());
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
validator.validate(source, result);
System.out.println(writer);
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
Catalog file ./foo/catalog.xml
<?xml version="1.0"?>
<!DOCTYPE catalog
PUBLIC "-//OASIS/DTD Entity Resolution XML Catalog V1.0//EN"
"http://www.oasis-open.org/comittees/entity/release/1.0/catalog.dtd">
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
<uri name="urn:foo:bar:xyzzy.xsd:0.1"
uri="schemas/xyzzy.xsd"/>
</catalog>
XSD schema file ./foo/schemas/xyzzy.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="urn:foo:bar"
xmlns:gazonk="urn:foo:bar"
elementFormDefault="qualified">
<xs:element name="xyzzy">
<xs:complexType/>
</xs:element>
</xs:schema>
Input XML file ./xyzzy.xml
<?xml version="1.0"?>
<gazonk:xyzzy xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:gazonk="urn:foo:bar"
xsi:schemaLocation="urn:foo:bar:xyzzy.xsd:0.1"/>
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Introduce wrapper class for CatalogResolver (./foo/Resolver.java)
package foo;
import java.io.InputStream;
import javax.xml.catalog.CatalogResolver;
import javax.xml.transform.Source;
import org.w3c.dom.ls.LSInput;
import org.xml.sax.InputSource;
public class Resolver implements CatalogResolver
{
private final CatalogResolver m_resolver;
public Resolver(CatalogResolver resolver)
{
if (resolver != null)
{
m_resolver = resolver;
}
else
{
String message = "Wrapped resolver must not be null.";
throw new IllegalArgumentException(message);
}
}
public Source resolve(String href, String base)
{
return m_resolver.resolve(href, base);
}
public InputSource resolveEntity(String publicId, String systemId)
{
// Ensure systemId is not null.
return m_resolver.resolveEntity(publicId,
(systemId == null)? "" : systemId);
}
public InputStream resolveEntity(String publicId,
String systemId,
String baseUri,
String namespace)
{
// Ensure systemId is not null.
return m_resolver.resolveEntity(publicId,
(systemId == null)? "" : systemId,
baseUri,
namespace);
}
public LSInput resolveResource(String type,
String namespaceUri,
String publicId,
String systemId,
String baseUri)
{
// Ensure both publicId and systemId are not null at the same time
// before passing it on to the real resolver.
if ((publicId == null) && (systemId == null))
{
String message = ("Missing namespace and schema location pair, " +
"only have namespace URI '" + namespaceUri +
"' which is not enough to go on when trying to " +
"locate the schema file...");
throw new NullPointerException(message);
}
// Ensure systemId is not null.
return m_resolver.resolveResource(type,
namespaceUri,
publicId,
(systemId == null)? "" : systemId,
baseUri);
}
}
and modified variant of ./foo/Foo.java called ./foo/Bar.java that uses foo.Resolver
package foo;
import java.io.File;
import java.io.StringWriter;
import java.net.URL;
import java.net.URI;
import java.net.URISyntaxException;
import javax.xml.XMLConstants;
import javax.xml.catalog.CatalogFeatures;
import javax.xml.catalog.CatalogManager;
import javax.xml.catalog.CatalogResolver;
import javax.xml.transform.stream.StreamSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Schema;
import javax.xml.validation.Validator;
import org.w3c.dom.ls.LSInput;
public class Bar
{
public static void main(String[] args)
{
final String catalogFile = CatalogFeatures.Feature.FILES.getPropertyName();
final String catalogPath = "foo/catalog.xml";
final ClassLoader classLoader = Foo.class.getClassLoader();
try
{
final URL catalogUrl = classLoader.getResource(catalogPath);
final URI catalog = catalogUrl.toURI();
if (catalog != null)
{
CatalogFeatures features = CatalogFeatures.builder()
//.with(Feature.FILES, catalog.toString())
.with(CatalogFeatures.Feature.PREFER, "public")
.with(CatalogFeatures.Feature.DEFER, "true")
.with(CatalogFeatures.Feature.RESOLVE, "strict")
.build();
CatalogResolver resolver = CatalogManager.catalogResolver(features,
catalog);
Resolver wrapper = new Resolver(resolver);
SchemaFactory schemaFactory =
SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
schemaFactory.setResourceResolver(wrapper);
Schema schema = schemaFactory.newSchema();
StreamSource source = new StreamSource(new File("xyzzy.xml"));
Validator validator = schema.newValidator();
validator.setProperty(catalogFile, catalog.toString());
validator.setResourceResolver(wrapper);
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
validator.validate(source, result);
System.out.println(writer);
/*
*/
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
FREQUENCY : always
openjdk version "15" 2020-09-15
OpenJDK Runtime Environment (build 15+36-1562)
OpenJDK 64-Bit Server VM (build 15+36-1562, mixed mode, sharing)
A DESCRIPTION OF THE PROBLEM :
The method java.xml/javax.xml.catalog.CatalogResolverImpl.resolveEntity checks if systemId is null and if so reports the problem "JAXP09020006: The argument 'systemId' can not be null.". The thing is that when using a catalog file the systemId parameter is always set to null and this in turn triggers JAXP09020006. However if a wrapper class is introduced that implement the CatalogResolver interface and intercepts any systemId null values (replacing them with the empty string "") validation in combination with a catalog file magically start to work as expected.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Use a catalog file in combination with validation.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Validation should be able to work together with a catalog file.
ACTUAL -
(Source code for foo/Foo.java provided in the test case)
java.lang.NullPointerException: JAXP09020006: The argument 'systemId' can not be null.
at java.xml/javax.xml.catalog.CatalogMessages.reportNPEOnNull(CatalogMessages.java:129)
at java.xml/javax.xml.catalog.CatalogResolverImpl.resolveEntity(CatalogResolverImpl.java:70)
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLEntityManager.resolveEntity(XMLEntityManager.java:1154)
at java.xml/com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.resolveDocument(XMLSchemaLoader.java:662)
at java.xml/com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.findSchemaGrammar(XMLSchemaValidator.java:2694)
at java.xml/com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.handleStartElement(XMLSchemaValidator.java:2069)
at java.xml/com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.startElement(XMLSchemaValidator.java:829)
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(XMLNSDocumentScannerImpl.java:374)
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl$NSContentDriver.scanRootElementHook(XMLNSDocumentScannerImpl.java:613)
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:3078)
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:836)
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:605)
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:112)
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:541)
at java.xml/com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:888)
at java.xml/com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:824)
at java.xml/com.sun.org.apache.xerces.internal.jaxp.validation.StreamValidatorHelper.validate(StreamValidatorHelper.java:176)
at java.xml/com.sun.org.apache.xerces.internal.jaxp.validation.ValidatorImpl.validate(ValidatorImpl.java:115)
at foo.Foo.main(Foo.java:45)
---------- BEGIN SOURCE ----------
package foo;
import java.io.File;
import java.io.StringWriter;
import java.net.URL;
import java.net.URI;
import java.net.URISyntaxException;
import javax.xml.XMLConstants;
import javax.xml.catalog.CatalogFeatures;
import javax.xml.transform.stream.StreamSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Schema;
import javax.xml.validation.Validator;
public class Foo
{
public static void main(String[] args)
{
final String catalogFile = CatalogFeatures.Feature.FILES.getPropertyName();
final String catalogPath = "foo/catalog.xml";
final ClassLoader classLoader = Foo.class.getClassLoader();
try
{
final URL catalogUrl = classLoader.getResource(catalogPath);
final URI catalog = catalogUrl.toURI();
if (catalog != null)
{
SchemaFactory schemaFactory =
SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema();
StreamSource source = new StreamSource(new File("xyzzy.xml"));
Validator validator = schema.newValidator();
validator.setProperty(catalogFile, catalog.toString());
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
validator.validate(source, result);
System.out.println(writer);
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
Catalog file ./foo/catalog.xml
<?xml version="1.0"?>
<!DOCTYPE catalog
PUBLIC "-//OASIS/DTD Entity Resolution XML Catalog V1.0//EN"
"http://www.oasis-open.org/comittees/entity/release/1.0/catalog.dtd">
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
<uri name="urn:foo:bar:xyzzy.xsd:0.1"
uri="schemas/xyzzy.xsd"/>
</catalog>
XSD schema file ./foo/schemas/xyzzy.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="urn:foo:bar"
xmlns:gazonk="urn:foo:bar"
elementFormDefault="qualified">
<xs:element name="xyzzy">
<xs:complexType/>
</xs:element>
</xs:schema>
Input XML file ./xyzzy.xml
<?xml version="1.0"?>
<gazonk:xyzzy xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:gazonk="urn:foo:bar"
xsi:schemaLocation="urn:foo:bar:xyzzy.xsd:0.1"/>
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Introduce wrapper class for CatalogResolver (./foo/Resolver.java)
package foo;
import java.io.InputStream;
import javax.xml.catalog.CatalogResolver;
import javax.xml.transform.Source;
import org.w3c.dom.ls.LSInput;
import org.xml.sax.InputSource;
public class Resolver implements CatalogResolver
{
private final CatalogResolver m_resolver;
public Resolver(CatalogResolver resolver)
{
if (resolver != null)
{
m_resolver = resolver;
}
else
{
String message = "Wrapped resolver must not be null.";
throw new IllegalArgumentException(message);
}
}
public Source resolve(String href, String base)
{
return m_resolver.resolve(href, base);
}
public InputSource resolveEntity(String publicId, String systemId)
{
// Ensure systemId is not null.
return m_resolver.resolveEntity(publicId,
(systemId == null)? "" : systemId);
}
public InputStream resolveEntity(String publicId,
String systemId,
String baseUri,
String namespace)
{
// Ensure systemId is not null.
return m_resolver.resolveEntity(publicId,
(systemId == null)? "" : systemId,
baseUri,
namespace);
}
public LSInput resolveResource(String type,
String namespaceUri,
String publicId,
String systemId,
String baseUri)
{
// Ensure both publicId and systemId are not null at the same time
// before passing it on to the real resolver.
if ((publicId == null) && (systemId == null))
{
String message = ("Missing namespace and schema location pair, " +
"only have namespace URI '" + namespaceUri +
"' which is not enough to go on when trying to " +
"locate the schema file...");
throw new NullPointerException(message);
}
// Ensure systemId is not null.
return m_resolver.resolveResource(type,
namespaceUri,
publicId,
(systemId == null)? "" : systemId,
baseUri);
}
}
and modified variant of ./foo/Foo.java called ./foo/Bar.java that uses foo.Resolver
package foo;
import java.io.File;
import java.io.StringWriter;
import java.net.URL;
import java.net.URI;
import java.net.URISyntaxException;
import javax.xml.XMLConstants;
import javax.xml.catalog.CatalogFeatures;
import javax.xml.catalog.CatalogManager;
import javax.xml.catalog.CatalogResolver;
import javax.xml.transform.stream.StreamSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Schema;
import javax.xml.validation.Validator;
import org.w3c.dom.ls.LSInput;
public class Bar
{
public static void main(String[] args)
{
final String catalogFile = CatalogFeatures.Feature.FILES.getPropertyName();
final String catalogPath = "foo/catalog.xml";
final ClassLoader classLoader = Foo.class.getClassLoader();
try
{
final URL catalogUrl = classLoader.getResource(catalogPath);
final URI catalog = catalogUrl.toURI();
if (catalog != null)
{
CatalogFeatures features = CatalogFeatures.builder()
//.with(Feature.FILES, catalog.toString())
.with(CatalogFeatures.Feature.PREFER, "public")
.with(CatalogFeatures.Feature.DEFER, "true")
.with(CatalogFeatures.Feature.RESOLVE, "strict")
.build();
CatalogResolver resolver = CatalogManager.catalogResolver(features,
catalog);
Resolver wrapper = new Resolver(resolver);
SchemaFactory schemaFactory =
SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
schemaFactory.setResourceResolver(wrapper);
Schema schema = schemaFactory.newSchema();
StreamSource source = new StreamSource(new File("xyzzy.xml"));
Validator validator = schema.newValidator();
validator.setProperty(catalogFile, catalog.toString());
validator.setResourceResolver(wrapper);
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
validator.validate(source, result);
System.out.println(writer);
/*
*/
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
FREQUENCY : always