Skip to content

Commit 571340b

Browse files
belingueresrfscholte
authored andcommitted
#51: PrettyPrintXMLWriter fails with a java.util.NoSuchElementException (Java 1.7 only) (#52)
1 parent b762b99 commit 571340b

File tree

2 files changed

+83
-1
lines changed

2 files changed

+83
-1
lines changed

src/main/java/org/codehaus/plexus/util/xml/PrettyPrintXMLWriter.java

+8-1
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,14 @@ public void endElement()
304304
{
305305
finishTag();
306306

307-
write( "</" + elementStack.removeLast() + ">" );
307+
// see issue #51: https://github.com/codehaus-plexus/plexus-utils/issues/51
308+
// Rationale: replaced 1 write() with string concatenations with 3 write()
309+
// (this avoids the string concatenation optimization bug detected in Java 7)
310+
// TODO: change the below code to a more efficient expression when the library
311+
// be ready to target Java 8.
312+
write( "</" );
313+
write( elementStack.removeLast() );
314+
write( ">" );
308315
}
309316

310317
readyForNewLine = true;

src/test/java/org/codehaus/plexus/util/xml/PrettyPrintXMLWriterTest.java

+75
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,12 @@
1616
* limitations under the License.
1717
*/
1818

19+
import java.io.File;
20+
import java.io.FileOutputStream;
21+
import java.io.IOException;
22+
import java.io.OutputStreamWriter;
1923
import java.io.StringWriter;
24+
import java.util.NoSuchElementException;
2025

2126
import javax.swing.text.html.HTML.Tag;
2227

@@ -28,6 +33,7 @@
2833
* Test of {@link PrettyPrintXMLWriter}
2934
*
3035
* @author <a href="mailto:[email protected]">Vincent Siveton</a>
36+
* @author <a href="mailto:[email protected]">Gabriel Belingueres</a>
3137
* @version $Id$
3238
*/
3339
public class PrettyPrintXMLWriterTest
@@ -128,6 +134,75 @@ public void testEscapeXmlAttribute()
128134
assertEquals( "<div class=\"sect&#10;ion\"/>", w.toString() );
129135
}
130136

137+
public void testendElementAlreadyClosed()
138+
{
139+
try
140+
{
141+
writer.startElement( Tag.DIV.toString() );
142+
writer.addAttribute( "class", "someattribute" );
143+
writer.endElement(); // Tag.DIV closed
144+
writer.endElement(); // Tag.DIV already closed, and there is no other outer tag!
145+
fail( "Should throw a NoSuchElementException" );
146+
}
147+
catch ( NoSuchElementException e )
148+
{
149+
assert ( true );
150+
}
151+
}
152+
153+
/**
154+
* Issue #51: https://github.com/codehaus-plexus/plexus-utils/issues/51
155+
*
156+
* Purpose: test if concatenation string optimization bug is present.
157+
*
158+
* Target environment: Java 7 (u79 and u80 verified) running on Windows.
159+
*
160+
* Detection strategy: Tries to build a big XML file (~750MB size) and with
161+
* many nested tags to force the JVM to trigger the concatenation string
162+
* optimization bug that throws a NoSuchElementException when calling
163+
* endElement() method.
164+
*
165+
* @throws IOException if an I/O error occurs
166+
*/
167+
public void testIssue51DetectJava7ConcatenationBug()
168+
throws IOException
169+
{
170+
File dir = new File( "target/test-xml" );
171+
if ( !dir.exists() )
172+
{
173+
assertTrue( "cannot create directory test-xml", dir.mkdir() );
174+
}
175+
File xmlFile = new File( dir, "test-issue-51.xml" );
176+
OutputStreamWriter osw = new OutputStreamWriter( new FileOutputStream( xmlFile ), "UTF-8" );
177+
writer = new PrettyPrintXMLWriter( osw );
178+
179+
int iterations = 20000;
180+
181+
try
182+
{
183+
for ( int i = 0; i < iterations; ++i )
184+
{
185+
writer.startElement( Tag.DIV.toString() + i );
186+
writer.addAttribute( "class", "someattribute" );
187+
}
188+
for ( int i = 0; i < iterations; ++i )
189+
{
190+
writer.endElement(); // closes Tag.DIV + i
191+
}
192+
}
193+
catch ( NoSuchElementException e )
194+
{
195+
fail( "Should not throw a NoSuchElementException" );
196+
}
197+
finally
198+
{
199+
if ( osw != null )
200+
{
201+
osw.close();
202+
}
203+
}
204+
}
205+
131206
private void writeXhtmlHead( XMLWriter writer )
132207
{
133208
writer.startElement( Tag.HEAD.toString() );

0 commit comments

Comments
 (0)