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( "" + elementStack.removeLast() + ">" );
+ // 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( "" );
+ write( elementStack.removeLast() );
+ 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() );