JDK-8230094 : CCE in createXMLEventWriter(Result) over an arbitrary XMLStreamWriter
  • Type: Bug
  • Component: xml
  • Sub-Component: javax.xml.stream
  • Affected Version: 9,11,12,13,14
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: linux
  • CPU: x86_64
  • Submitted: 2019-08-20
  • Updated: 2020-08-28
  • Resolved: 2019-08-28
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 11 JDK 13 JDK 14
11.0.10-oracleFixed 13.0.5Fixed 14 b12Fixed
Description
ADDITIONAL SYSTEM INFORMATION :
The "Operating System" dropdown does not have an "OS independent" option. The links given above to the regressed code are in shared, OS-independent class sources.

A DESCRIPTION OF THE PROBLEM :
Through Java 8, it is possible to create an XMLEventWriter over an arbitrary class that implements XMLStreamWriter, by wrapping the XMLStreamWriter instance in a StAXResult and using XMLOutputFactory.createXMLEventWriter(Result).

Starting with Java 9, the same code produces a ClassCastException trying to cast the XMLStreamWriter instance to an inaccessible internal class XMLStreamWriterBase.

The pre-Java 9 code:
http://hg.openjdk.java.net/jdk8u/jdk8u/jaxp/file/2b9fdc450085/src/com/sun/xml/internal/stream/writers/XMLEventWriterImpl.java#l59

The Java 9 and later code:
http://hg.openjdk.java.net/jdk9/jdk9/jaxp/file/364631d8ff2e/src/java.xml/share/classes/com/sun/xml/internal/stream/writers/XMLEventWriterImpl.java#l62

REGRESSION : Last worked in version 8u201

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile the attached source code with javac and run it with 

java EventWriterOverStreamWriter

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Successful exit with no output
ACTUAL -
Exception in thread "main" java.lang.ClassCastException: class EventWriterOverStreamWriter$StreamWriterFilter cannot be cast to class com.sun.xml.internal.stream.writers.XMLStreamWriterBase (EventWriterOverStreamWriter$StreamWriterFilter is in unnamed module of loader 'app'; com.sun.xml.internal.stream.writers.XMLStreamWriterBase is in module java.xml of loader 'bootstrap')
	at java.xml/com.sun.xml.internal.stream.writers.XMLEventWriterImpl.<init>(XMLEventWriterImpl.java:62)
	at java.xml/com.sun.xml.internal.stream.XMLOutputFactoryImpl.createXMLEventWriter(XMLOutputFactoryImpl.java:83)
	at EventWriterOverStreamWriter.main(EventWriterOverStreamWriter.java:15)

---------- BEGIN SOURCE ----------
import javax.xml.namespace.NamespaceContext;

import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.stream.XMLStreamException;

import javax.xml.transform.stax.StAXResult;

public class EventWriterOverStreamWriter
{
  public static void main(String[] args) throws XMLStreamException
  {
    XMLOutputFactory.newFactory()
      .createXMLEventWriter(new StAXResult(new StreamWriterFilter()));
  }

  static class StreamWriterFilter implements XMLStreamWriter
  {
    @Override
    public void writeStartElement(String localName)
      throws XMLStreamException
    {
    }

    @Override
    public void writeStartElement(String namespaceURI, String localName)
      throws XMLStreamException
    {
    }

    @Override
    public void writeStartElement(
      String prefix, String localName, String namespaceURI)
      throws XMLStreamException
    {
    }

    @Override
    public void writeEmptyElement(String namespaceURI, String localName)
      throws XMLStreamException
    {
    }

    @Override
    public void writeEmptyElement(
      String prefix, String localName, String namespaceURI)
      throws XMLStreamException
    {
    }

    @Override
    public void writeEmptyElement(String localName)
      throws XMLStreamException
    {
    }

    @Override
    public void writeEndElement() throws XMLStreamException
    {
    }

    @Override
    public void writeEndDocument() throws XMLStreamException
    {
    }

    @Override
    public void close() throws XMLStreamException
    {
    }

    @Override
    public void flush() throws XMLStreamException
    {
    }

    @Override
    public void writeAttribute(String localName, String value)
      throws XMLStreamException
    {
    }

    @Override
    public void writeAttribute(
      String prefix, String namespaceURI, String localName, String value)
      throws XMLStreamException
    {
    }

    @Override
    public void writeAttribute(
      String namespaceURI, String localName, String value)
      throws XMLStreamException
    {
    }

    @Override
    public void writeNamespace(String prefix, String namespaceURI)
      throws XMLStreamException
    {
    }

    @Override
    public void writeDefaultNamespace(String namespaceURI)
      throws XMLStreamException
    {
    }

    @Override
    public void writeComment(String data) throws XMLStreamException
    {
    }

    @Override
    public void writeProcessingInstruction(String target)
      throws XMLStreamException
    {
    }

    @Override
    public void writeProcessingInstruction(String target, String data)
      throws XMLStreamException
    {
    }

    @Override
    public void writeCData(String data) throws XMLStreamException
    {
    }

    @Override
    public void writeDTD(String dtd) throws XMLStreamException
    {
    }

    @Override
    public void writeEntityRef(String name) throws XMLStreamException
    {
    }

    @Override
    public void writeStartDocument() throws XMLStreamException
    {
    }

    @Override
    public void writeStartDocument(String version) throws XMLStreamException
    {
    }

    @Override
    public void writeStartDocument(String encoding, String version)
      throws XMLStreamException
    {
    }

    @Override
    public void writeCharacters(String text) throws XMLStreamException
    {
    }

    @Override
    public void writeCharacters(char[] text, int start, int len)
      throws XMLStreamException
    {
    }

    @Override
    public String getPrefix(String uri) throws XMLStreamException
    {
      return null;
    }

    @Override
    public void setPrefix(String prefix, String uri)
      throws XMLStreamException
    {
    }

    @Override
    public void setDefaultNamespace(String uri) throws XMLStreamException
    {
    }

    @Override
    public void setNamespaceContext(NamespaceContext context)
      throws XMLStreamException
    {
    }

    @Override
    public NamespaceContext getNamespaceContext()
    {
      throw new UnsupportedOperationException();
    }

    @Override
    public Object getProperty(String name) throws IllegalArgumentException
    {
      throw new UnsupportedOperationException();
    }
  }
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
None as far as I know, other than for the application developer to bundle a complete reimplementation of the pre-Java 9 XMLEventWriterImpl logic when writing to an XMLStreamWriter instance.

Even after the regression is fixed, developers will have to bundle the duplicated code in order to support non-updated platforms. It might be appropriate for the project to consider making a version of that class's source code available under a nonrestrictive license.

FREQUENCY : always



Comments
Fix request (13u) We should fix this regression in 13u as well. Patch applies cleanly. Tier1,2,3 tests pass with the patch.
28-08-2020

Fix Request (11u) This fixes the regression in 9. Patch applies cleanly to 11u. New test fails without the patch, passes with it. Additionally, tier{1,2} pass with the patch.
10-08-2020

URL: https://hg.openjdk.java.net/jdk/jdk/rev/8570f22b9b6a User: joehw Date: 2019-08-28 19:03:42 +0000
28-08-2019

To reproduce the issue, run the attached test case : JDK 8u221 - Pass JDK 9 GA - Fail JDK 11 - Fail JDK 12- Fail JDK 13- Fail JDK 14 - Fail Output: Exception in thread "main" java.lang.ClassCastException: class JI9062000$StreamWriterFilter cannot be cast to class com.sun.xml.internal.stream.writers.XMLStreamWriterBase (JI9062000$StreamWriterFilter is in unnamed module of loader 'app'; com.sun.xml.internal.stream.writers.XMLStreamWriterBase is in module java.xml of loader 'bootstrap') at java.xml/com.sun.xml.internal.stream.writers.XMLEventWriterImpl.<init>(XMLEventWriterImpl.java:62) at java.xml/com.sun.xml.internal.stream.XMLOutputFactoryImpl.createXMLEventWriter(XMLOutputFactoryImpl.java:83) at JI9062000.main(JI9062000.java:14)
23-08-2019