From 9bffd1e3762ebd8c149b9fd3e7cf3837c7528167 Mon Sep 17 00:00:00 2001 From: Scott Steen Date: Fri, 10 Feb 2023 14:36:20 +0000 Subject: [PATCH] Encode transformed properties files with specified Charset Currently, the content from any properties file that is passed through the `PropertiesFileTransformer` will have its output written into the jar encoded as `ISO_8859_1`. If the source file contains UTF-8 content, the output becomes corrupted. This commit allows the buildscript to define the Charset to perform the transformation with. --- .../PropertiesFileTransformer.groovy | 19 ++++++++++++++----- .../PropertiesFileTransformerSpec.groovy | 19 +++++++++++++++++++ .../TransformerSpecSupport.groovy | 10 ++++++---- 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformer.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformer.groovy index 31e1a5452..1f61777c3 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformer.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformer.groovy @@ -131,6 +131,9 @@ class PropertiesFileTransformer implements Transformer { @Input String mergeSeparator = ',' + @Input + String charset = 'ISO_8859_1' + @Internal Closure keyTransformer = IDENTITY @@ -180,7 +183,8 @@ class PropertiesFileTransformer implements Transformer { private Properties loadAndTransformKeys(InputStream is) { Properties props = new Properties() - props.load(is) + // InputStream closed by caller, so we don't do it here. + props.load(new InputStreamReader(is, charset)) return transformKeys(props) } @@ -227,18 +231,23 @@ class PropertiesFileTransformer implements Transformer { @Override void modifyOutputStream(ZipOutputStream os, boolean preserveFileTimestamps) { + // cannot close the writer as the OutputStream needs to remain open + def zipWriter = new OutputStreamWriter(os, charset) propertiesEntries.each { String path, Properties props -> ZipEntry entry = new ZipEntry(path) entry.time = TransformerContext.getEntryTimestamp(preserveFileTimestamps, entry.time) os.putNextEntry(entry) - IOUtil.copy(toInputStream(props), os) + IOUtil.copy(readerFor(props, charset), zipWriter) + zipWriter.flush() os.closeEntry() } } - private static InputStream toInputStream(Properties props) { + private static InputStreamReader readerFor(Properties props, String charset) { ByteArrayOutputStream baos = new ByteArrayOutputStream() - props.store(baos, '') - new ByteArrayInputStream(baos.toByteArray()) + baos.withWriter(charset) { w -> + props.store(w, '') + } + new InputStreamReader(new ByteArrayInputStream(baos.toByteArray()), charset) } } diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformerSpec.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformerSpec.groovy index 4ebf74851..333048ac4 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformerSpec.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformerSpec.groovy @@ -142,4 +142,23 @@ class PropertiesFileTransformerSpec extends TransformerSpecSupport { 'foo.properties' | { key -> 'bar.' + key.toLowerCase() } | ['foo': 'bar'] | ['FOO': 'baz'] || ['bar.foo': 'bar,baz'] 'foo.properties' | { key -> key.replaceAll('^(foo)', 'bar.$1') } | ['foo': 'bar'] | ['FOO': 'baz'] || ['bar.foo': 'bar', 'FOO': 'baz'] } + + void appliesCharset() { + given: + def element = getFileElement(path) + def transformer = new PropertiesFileTransformer() + transformer.charset = charset + + when: + if (transformer.canTransformResource(element)) { + transformer.transform(context(path, input, charset)) + } + + then: + output == toMap(transformer.propertiesEntries[path]) + + where: + path | charset | input || output + 'utf8.properties' | 'utf-8' | ['foo': '传傳磨宿说説'] || ['foo': '传傳磨宿说説'] + } } diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/TransformerSpecSupport.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/TransformerSpecSupport.groovy index 51a9305b7..fe030d0bd 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/TransformerSpecSupport.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/TransformerSpecSupport.groovy @@ -24,9 +24,11 @@ class TransformerSpecSupport extends Specification { return new ByteArrayInputStream(str.bytes) } - protected static InputStream toInputStream(Properties props) { + protected static InputStream toInputStream(Properties props, String charset) { ByteArrayOutputStream baos = new ByteArrayOutputStream() - props.store(baos, '') + baos.withWriter(charset) { w -> + props.store(w, '') + } new ByteArrayInputStream(baos.toByteArray()) } @@ -44,8 +46,8 @@ class TransformerSpecSupport extends Specification { } } - protected TransformerContext context(String path, Map input) { - TransformerContext.builder().path(path).is(toInputStream(toProperties(input))).relocators([]).stats(stats).build() + protected TransformerContext context(String path, Map input, String charset = 'ISO_8859_1') { + TransformerContext.builder().path(path).is(toInputStream(toProperties(input), charset)).relocators([]).stats(stats).build() } protected TransformerContext context(String path, String input) {