In the meantime Cayenne team member who gave me the original description fixed it in Ant and sent me a patch, attached to this message. All I can tell is that patched version completely fixes the problem and we already use it in Cayenne builds.
Andrus Adamchik http://objectstyle.org/cayenne/
diff -ur ant/org/apache/tools/ant/taskdefs/optional/junit/XMLJUnitResultFormatter.java ant-patched/org/apache/tools/ant/taskdefs/optional/junit/XMLJUnitResultFormatter.java --- ant/org/apache/tools/ant/taskdefs/optional/junit/XMLJUnitResultFormatter.java 2003-02-28 10:07:08.000000000 +0100 +++ ant-patched/org/apache/tools/ant/taskdefs/optional/junit/XMLJUnitResultFormatter.java 2003-04-03 20:17:14.000000000 +0200 @@ -54,14 +54,11 @@ package org.apache.tools.ant.taskdefs.optional.junit; +import java.io.BufferedWriter; import java.io.OutputStream; import java.io.Writer; import java.io.OutputStreamWriter; import java.io.IOException; - - - - import java.util.Properties; import java.util.Enumeration; import java.util.Hashtable; @@ -166,7 +163,7 @@ if (out != null) { Writer wri = null; try { - wri = new OutputStreamWriter(out, "UTF8"); + wri = new BufferedWriter(new OutputStreamWriter(out, "UTF8")); wri.write("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"); (new DOMElementWriter()).write(rootElement, wri, 0, " "); wri.flush(); diff -ur ant/org/apache/tools/ant/taskdefs/optional/junit/XMLResultAggregator.java ant-patched/org/apache/tools/ant/taskdefs/optional/junit/XMLResultAggregator.java --- ant/org/apache/tools/ant/taskdefs/optional/junit/XMLResultAggregator.java 2003-02-28 10:07:30.000000000 +0100 +++ ant-patched/org/apache/tools/ant/taskdefs/optional/junit/XMLResultAggregator.java 2003-03-31 00:19:34.000000000 +0200 @@ -53,30 +53,30 @@ */ package org.apache.tools.ant.taskdefs.optional.junit; +import java.io.BufferedOutputStream; +import java.io.BufferedWriter; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; - -import java.io.FileOutputStream; import java.util.Enumeration; import java.util.Vector; -import org.w3c.dom.Element; -import org.w3c.dom.Document; - - -import org.xml.sax.SAXException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; -import org.apache.tools.ant.DirectoryScanner; -import org.apache.tools.ant.BuildException; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.util.DOMElementWriter; import org.apache.tools.ant.util.StringUtils; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; /** @@ -161,17 +161,18 @@ public void execute() throws BuildException { Element rootElement = createDocument(); File destFile = getDestinationFile(); + // write the document try { writeDOMTree(rootElement.getOwnerDocument(), destFile); } catch (IOException e){ throw new BuildException("Unable to write test aggregate to '" + destFile + "'", e); } + // apply transformation Enumeration enum = transformers.elements(); while (enum.hasMoreElements()) { - AggregateTransformer transformer = - (AggregateTransformer) enum.nextElement(); + AggregateTransformer transformer = (AggregateTransformer) enum.nextElement(); transformer.setXmlDocument(rootElement.getOwnerDocument()); transformer.transform(); } @@ -232,8 +233,8 @@ OutputStream out = null; PrintWriter wri = null; try { - out = new FileOutputStream(file); - wri = new PrintWriter(new OutputStreamWriter(out, "UTF8")); + out = new BufferedOutputStream(new FileOutputStream(file)); + wri = new PrintWriter(new BufferedWriter(new OutputStreamWriter(out, "UTF8"))); wri.write("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"); (new DOMElementWriter()).write(doc.getDocumentElement(), wri, 0, " "); wri.flush(); diff -ur ant/org/apache/tools/ant/taskdefs/optional/junit/XalanExecutor.java ant-patched/org/apache/tools/ant/taskdefs/optional/junit/XalanExecutor.java --- ant/org/apache/tools/ant/taskdefs/optional/junit/XalanExecutor.java 2003-02-28 10:07:44.000000000 +0100 +++ ant-patched/org/apache/tools/ant/taskdefs/optional/junit/XalanExecutor.java 2003-04-03 20:15:22.000000000 +0200 @@ -56,6 +56,7 @@ import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; +import java.io.BufferedOutputStream; import java.io.File; import java.io.IOException; import java.io.OutputStream; @@ -83,12 +84,12 @@ /** get the appropriate stream based on the format (frames/noframes) */ protected OutputStream getOutputStream() throws IOException { - if (caller.FRAMES.equals(caller.format)){ + if (AggregateTransformer.FRAMES.equals(caller.format)){ // dummy output for the framed report // it's all done by extension... return new ByteArrayOutputStream(); } else { - return new FileOutputStream(new File(caller.toDir, "junit-noframes.html")); + return new BufferedOutputStream(new FileOutputStream(new File(caller.toDir, "junit-noframes.html"))); } } diff -ur ant/org/apache/tools/ant/util/DOMElementWriter.java ant-patched/org/apache/tools/ant/util/DOMElementWriter.java --- ant/org/apache/tools/ant/util/DOMElementWriter.java 2003-02-28 10:05:52.000000000 +0100 +++ ant-patched/org/apache/tools/ant/util/DOMElementWriter.java 2003-04-03 19:44:42.000000000 +0200 @@ -55,15 +55,15 @@ package org.apache.tools.ant.util; import java.io.IOException; -import java.io.Writer; import java.io.OutputStream; import java.io.OutputStreamWriter; +import java.io.Writer; +import org.w3c.dom.Attr; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Attr; -import org.w3c.dom.NodeList; import org.w3c.dom.Node; +import org.w3c.dom.NodeList; import org.w3c.dom.Text; /** @@ -206,7 +206,7 @@ */ public String encode(String value) { sb.setLength(0); - for (int i = 0; i < value.length(); i++) { + for (int i = 0, vlength = value.length(); i < vlength; i++) { char c = value.charAt(i); switch (c) { case '<': @@ -237,7 +237,8 @@ break; } } - return sb.toString(); + // fix for JDK 1.4.1 StringBuffer bug #4724129 + return sb.substring(0); } /** @@ -251,7 +252,6 @@ * href="http://www.w3.org/TR/1998/REC-xml-19980210#charsets">http://www.w3.org/TR/1998/REC-xml-19980210#charsets</a> and * 2.7 <a * href="http://www.w3.org/TR/1998/REC-xml-19980210#sec-cdata-sect">http://www.w3.org/TR/1998/REC-xml-19980210#sec-cdata-sect</a>.</p> - */ public String encodedata(final String value) { sb.setLength(0); @@ -262,13 +262,14 @@ } } - String result = sb.toString(); + // fix for JDK 1.4.1 StringBuffer bug #4724129 + String result = sb.substring(0); int cdEnd = result.indexOf("]]>"); while (cdEnd != -1) { sb.setLength(cdEnd); sb.append("]]>") .append(result.substring(cdEnd+3)); - result = sb.toString(); + result = sb.substring(0); cdEnd = result.indexOf("]]>"); }