You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by gn...@apache.org on 2026/09/25 15:11:47 UTC
(maven-filtering) 03/04: Add separate input/output encoding support for resource filtering (MRESOURCES-232)
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch feat/resource-encoding
in repository https://gitbox.apache.org/repos/asf/maven-filtering.git
commit 5c3f2223792a809564d78ab2446bf1704cc7fe20
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Fri Sep 25 11:21:14 2026 +0000
Add separate input/output encoding support for resource filtering (MRESOURCES-232)
Add the ability to configure a separate output encoding when filtering resources,
enabling encoding conversion during the build (e.g. reading ISO-8859-1 / EBCDIC
sources and writing UTF-8 output).
Changes:
- FilteringUtils.copyFile(): add overload with separate inputEncoding/outputEncoding;
the single-encoding overload delegates to it for backward compatibility
- MavenFileFilter: add copyFile() overload with inputEncoding + outputEncoding;
the gracefulBinaryHandling overload delegates to the new one
- DefaultMavenFileFilter: override new overload, use separate charsets for reader/writer
- MavenResourcesExecution: add outputEncoding and outputPropertiesEncoding fields
with getters/setters and copyOf() support
- Resource: add per-resource encoding and outputEncoding fields so users can configure
encoding conversion inside a single <resource> block
- DefaultMavenResourcesFiltering: compute separate input/output encodings in the
per-file loop; per-resource values override global ones; add getOutputEncoding()
static helper (mirrors existing getEncoding())
New tests:
- getOutputEncoding(): unit-tests all fallback combinations
- filterResourcesWithOutputEncoding(): end-to-end conversion ISO-8859-1 → UTF-8
- filterResourcesWithPerResourceOutputEncoding(): per-resource override
---
.../shared/filtering/DefaultMavenFileFilter.java | 34 ++++++++-
.../filtering/DefaultMavenResourcesFiltering.java | 61 ++++++++++++---
.../maven/shared/filtering/FilteringUtils.java | 53 ++++++++++---
.../maven/shared/filtering/MavenFileFilter.java | 25 ++++++
.../shared/filtering/MavenResourcesExecution.java | 65 +++++++++++++++-
.../DefaultMavenResourcesFilteringTest.java | 89 ++++++++++++++++++++++
src/test/units-files/MRESOURCES-232/message.txt | 1 +
7 files changed, 300 insertions(+), 28 deletions(-)
diff --git a/src/main/java/org/apache/maven/shared/filtering/DefaultMavenFileFilter.java b/src/main/java/org/apache/maven/shared/filtering/DefaultMavenFileFilter.java
index 0758e37..72c8f25 100644
--- a/src/main/java/org/apache/maven/shared/filtering/DefaultMavenFileFilter.java
+++ b/src/main/java/org/apache/maven/shared/filtering/DefaultMavenFileFilter.java
@@ -127,6 +127,19 @@ public class DefaultMavenFileFilter extends BaseFilter implements MavenFileFilte
doCopyFile(from, to, filtering, filterWrappers, encoding, ChangeDetection.CONTENT, gracefulBinaryHandling);
}
+ @Override
+ public boolean copyFileWithResult(
+ Path from,
+ Path to,
+ boolean filtering,
+ List<FilterWrapper> filterWrappers,
+ String inputEncoding,
+ String outputEncoding,
+ ChangeDetection changeDetection)
+ throws MavenFilteringException {
+ return doCopyFile(from, to, filtering, filterWrappers, inputEncoding, outputEncoding, changeDetection, false);
+ }
+
private boolean doCopyFile(
Path from,
Path to,
@@ -136,12 +149,25 @@ public class DefaultMavenFileFilter extends BaseFilter implements MavenFileFilte
ChangeDetection changeDetection,
boolean gracefulBinaryHandling)
throws MavenFilteringException {
+ return doCopyFile(from, to, filtering, filterWrappers, encoding, encoding, changeDetection, gracefulBinaryHandling);
+ }
+
+ private boolean doCopyFile(
+ Path from,
+ Path to,
+ boolean filtering,
+ List<FilterWrapper> filterWrappers,
+ String inputEncoding,
+ String outputEncoding,
+ ChangeDetection changeDetection,
+ boolean gracefulBinaryHandling)
+ throws MavenFilteringException {
try {
boolean copied;
if (filtering) {
FilterWrapper[] array = filterWrappers.toArray(new FilterWrapper[0]);
try {
- copied = FilteringUtils.copyFile(from, to, encoding, array, changeDetection);
+ copied = FilteringUtils.copyFile(from, to, inputEncoding, outputEncoding, array, changeDetection);
} catch (MalformedInputException e) {
if (!gracefulBinaryHandling) {
throw e;
@@ -156,7 +182,7 @@ public class DefaultMavenFileFilter extends BaseFilter implements MavenFileFilte
copied = true;
}
} else {
- copied = FilteringUtils.copyFile(from, to, encoding, new FilterWrapper[0], changeDetection);
+ copied = FilteringUtils.copyFile(from, to, inputEncoding, outputEncoding, new FilterWrapper[0], changeDetection);
}
buildContext.refresh(to.toFile());
@@ -164,9 +190,9 @@ public class DefaultMavenFileFilter extends BaseFilter implements MavenFileFilte
} catch (IOException e) {
String reason = e.getClass().getSimpleName() + ": " + e.getMessage();
if (e instanceof MalformedInputException) {
- String charsetName = encoding == null || encoding.isEmpty()
+ String charsetName = inputEncoding == null || inputEncoding.isEmpty()
? Charset.defaultCharset().name()
- : encoding;
+ : inputEncoding;
reason += " while reading with " + charsetName + " encoding";
}
throw new MavenFilteringException(
diff --git a/src/main/java/org/apache/maven/shared/filtering/DefaultMavenResourcesFiltering.java b/src/main/java/org/apache/maven/shared/filtering/DefaultMavenResourcesFiltering.java
index c46eeb3..8762a2c 100644
--- a/src/main/java/org/apache/maven/shared/filtering/DefaultMavenResourcesFiltering.java
+++ b/src/main/java/org/apache/maven/shared/filtering/DefaultMavenResourcesFiltering.java
@@ -277,17 +277,27 @@ public class DefaultMavenResourcesFiltering implements MavenResourcesFiltering {
propertiesFiles.add(source);
}
- // Determine which encoding to use when filtering this file.
- // A per-resource encoding overrides the global encoding and propertiesEncoding.
- String resourceEncoding = resource.getEncoding();
- String encoding = (resourceEncoding != null)
- ? resourceEncoding
- : getEncoding(
- source,
- mavenResourcesExecution.getEncoding(),
- mavenResourcesExecution.getPropertiesEncoding());
+ // Determine which encoding to use when filtering this file
+ String inputEncoding = getEncoding(
+ source, mavenResourcesExecution.getEncoding(), mavenResourcesExecution.getPropertiesEncoding());
+ // Per-resource input encoding overrides global (MRESOURCES-232 pattern)
+ if (resource.getEncoding() != null) {
+ inputEncoding = resource.getEncoding();
+ }
+ String outputEncoding = getOutputEncoding(
+ source,
+ mavenResourcesExecution.getOutputEncoding(),
+ mavenResourcesExecution.getOutputPropertiesEncoding(),
+ inputEncoding);
+ // Per-resource output encoding overrides global
+ if (resource.getOutputEncoding() != null) {
+ outputEncoding = resource.getOutputEncoding();
+ }
LOGGER.debug(
- "Using '" + encoding + "' encoding to copy filtered resource '" + source.getFileName() + "'.");
+ "Using '{}' input / '{}' output encoding to copy filtered resource '{}'.",
+ inputEncoding,
+ outputEncoding,
+ source.getFileName());
boolean doFiltering = resource.isFiltering() && filteredExt && filteredGlob;
boolean copied;
try {
@@ -296,7 +306,8 @@ public class DefaultMavenResourcesFiltering implements MavenResourcesFiltering {
destinationFile,
doFiltering,
mavenResourcesExecution.getFilterWrappers(),
- encoding,
+ inputEncoding,
+ outputEncoding,
changeDetection);
} catch (MavenFilteringException e) {
if (!mavenResourcesExecution.isGracefulBinaryHandling()
@@ -313,7 +324,8 @@ public class DefaultMavenResourcesFiltering implements MavenResourcesFiltering {
destinationFile,
false,
mavenResourcesExecution.getFilterWrappers(),
- encoding,
+ inputEncoding,
+ outputEncoding,
changeDetection);
}
if (LOGGER.isDebugEnabled()) {
@@ -399,6 +411,31 @@ public class DefaultMavenResourcesFiltering implements MavenResourcesFiltering {
}
}
+ /**
+ * Get the output encoding to use when writing the specified file. When a dedicated
+ * {@code outputEncoding} is configured, it is returned (using {@code outputPropertiesEncoding}
+ * for properties files). When no output encoding is configured, the resolved input encoding
+ * is used (backward-compatible: same encoding for reading and writing).
+ *
+ * @param file The file to check
+ * @param outputEncoding The global output encoding (may be {@code null})
+ * @param outputPropertiesEncoding The global output encoding for properties files (may be {@code null})
+ * @param inputEncoding The already-resolved input encoding to fall back to
+ * @return The output encoding to use when writing the specified file
+ * @since 4.0.0-beta-3
+ */
+ static String getOutputEncoding(
+ Path file, String outputEncoding, String outputPropertiesEncoding, String inputEncoding) {
+ if (outputEncoding == null) {
+ // no output encoding configured — fall back to input encoding (no conversion)
+ return inputEncoding;
+ }
+ if (isPropertiesFile(file)) {
+ return outputPropertiesEncoding != null ? outputPropertiesEncoding : outputEncoding;
+ }
+ return outputEncoding;
+ }
+
/**
* Determine whether a file is a properties file or not.
*
diff --git a/src/main/java/org/apache/maven/shared/filtering/FilteringUtils.java b/src/main/java/org/apache/maven/shared/filtering/FilteringUtils.java
index 11571b5..ce41e9d 100644
--- a/src/main/java/org/apache/maven/shared/filtering/FilteringUtils.java
+++ b/src/main/java/org/apache/maven/shared/filtering/FilteringUtils.java
@@ -292,7 +292,7 @@ public final class FilteringUtils {
*
* @param from the file to copy
* @param to the destination file
- * @param encoding the file output encoding (only if wrappers is not empty)
+ * @param encoding the encoding used for both reading and writing (only if wrappers is not empty)
* @param wrappers array of {@link FilterWrapper}
* @param overwrite if {@code true}, uses {@link ChangeDetection#ALWAYS}; if {@code false}, uses {@link ChangeDetection#CONTENT}
* @throws IOException if an IO error occurs during copying or filtering
@@ -319,6 +319,33 @@ public final class FilteringUtils {
public static boolean copyFile(
Path from, Path to, String encoding, FilterWrapper[] wrappers, ChangeDetection changeDetection)
throws IOException {
+ return copyFile(from, to, encoding, encoding, wrappers, changeDetection);
+ }
+
+ /**
+ * Copy and optionally filter a file using separate input and output encodings. This allows
+ * encoding conversion during resource filtering (e.g. reading ISO-8859-1 and writing UTF-8).
+ * <b>If wrappers is null or empty, the file is copied as raw bytes — encoding parameters are
+ * ignored in that case.</b>
+ *
+ * @param from the file to copy
+ * @param to the destination file
+ * @param inputEncoding the charset used to read {@code from} (only when wrappers is not empty)
+ * @param outputEncoding the charset used to write {@code to} (only when wrappers is not empty)
+ * @param wrappers array of {@link FilterWrapper}
+ * @param changeDetection the strategy to apply if to is existing file
+ * @return {@code true} if the file was copied.
+ * @throws IOException if an IO error occurs during copying or filtering
+ * @since 4.0.0-beta-3
+ */
+ public static boolean copyFile(
+ Path from,
+ Path to,
+ String inputEncoding,
+ String outputEncoding,
+ FilterWrapper[] wrappers,
+ ChangeDetection changeDetection)
+ throws IOException {
boolean needsCopy = false;
boolean unconditionally = false;
switch (changeDetection) {
@@ -350,28 +377,30 @@ public final class FilteringUtils {
boolean copied = false;
if (needsCopy) {
if (unconditionally) {
- copied = copyUnconditionally(from, to, encoding, wrappers);
+ copied = copyUnconditionally(from, to, inputEncoding, outputEncoding, wrappers);
} else {
- copied = copyIfContentsChanged(from, to, encoding, wrappers);
+ copied = copyIfContentsChanged(from, to, inputEncoding, outputEncoding, wrappers);
}
}
return copied;
}
- private static boolean copyUnconditionally(Path from, Path to, String encoding, FilterWrapper[] wrappers)
+ private static boolean copyUnconditionally(
+ Path from, Path to, String inputEncoding, String outputEncoding, FilterWrapper[] wrappers)
throws IOException {
if (wrappers == null || wrappers.length == 0) {
try (OutputStream os = Files.newOutputStream(to)) {
Files.copy(from, os);
}
} else {
- Charset charset = charset(encoding);
- try (Reader fileReader = Files.newBufferedReader(from, charset)) {
+ Charset inputCharset = charset(inputEncoding);
+ Charset outputCharset = charset(outputEncoding);
+ try (Reader fileReader = Files.newBufferedReader(from, inputCharset)) {
Reader wrapped = fileReader;
for (FilterWrapper wrapper : wrappers) {
wrapped = wrapper.getReader(wrapped);
}
- try (Writer writer = Files.newBufferedWriter(to, charset)) {
+ try (Writer writer = Files.newBufferedWriter(to, outputCharset)) {
char[] buffer = new char[COPY_BUFFER_LENGTH];
int nRead;
while ((nRead = wrapped.read(buffer, 0, COPY_BUFFER_LENGTH)) >= 0) {
@@ -384,7 +413,8 @@ public final class FilteringUtils {
return true;
}
- private static boolean copyIfContentsChanged(Path from, Path to, String encoding, FilterWrapper[] wrappers)
+ private static boolean copyIfContentsChanged(
+ Path from, Path to, String inputEncoding, String outputEncoding, FilterWrapper[] wrappers)
throws IOException {
boolean copied = false;
if (wrappers == null || wrappers.length == 0) {
@@ -393,13 +423,14 @@ public final class FilteringUtils {
copied = os.isModified();
}
} else {
- Charset charset = charset(encoding);
- try (Reader fileReader = Files.newBufferedReader(from, charset)) {
+ Charset inputCharset = charset(inputEncoding);
+ Charset outputCharset = charset(outputEncoding);
+ try (Reader fileReader = Files.newBufferedReader(from, inputCharset)) {
Reader wrapped = fileReader;
for (FilterWrapper wrapper : wrappers) {
wrapped = wrapper.getReader(wrapped);
}
- try (CachingWriter writer = new CachingWriter(to, charset)) {
+ try (CachingWriter writer = new CachingWriter(to, outputCharset)) {
char[] buffer = new char[COPY_BUFFER_LENGTH];
int nRead;
while ((nRead = wrapped.read(buffer, 0, COPY_BUFFER_LENGTH)) >= 0) {
diff --git a/src/main/java/org/apache/maven/shared/filtering/MavenFileFilter.java b/src/main/java/org/apache/maven/shared/filtering/MavenFileFilter.java
index b66f830..6cd88de 100644
--- a/src/main/java/org/apache/maven/shared/filtering/MavenFileFilter.java
+++ b/src/main/java/org/apache/maven/shared/filtering/MavenFileFilter.java
@@ -143,4 +143,29 @@ public interface MavenFileFilter extends DefaultFilterInfo {
throws MavenFilteringException {
copyFile(from, to, filtering, filterWrappers, encoding, ChangeDetection.CONTENT);
}
+
+ /**
+ * Copy and optionally filter a file using separate input and output encodings. This enables
+ * encoding conversion during resource filtering (e.g. reading ISO-8859-1 and writing UTF-8).
+ *
+ * @param from The source file
+ * @param to The target file
+ * @param filtering true to apply filtering
+ * @param filterWrappers {@link List} of FileUtils.FilterWrapper
+ * @param inputEncoding The charset used to read {@code from}
+ * @param outputEncoding The charset used to write {@code to}
+ * @param changeDetection The change detection mode to use
+ * @return {@code true} if the destination was written; {@code false} if it was skipped.
+ * @throws MavenFilteringException In case of an error.
+ * @since 4.0.0-beta-3
+ */
+ boolean copyFileWithResult(
+ Path from,
+ Path to,
+ boolean filtering,
+ List<FilterWrapper> filterWrappers,
+ String inputEncoding,
+ String outputEncoding,
+ ChangeDetection changeDetection)
+ throws MavenFilteringException;
}
diff --git a/src/main/java/org/apache/maven/shared/filtering/MavenResourcesExecution.java b/src/main/java/org/apache/maven/shared/filtering/MavenResourcesExecution.java
index b9cadd6..aebc27f 100644
--- a/src/main/java/org/apache/maven/shared/filtering/MavenResourcesExecution.java
+++ b/src/main/java/org/apache/maven/shared/filtering/MavenResourcesExecution.java
@@ -52,11 +52,27 @@ public class MavenResourcesExecution extends AbstractMavenFilteringRequest {
private String encoding;
+ /**
+ * The character encoding used to write filtered resources. When {@code null}, defaults to
+ * {@link #encoding} (i.e. same encoding for reading and writing, preserving backward compatibility).
+ *
+ * @since 4.0.0-beta-3
+ */
+ private String outputEncoding;
+
/**
* @since 3.2.0
*/
private String propertiesEncoding;
+ /**
+ * The character encoding used to write filtered properties files. When {@code null}, defaults to
+ * {@link #outputEncoding} if set, otherwise to {@link #propertiesEncoding}.
+ *
+ * @since 4.0.0-beta-3
+ */
+ private String outputPropertiesEncoding;
+
/**
* By default files like {@code .gitignore}, {@code .cvsignore} etc. are excluded which means they will not being
* copied. If you need them for a particular reason you can do that by settings this to {@code false}. This means
@@ -196,6 +212,29 @@ public class MavenResourcesExecution extends AbstractMavenFilteringRequest {
this.encoding = encoding;
}
+ /**
+ * Return the output encoding used when writing filtered resources.
+ * When {@code null}, {@link #getEncoding()} is used for writing as well.
+ *
+ * @return the output encoding, or {@code null} if not set
+ * @since 4.0.0-beta-3
+ */
+ public String getOutputEncoding() {
+ return outputEncoding;
+ }
+
+ /**
+ * Set the output encoding used when writing filtered resources.
+ * When set, enables encoding conversion during filtering (read with {@link #getEncoding()},
+ * write with this encoding). Pass {@code null} to restore symmetric behaviour.
+ *
+ * @param outputEncoding the output encoding, or {@code null} to use {@link #getEncoding()}
+ * @since 4.0.0-beta-3
+ */
+ public void setOutputEncoding(String outputEncoding) {
+ this.outputEncoding = outputEncoding;
+ }
+
/**
* Return the encoding of properties files.
*
@@ -216,6 +255,28 @@ public class MavenResourcesExecution extends AbstractMavenFilteringRequest {
this.propertiesEncoding = propertiesEncoding;
}
+ /**
+ * Return the output encoding used when writing filtered properties files.
+ * When {@code null}, falls back to {@link #getOutputEncoding()} if set, then to
+ * {@link #getPropertiesEncoding()}.
+ *
+ * @return the output properties encoding, or {@code null} if not explicitly set
+ * @since 4.0.0-beta-3
+ */
+ public String getOutputPropertiesEncoding() {
+ return outputPropertiesEncoding;
+ }
+
+ /**
+ * Set the output encoding used when writing filtered properties files.
+ *
+ * @param outputPropertiesEncoding the output encoding for properties files, or {@code null}
+ * @since 4.0.0-beta-3
+ */
+ public void setOutputPropertiesEncoding(String outputPropertiesEncoding) {
+ this.outputPropertiesEncoding = outputPropertiesEncoding;
+ }
+
/**
* @return List of {@link Resource}
*/
@@ -437,6 +498,9 @@ public class MavenResourcesExecution extends AbstractMavenFilteringRequest {
MavenResourcesExecution mre = new MavenResourcesExecution();
mre.setAdditionalProperties(this.getAdditionalProperties());
mre.setEncoding(this.getEncoding());
+ mre.setOutputEncoding(this.getOutputEncoding());
+ mre.setPropertiesEncoding(this.getPropertiesEncoding());
+ mre.setOutputPropertiesEncoding(this.getOutputPropertiesEncoding());
mre.setEscapedBackslashesInFilePath(this.isEscapedBackslashesInFilePath());
mre.setEscapeString(this.getEscapeString());
mre.setFileFilters(copyList(this.getFileFilters()));
@@ -455,7 +519,6 @@ public class MavenResourcesExecution extends AbstractMavenFilteringRequest {
mre.setAddDefaultExcludes(this.isAddDefaultExcludes());
mre.setSupportMultiLineFiltering(this.isSupportMultiLineFiltering());
mre.setFlatten(this.isFlatten());
- mre.setPropertiesEncoding(this.getPropertiesEncoding());
mre.setDelimiters(new LinkedHashSet<>(this.getDelimiters()));
mre.setInterpolatorCustomizer(this.getInterpolatorCustomizer());
mre.setGracefulBinaryHandling(this.isGracefulBinaryHandling());
diff --git a/src/test/java/org/apache/maven/shared/filtering/DefaultMavenResourcesFilteringTest.java b/src/test/java/org/apache/maven/shared/filtering/DefaultMavenResourcesFilteringTest.java
index 32e99b9..d4da8ff 100644
--- a/src/test/java/org/apache/maven/shared/filtering/DefaultMavenResourcesFilteringTest.java
+++ b/src/test/java/org/apache/maven/shared/filtering/DefaultMavenResourcesFilteringTest.java
@@ -1211,6 +1211,95 @@ class DefaultMavenResourcesFilteringTest {
assertTrue(contentEquals(Paths.get(unitFilesDir, "binary-file"), outputDirectory.resolve("binary-file")));
}
+ /**
+ * MRESOURCES-232: getOutputEncoding returns correct encoding based on parameters.
+ */
+ @Test
+ void getOutputEncoding() {
+ Path propertiesFile = Paths.get("file.properties");
+ Path regularFile = Paths.get("file.xml");
+
+ // When outputEncoding is null -> fall back to inputEncoding (no conversion)
+ assertNull(DefaultMavenResourcesFiltering.getOutputEncoding(regularFile, null, null, null));
+ assertEquals("UTF-8", DefaultMavenResourcesFiltering.getOutputEncoding(regularFile, null, null, "UTF-8"));
+
+ // Regular file with outputEncoding set -> use outputEncoding
+ assertEquals(
+ "UTF-16", DefaultMavenResourcesFiltering.getOutputEncoding(regularFile, "UTF-16", null, "ISO-8859-1"));
+ // Regular file: outputPropertiesEncoding is ignored for non-properties files
+ assertEquals(
+ "UTF-16",
+ DefaultMavenResourcesFiltering.getOutputEncoding(regularFile, "UTF-16", "ISO-8859-1", "UTF-8"));
+
+ // Properties file with outputEncoding only -> use outputEncoding
+ assertEquals(
+ "UTF-16",
+ DefaultMavenResourcesFiltering.getOutputEncoding(propertiesFile, "UTF-16", null, "ISO-8859-1"));
+ // Properties file with outputPropertiesEncoding -> use outputPropertiesEncoding
+ assertEquals(
+ "ISO-8859-1",
+ DefaultMavenResourcesFiltering.getOutputEncoding(propertiesFile, "UTF-16", "ISO-8859-1", "UTF-8"));
+ }
+
+ /**
+ * MRESOURCES-232: Filtering with a different output encoding should produce a file
+ * readable with that output encoding (encoding conversion test).
+ * Input: ISO-8859-1 source containing a token and a Latin-1 character (é = 0xE9).
+ * Output: UTF-8 (é is encoded as 0xC3 0xA9 in UTF-8).
+ */
+ @Test
+ void filterResourcesWithOutputEncoding() throws Exception {
+ mavenProject.addProperty("greeting", "World");
+ String unitFilesDir = getBasedir() + "/src/test/units-files/MRESOURCES-232";
+
+ Resource resource = new Resource();
+ resource.setDirectory(unitFilesDir);
+ resource.setFiltering(true);
+
+ MavenResourcesExecution mre = new MavenResourcesExecution(
+ Collections.singletonList(resource),
+ outputDirectory,
+ mavenProject,
+ "ISO-8859-1",
+ Collections.emptyList(),
+ Collections.emptyList(),
+ new StubSession());
+ mre.setOutputEncoding("UTF-8");
+ mavenResourcesFiltering.filterResources(mre);
+
+ // Read the output file as UTF-8 — the token must be expanded and é must survive
+ String result = Files.readString(outputDirectory.resolve("message.txt"), StandardCharsets.UTF_8);
+ assertEquals("Bonjour World! café", result);
+ }
+
+ /**
+ * MRESOURCES-232: Per-resource outputEncoding overrides the global setting.
+ */
+ @Test
+ void filterResourcesWithPerResourceOutputEncoding() throws Exception {
+ mavenProject.addProperty("greeting", "World");
+ String unitFilesDir = getBasedir() + "/src/test/units-files/MRESOURCES-232";
+
+ Resource resource = new Resource();
+ resource.setDirectory(unitFilesDir);
+ resource.setFiltering(true);
+ resource.setEncoding("ISO-8859-1");
+ resource.setOutputEncoding("UTF-8");
+
+ MavenResourcesExecution mre = new MavenResourcesExecution();
+ mre.setResources(Collections.singletonList(resource));
+ mre.setOutputDirectory(outputDirectory);
+ mre.setEncoding("UTF-8"); // global encoding — overridden per-resource
+ mre.setMavenProject(mavenProject);
+ mre.setMavenSession(new StubSession());
+ mre.setNonFilteredFileExtensions(Collections.emptyList());
+ mre.setUseDefaultFilterWrappers(true);
+ mavenResourcesFiltering.filterResources(mre);
+
+ String result = Files.readString(outputDirectory.resolve("message.txt"), StandardCharsets.UTF_8);
+ assertEquals("Bonjour World! café", result);
+ }
+
private String filename(Path file) {
return file.getFileName().toString();
}
diff --git a/src/test/units-files/MRESOURCES-232/message.txt b/src/test/units-files/MRESOURCES-232/message.txt
new file mode 100644
index 0000000..d7521b9
--- /dev/null
+++ b/src/test/units-files/MRESOURCES-232/message.txt
@@ -0,0 +1 @@
+Bonjour ${greeting}! caf�
\ No newline at end of file