8069098: StAX produces the wrong event stream
authorjoehw
Mon, 31 Oct 2016 09:29:05 -0700
changeset 41846 dd1e92025fd3
parent 41845 59246c0a3299
child 41847 e444f2f9dc8a
8069098: StAX produces the wrong event stream Reviewed-by: lancea
jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentScannerImpl.java
jaxp/src/java.xml/share/classes/javax/xml/stream/XMLEventReader.java
jaxp/src/java.xml/share/classes/javax/xml/stream/XMLStreamReader.java
jaxp/test/javax/xml/jaxp/unittest/stream/XMLStreamReaderTest/BugTest.java
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentScannerImpl.java	Thu Oct 27 16:29:00 2016 +0000
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentScannerImpl.java	Mon Oct 31 09:29:05 2016 -0700
@@ -746,42 +746,18 @@
             // scan XMLDecl
             try {
                 if (fEntityScanner.skipString(xmlDecl)) {
-                    fMarkupDepth++;
-                    // NOTE: special case where document starts with a PI
-                    //       whose name starts with "xml" (e.g. "xmlfoo")
-                    if (XMLChar.isName(fEntityScanner.peekChar())) {
-                        fStringBuffer.clear();
-                        fStringBuffer.append("xml");
-                        while (XMLChar.isName(fEntityScanner.peekChar())) {
-                            fStringBuffer.append((char)fEntityScanner.scanChar(null));
-                        }
-                        String target = fSymbolTable.addSymbol(fStringBuffer.ch, fStringBuffer.offset, fStringBuffer.length);
-                        //this function should fill the data.. and set the fEvent object to this event.
-                        fContentBuffer.clear() ;
-                        scanPIData(target, fContentBuffer);
-                        //REVISIT:where else we can set this value to 'true'
-                        fEntityManager.fCurrentEntity.mayReadChunks = true;
-                        //return PI event since PI was encountered
-                        return XMLEvent.PROCESSING_INSTRUCTION ;
+                    if (fEntityScanner.peekChar() == ' ') {
+                        fMarkupDepth++;
+                        scanXMLDeclOrTextDecl(false);
+                    } else {
+                        // PI, reset position
+                        fEntityManager.fCurrentEntity.position = 0;
                     }
-                    // standard XML declaration
-                    else {
-                        scanXMLDeclOrTextDecl(false);
-                        //REVISIT:where else we can set this value to 'true'
-                        fEntityManager.fCurrentEntity.mayReadChunks = true;
-                        return XMLEvent.START_DOCUMENT;
-                    }
-                } else{
-                    //REVISIT:where else we can set this value to 'true'
-                    fEntityManager.fCurrentEntity.mayReadChunks = true;
-                    //In both case return the START_DOCUMENT. ony difference is that first block will
-                    //cosume the XML declaration if any.
-                    return XMLEvent.START_DOCUMENT;
                 }
 
-
                 //START_OF_THE_DOCUMENT
-
+                fEntityManager.fCurrentEntity.mayReadChunks = true;
+                return XMLEvent.START_DOCUMENT;
 
             }
 
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLEventReader.java	Thu Oct 27 16:29:00 2016 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLEventReader.java	Mon Oct 31 09:29:05 2016 -0700
@@ -46,7 +46,10 @@
  */
 public interface XMLEventReader extends Iterator {
   /**
-   * Get the next XMLEvent
+   * Gets the next XMLEvent. The initial event is
+   * {@link javax.xml.stream.events.StartDocument StartDocument}.
+   *
+   * @return the next XMLEvent
    * @see XMLEvent
    * @throws XMLStreamException if there is an error with the underlying XML.
    * @throws java.util.NoSuchElementException iteration has no more elements.
@@ -58,12 +61,15 @@
    * Returns true if there are more events and false otherwise.
    * @return true if the event reader has more events, false otherwise
    */
+  @Override
   public boolean hasNext();
 
   /**
    * Check the next XMLEvent without reading it from the stream.
    * Returns null if the stream is at EOF or has no more XMLEvents.
    * A call to peek() will be equal to the next return of next().
+   *
+   * @return the next XMLEvent
    * @see XMLEvent
    * @throws XMLStreamException
    */
@@ -73,6 +79,8 @@
    * Reads the content of a text-only element. Precondition:
    * the current event is START_ELEMENT. Postcondition:
    * The current event is the corresponding END_ELEMENT.
+   *
+   * @return the text of the element
    * @throws XMLStreamException if the current event is not a START_ELEMENT
    * or if a non text element is encountered
    */
@@ -85,6 +93,8 @@
    * be used when processing element-only content because
    * the parser is not able to recognize ignorable whitespace if
    * the DTD is missing or not interpreted.
+   *
+   * @return a START_ELEMENT or END_ELEMENT
    * @throws XMLStreamException if anything other than space characters are encountered
    */
   public XMLEvent nextTag() throws XMLStreamException;
--- a/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLStreamReader.java	Thu Oct 27 16:29:00 2016 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/stream/XMLStreamReader.java	Mon Oct 31 09:29:05 2016 -0700
@@ -28,7 +28,6 @@
 
 package javax.xml.stream;
 
-import java.io.Reader;
 import javax.xml.namespace.NamespaceContext;
 import javax.xml.namespace.QName;
 
@@ -37,19 +36,26 @@
  *  It is designed to be the lowest level and most efficient way to
  *  read XML data.
  *
- * <p> The XMLStreamReader is designed to iterate over XML using
+ * <p>
+ * The XMLStreamReader is designed to iterate over XML using
  * next() and hasNext().  The data can be accessed using methods such as getEventType(),
  * getNamespaceURI(), getLocalName() and getText();
  *
- * <p> The <a href="#next()">next()</a> method causes the reader to read the next parse event.
- * The next() method returns an integer which identifies the type of event just read.
- * <p> The event type can be determined using <a href="#getEventType()">getEventType()</a>.
- * <p> Parsing events are defined as the XML Declaration, a DTD,
+ * <p>
+ * An XMLStreamReader instance is created with an initial event type START_DOCUMENT.
+ * At any moment in time, it has a current event that the methods of the interface
+ * access and may load the next event through the {@link #next() next()} method.
+ * The current event type can be determined by {@link #getEventType getEventType()}, and
+ * the next returned by the {@link #next() next()} method.
+ *
+ * <p>
+ * Parsing events are defined as the XML Declaration, a DTD,
  * start tag, character data, white space, end tag, comment,
  * or processing instruction.  An attribute or namespace event may be encountered
  * at the root level of a document as the result of a query operation.
  *
- * <p>For XML 1.0 compliance an XML processor must pass the
+ * <p>
+ * For XML 1.0 compliance an XML processor must pass the
  * identifiers of declared unparsed entities, notation declarations and their
  * associated identifiers to the application.  This information is
  * provided through the property API on this interface.
@@ -63,7 +69,8 @@
  * These properties can only be accessed during a DTD event and
  * are defined to return null if the information is not available.
  *
- * <p>The following table describes which methods are valid in what state.
+ * <p>
+ * The following table describes which methods are valid in what state.
  * If a method is called in an invalid state the method will throw a
  * java.lang.IllegalStateException.
  *
@@ -502,8 +509,10 @@
   //  public void recycle() throws XMLStreamException;
 
   /**
-   * Returns an integer code that indicates the type
-   * of the event the cursor is pointing to.
+   * Returns an integer code that indicates the type of the event the cursor is
+   * pointing to. The initial event type is {@link #START_DOCUMENT}.
+   *
+   * @return the type of the current event
    */
   public int getEventType();
 
@@ -590,6 +599,8 @@
   /**
    * Returns the offset into the text character array where the first
    * character (of this text event) is stored.
+   *
+   * @return the starting position of the text in the character array
    * @throws java.lang.IllegalStateException if this state is not
    * a valid text state.
    */
@@ -598,6 +609,8 @@
   /**
    * Returns the length of the sequence of characters for this
    * Text event within the text character array.
+   *
+   * @return the length of the text
    * @throws java.lang.IllegalStateException if this state is not
    * a valid text state.
    */
@@ -610,9 +623,11 @@
   public String getEncoding();
 
   /**
-   * Return true if the current event has text, false otherwise
+   * Return a boolean indicating whether the current event has text.
    * The following events have text:
    * CHARACTERS,DTD ,ENTITY_REFERENCE, COMMENT, SPACE
+   *
+   * @return true if the event has text, false otherwise
    */
   public boolean hasText();
 
@@ -623,6 +638,7 @@
    * location and null for the publicId and systemId.
    * The location information is only valid until next() is
    * called.
+   * @return the location of the cursor
    */
   public Location getLocation();
 
@@ -647,8 +663,10 @@
   public String getLocalName();
 
   /**
-   * returns true if the current event has a name (is a START_ELEMENT or END_ELEMENT)
-   * returns false otherwise
+   * returns a boolean indicating whether the current event has a name
+   * (is a START_ELEMENT or END_ELEMENT).
+   *
+   * @return true if the event has a name, false otherwise
    */
   public boolean hasName();
 
--- a/jaxp/test/javax/xml/jaxp/unittest/stream/XMLStreamReaderTest/BugTest.java	Thu Oct 27 16:29:00 2016 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/stream/XMLStreamReaderTest/BugTest.java	Mon Oct 31 09:29:05 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,17 +24,20 @@
 package stream.XMLStreamReaderTest;
 
 import java.io.StringReader;
+import javax.xml.stream.XMLEventReader;
 
 import javax.xml.stream.XMLInputFactory;
 import javax.xml.stream.XMLStreamConstants;
 import javax.xml.stream.XMLStreamReader;
 
 import org.testng.Assert;
+import org.testng.annotations.DataProvider;
 import org.testng.annotations.Listeners;
 import org.testng.annotations.Test;
 
 /*
  * @test
+ * @bug 8069098
  * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
  * @run testng/othervm -DrunSecMngr=true stream.XMLStreamReaderTest.BugTest
  * @run testng/othervm stream.XMLStreamReaderTest.BugTest
@@ -43,11 +46,70 @@
 @Listeners({jaxp.library.BasePolicy.class})
 public class BugTest {
 
-    @Test
-    public static void test1() throws Exception {
-        XMLInputFactory xif = XMLInputFactory.newInstance(); // new
-                                                             // com.sun.xml.stream.ZephyrParserFactory();
-        XMLStreamReader r = xif.createXMLStreamReader(new StringReader("<foo/>"));
-        Assert.assertEquals(XMLStreamConstants.START_DOCUMENT, r.getEventType());
+    /**
+     * Verifies that the initial event of an XMLStreamReader instance is
+     * START_DOCUMENT.
+     *
+     * @param xml the xml input
+     * @param type1 the type of the 1st event
+     * @param type2 the type of the 2nd event
+     * @throws Exception if the test fails to run properly
+     */
+    @Test(dataProvider = "xmls")
+    public static void test1(String xml, int type1, int type2) throws Exception {
+       XMLInputFactory factory = XMLInputFactory.newFactory();
+
+       XMLStreamReader reader = factory.createXMLStreamReader(new StringReader(xml));
+       int type1stEvent = reader.getEventType();
+       int type2ndEvent = reader.next();
+       System.out.println("First event: " + type1stEvent);
+       System.out.println("2nd event: " + type2ndEvent);
+       Assert.assertEquals(type1, type1stEvent);
+       Assert.assertEquals(type2, type2ndEvent);
+    }
+
+
+    /**
+     * Verifies that the initial event of an XMLEventReader instance is
+     * START_DOCUMENT. XMLEventReader depends on XMLStreamReader.
+     *
+     * @param xml the xml input
+     * @param type1 the type of the 1st event
+     * @param type2 the type of the 2nd event
+     * @throws Exception if the test fails to run properly
+     */
+    @Test(dataProvider = "xmls")
+    public static void test2(String xml, int type1, int type2) throws Exception {
+       XMLInputFactory factory = XMLInputFactory.newFactory();
+
+       XMLEventReader reader = factory.createXMLEventReader(new StringReader(xml));
+       int type1stEvent = reader.nextEvent().getEventType();
+       int type2ndEvent = reader.nextEvent().getEventType();
+       System.out.println("First event: " + type1stEvent);
+       System.out.println("2nd event: " + type2ndEvent);
+       Assert.assertEquals(type1, type1stEvent);
+       Assert.assertEquals(type2, type2ndEvent);
+    }
+
+    /*
+       DataProvider: for testing beginning event type
+       Data: xml, 1st event type, 2nd event type
+     */
+    @DataProvider(name = "xmls")
+    public Object[][] getXMLs() {
+
+        return new Object[][]{
+            {"<?xml version='1.0'?><foo/>",
+                XMLStreamConstants.START_DOCUMENT, XMLStreamConstants.START_ELEMENT},
+            {"<foo/>",
+                XMLStreamConstants.START_DOCUMENT, XMLStreamConstants.START_ELEMENT},
+            {"<?xml version='1.0'?>"
+                + "<?xml-stylesheet href=\"bar.xsl\" type=\"text/xsl\"?>" +
+                    "<foo/>",
+                XMLStreamConstants.START_DOCUMENT, XMLStreamConstants.PROCESSING_INSTRUCTION},
+            {"<?xml-stylesheet href=\"bar.xsl\" type=\"text/xsl\"?>" +
+                    "<foo/>",
+                XMLStreamConstants.START_DOCUMENT, XMLStreamConstants.PROCESSING_INSTRUCTION},
+        };
     }
 }