Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do I get different results with String.intern() vs. passing String object in Java?

Tags:

java

I have a command line program to validate an XML against an XSD file. One of the command line options for this program is the namespace to use, which is stored in String namespace. I get a different validation result depending on whether I pass the parsed option as namespace or pass the call to namespace.intern(). The different results mean that somewhere in the XML validator the String comparisons performed on namespace have different results, even though they should have the same set of ASCII values.

Is there a fundamental reason why these might produce different comparison results?

The NamespaceFilter class, see below, is where the namespace value is used. This class compares namespace to the value found on the current element inside startElement and then assigns it. startElement is called by the XML reader.

These are the line variations inside validateAgainstXSD:

String.intern()

NamespaceFilter nsf = new NamespaceFilter(XMLReaderFactory.createXMLReader(), namespace.intern());

Result:
Validating uart.xml.

String object as is

NamespaceFilter nsf = new NamespaceFilter(XMLReaderFactory.createXMLReader(), namespace);

Result:
Error at 4: cvc-complex-type.2.4.a: Invalid content was found starting with element 'fileVersion'. One of '{"myNamespace":fileVersion}' is expected.

Source in context

public static void validateAgainstXSD(File file, File schemaFile, String namespace) {

    try {
        SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");

        Schema xsdScheme = factory.newSchema(schemaFile);

        Validator validator = xsdScheme.newValidator();
        ErrorHandler eh = new DefaultErrorHandler();

        validator.setErrorHandler(eh);

        // Create namespace replacement filter  
        NamespaceFilter nsf = new NamespaceFilter(XMLReaderFactory.createXMLReader(), namespace.intern());

        // Load the XML source
        SAXSource source = new SAXSource(nsf, new InputSource(new FileInputStream(file)));

        validator.validate(source, null);
    } catch (Exception e) {
        e.printStackTrace();
    }

}

private static class NamespaceFilter extends XMLFilterImpl {

    private String requiredNamespace;

    public NamespaceFilter(XMLReader parent) {
        super(parent);
    }

    public NamespaceFilter(XMLReader parent, String namespace) {
        this(parent);

        requiredNamespace = namespace;
    }

    @Override
    public void startElement(String uri,
            String localName,
            String qName,
            Attributes atts)
            throws SAXException {

        if (!uri.equals(requiredNamespace)) {
            uri = requiredNamespace;
        }
        super.startElement(uri, localName, qName, atts);

    }
}
like image 974
stever Avatar asked Nov 13 '22 02:11

stever


1 Answers

You need to override endElement() as well, with similar logic in it. Otherwise the start and end element URIs may not match. XMLFilterImpl is probably matching them on == rather than .equals().

like image 122
user207421 Avatar answered Nov 16 '22 02:11

user207421