Java SAX XMLFilter not recognizing final variable initialized by a method



Java 8. Eclipse Luna. I am having bizarre trouble assigning a final variable accessed by an anonymous method body.


The Background


I am validating a namespace-less XML file with my own choice of XSD schema. The file has no xmlns declaration, but the schema has a targetNamespace="mynamespace" declaration. Obviously, the file will fail validation. To make it pass validation regardless, I give a filter to the validator to force it to pretend the XML file has xmlns="mynamespace", as suggested here. See the code below.


The Problem


Notice the variable targetNamespace. If I initialize it with a string literal namespace, validation passes. If I initialize with a method call that returns the same value, validation fails.


The Code



public static void validate(byte[] xmlFile, byte[] xsdFile)
throws SAXException, IOException, XMLStreamException, FactoryConfigurationError {

final String targetNamespace = "mynamespace"; // PASS!
//final String targetNamespace = getTargetNamespace(xsdFile); // FAIL!

XMLFilter namespaceFilter = new XMLFilterImpl(XMLReaderFactory.createXMLReader()) {
@Override
public void startElement(String uri, String localName, String qName, Attributes atts)
throws SAXException {
// Make the validator think the XML file's elements have a namespace
uri = targetNamespace;

super.startElement(uri, localName, qName, atts);
}
};

Source xmlSource = new SAXSource(namespaceFilter, new InputSource(new ByteArrayInputStream(xmlFile)));
Source xsdSource = new StreamSource(new ByteArrayInputStream(xsdFile));
SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(xsdSource).newValidator().validate(xmlSource);
}

private static String getTargetNamespace(byte[] xsdFile)
throws XMLStreamException, FactoryConfigurationError {
XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(new ByteArrayInputStream(xsdFile));
while (reader.hasNext()) {
int event = reader.next();

// Get the root element's "targetNamespace" attribute
if (event == XMLEvent.START_ELEMENT) {
return reader.getAttributeValue(null, "targetNamespace");
}
}
return null;
}


The Error



cvc-complex-type.2.4.a: Invalid content was found starting with element 'childtag'. One of '{"mynamespace":childtag}' is expected.



It gets more bizarre. Validation passes when the method returns "mynamespace" as a string literal. But validation fails when the method obtains the value of "mynamespace" from the XSD file. I have verified with String.equals() that the value passed to super.startElement when validation fails is indeed exactly the same as when validation passes!


The only difference I can see here is that it passes when the value assigned to the final variable targetNamespace is ultimately a constant (the string literal), and it fails when the value assigned is ultimately determined by some condition (derived from the XSD file). Final or effectively final makes no difference.


Is this a known Java bug? Or is it my lack of understanding of initialization of variables accessed from anonymous methods? Does the XSD validation really have anything to do with it?


No comments:

Post a Comment