From 74583d003a841af280e7fea8f3ae3521dfcbb89b Mon Sep 17 00:00:00 2001 From: pyxide Date: Sat, 17 Dec 2016 00:34:12 +0100 Subject: [PATCH] Ant Task Formatter encoding issue with XMLRenderer Hi, The writers in the Ant task's formatter uses the default platform's encoding (for instance cp1252 on Western Windows) and the XMLRenderer sets the default XML encoding to UTF-8. This may lead to incorrect XML encoding, detected for instance when the XML file is sent to a XSLT task. This goes undetected as long as the characters in the XML file are in the ASCII subset, which is frequently the case with code, usually in plain Latin language. In my case, the issue was raised because of the localized formatting of some line numbers greater than 999, due to localized thousand separator 0xA0, which is out of the ASCII subset. I modified the Formatter class to always use a charset for writers. When no encoding is specified, UTF-8 is used instead of the default platform's encoding. I strongly recommend to *always set the encoding parameter* of the formatter element. It should be reflected as so in the Ant Task documentation. ```xml ``` Note: when digging into sourceforge issues for similar bugs, I found [Bug 877: Output with encoding CP1252](https://sourceforge.net/p/pmd/bugs/877/) . Not the same task, but the same symptoms, probably the same cause ? --- .../net/sourceforge/pmd/ant/Formatter.java | 57 +++++++++++++++---- 1 file changed, 47 insertions(+), 10 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/ant/Formatter.java b/pmd-core/src/main/java/net/sourceforge/pmd/ant/Formatter.java index 58a83247e3..a10fb0a1b2 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/ant/Formatter.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/ant/Formatter.java @@ -5,22 +5,25 @@ package net.sourceforge.pmd.ant; import java.io.BufferedWriter; import java.io.File; -import java.io.FileWriter; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import java.util.Properties; +import org.apache.commons.io.IOUtils; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.types.Parameter; + import net.sourceforge.pmd.Report; import net.sourceforge.pmd.renderers.Renderer; import net.sourceforge.pmd.renderers.RendererFactory; import net.sourceforge.pmd.util.StringUtil; -import org.apache.tools.ant.BuildException; -import org.apache.tools.ant.types.Parameter; - public class Formatter { private File toFile; @@ -58,12 +61,27 @@ public class Formatter { } public void start(String baseDir) { + + Properties properties = createProperties(); + + Charset charset; + { + String s = (String) properties.get("encoding"); + if (null == s) { + charset = Charset.forName("UTF-8"); + properties.put("encoding", charset.name()); + } + else { + charset = Charset.forName(s); + } + } + try { if (toConsole) { - writer = new BufferedWriter(new OutputStreamWriter(System.out)); + writer = new BufferedWriter(new OutputStreamWriter(System.out, charset)); } if (toFile != null) { - writer = getToFileWriter(baseDir); + writer = getToFileWriter(baseDir, toFile, charset); } renderer = createRenderer(); renderer.setWriter(writer); @@ -133,10 +151,29 @@ public class Formatter { return properties; } - private Writer getToFileWriter(String baseDir) throws IOException { - if (!toFile.isAbsolute()) { - return new BufferedWriter(new FileWriter(new File(baseDir + System.getProperty("file.separator") + toFile.getPath()))); + private static final Writer getToFileWriter(String baseDir, File toFile, Charset charset) throws IOException { + final File file; + if (toFile.isAbsolute()) { + file = toFile; } - return new BufferedWriter(new FileWriter(toFile)); + else { + file = new File(baseDir + System.getProperty("file.separator") + toFile.getPath()); + } + + OutputStream output = null; + Writer writer = null; + boolean isOnError = true; + try { + output = new FileOutputStream(file); + writer = new OutputStreamWriter(output, charset); + writer = new BufferedWriter(writer); + isOnError = false; + } + finally { + if (isOnError) { + IOUtils.closeQuietly(output, writer); + } + } + return writer; } }