diff --git a/src/main/java/org/codehaus/plexus/util/xml/PrettyPrintXMLWriter.java b/src/main/java/org/codehaus/plexus/util/xml/PrettyPrintXMLWriter.java index 234767cd..9710a6f7 100644 --- a/src/main/java/org/codehaus/plexus/util/xml/PrettyPrintXMLWriter.java +++ b/src/main/java/org/codehaus/plexus/util/xml/PrettyPrintXMLWriter.java @@ -304,7 +304,14 @@ public void endElement() { finishTag(); - write( "" ); + // see issue #51: https://github.com/codehaus-plexus/plexus-utils/issues/51 + // Rationale: replaced 1 write() with string concatenations with 3 write() + // (this avoids the string concatenation optimization bug detected in Java 7) + // TODO: change the below code to a more efficient expression when the library + // be ready to target Java 8. + write( "" ); } readyForNewLine = true; diff --git a/src/test/java/org/codehaus/plexus/util/xml/PrettyPrintXMLWriterTest.java b/src/test/java/org/codehaus/plexus/util/xml/PrettyPrintXMLWriterTest.java index 59ef561d..23f37894 100644 --- a/src/test/java/org/codehaus/plexus/util/xml/PrettyPrintXMLWriterTest.java +++ b/src/test/java/org/codehaus/plexus/util/xml/PrettyPrintXMLWriterTest.java @@ -16,7 +16,12 @@ * limitations under the License. */ +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; import java.io.StringWriter; +import java.util.NoSuchElementException; import javax.swing.text.html.HTML.Tag; @@ -28,6 +33,7 @@ * Test of {@link PrettyPrintXMLWriter} * * @author Vincent Siveton + * @author Gabriel Belingueres * @version $Id$ */ public class PrettyPrintXMLWriterTest @@ -128,6 +134,75 @@ public void testEscapeXmlAttribute() assertEquals( "
", w.toString() ); } + public void testendElementAlreadyClosed() + { + try + { + writer.startElement( Tag.DIV.toString() ); + writer.addAttribute( "class", "someattribute" ); + writer.endElement(); // Tag.DIV closed + writer.endElement(); // Tag.DIV already closed, and there is no other outer tag! + fail( "Should throw a NoSuchElementException" ); + } + catch ( NoSuchElementException e ) + { + assert ( true ); + } + } + + /** + * Issue #51: https://github.com/codehaus-plexus/plexus-utils/issues/51 + * + * Purpose: test if concatenation string optimization bug is present. + * + * Target environment: Java 7 (u79 and u80 verified) running on Windows. + * + * Detection strategy: Tries to build a big XML file (~750MB size) and with + * many nested tags to force the JVM to trigger the concatenation string + * optimization bug that throws a NoSuchElementException when calling + * endElement() method. + * + * @throws IOException if an I/O error occurs + */ + public void testIssue51DetectJava7ConcatenationBug() + throws IOException + { + File dir = new File( "target/test-xml" ); + if ( !dir.exists() ) + { + assertTrue( "cannot create directory test-xml", dir.mkdir() ); + } + File xmlFile = new File( dir, "test-issue-51.xml" ); + OutputStreamWriter osw = new OutputStreamWriter( new FileOutputStream( xmlFile ), "UTF-8" ); + writer = new PrettyPrintXMLWriter( osw ); + + int iterations = 20000; + + try + { + for ( int i = 0; i < iterations; ++i ) + { + writer.startElement( Tag.DIV.toString() + i ); + writer.addAttribute( "class", "someattribute" ); + } + for ( int i = 0; i < iterations; ++i ) + { + writer.endElement(); // closes Tag.DIV + i + } + } + catch ( NoSuchElementException e ) + { + fail( "Should not throw a NoSuchElementException" ); + } + finally + { + if ( osw != null ) + { + osw.close(); + } + } + } + private void writeXhtmlHead( XMLWriter writer ) { writer.startElement( Tag.HEAD.toString() );