# HG changeset patch # User joehw # Date 1477931345 25200 # Node ID dd1e92025fd37a9a67732c1d32bdf28d5e6fe59b # Parent 59246c0a32997a9134715d3e3f7de0e747c357c1 8069098: StAX produces the wrong event stream Reviewed-by: lancea diff -r 59246c0a3299 -r dd1e92025fd3 jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentScannerImpl.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; } diff -r 59246c0a3299 -r dd1e92025fd3 jaxp/src/java.xml/share/classes/javax/xml/stream/XMLEventReader.java --- 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; diff -r 59246c0a3299 -r dd1e92025fd3 jaxp/src/java.xml/share/classes/javax/xml/stream/XMLStreamReader.java --- 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. * - *

The XMLStreamReader is designed to iterate over XML using + *

+ * 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(); * - *

The next() method causes the reader to read the next parse event. - * The next() method returns an integer which identifies the type of event just read. - *

The event type can be determined using getEventType(). - *

Parsing events are defined as the XML Declaration, a DTD, + *

+ * 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. + * + *

+ * 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. * - *

For XML 1.0 compliance an XML processor must pass the + *

+ * 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. * - *

The following table describes which methods are valid in what state. + *

+ * 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(); diff -r 59246c0a3299 -r dd1e92025fd3 jaxp/test/javax/xml/jaxp/unittest/stream/XMLStreamReaderTest/BugTest.java --- 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("")); - 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[][]{ + {"", + XMLStreamConstants.START_DOCUMENT, XMLStreamConstants.START_ELEMENT}, + {"", + XMLStreamConstants.START_DOCUMENT, XMLStreamConstants.START_ELEMENT}, + {"" + + "" + + "", + XMLStreamConstants.START_DOCUMENT, XMLStreamConstants.PROCESSING_INSTRUCTION}, + {"" + + "", + XMLStreamConstants.START_DOCUMENT, XMLStreamConstants.PROCESSING_INSTRUCTION}, + }; } }