Skip to content

Fix: Include charset resources in native image for Cp1252 support - #227

Closed
bmarwell wants to merge 10 commits into
mainfrom
fix/issue-190-cp1252-charset-support
Closed

Fix: Include charset resources in native image for Cp1252 support#227
bmarwell wants to merge 10 commits into
mainfrom
fix/issue-190-cp1252-charset-support

Conversation

@bmarwell

Copy link
Copy Markdown
Owner

Description

Fixes #190 - UnsupportedCharsetException: Cp1252 with Windows image

This PR adds explicit charset resource inclusion to the GraalVM native image configuration to ensure Windows-1252 (Cp1252) and other extended charsets are available at runtime.

Problem

The existing -H:+AddAllCharsets flag in native-image.properties includes charset classes but does not automatically include the required resource files (SPI metadata and charset mapping data). This causes UnsupportedCharsetException: Cp1252 when the Eclipse JDT Platform tries to use Charset.forName("Cp1252") on Windows systems.

Solution

Added three resource patterns to resource-config.json:

  1. META-INF/services/java.nio.charset.spi.CharsetProvider - Service provider configuration
  2. sun/nio/cs/* - Core charset providers (UTF-8, ASCII, ISO-8859-1)
  3. sun/nio/cs/ext/* - Extended charset providers (Cp1252, Windows-1252, etc.)

Changes

Configuration

  • Modified: cli/src/main/graalvm-native/resource-config.json
    • Added charset provider SPI pattern
    • Added core charset resource patterns
    • Added extended charset resource patterns

Testing

  • Added: integration-tests/jreleaser-builtin/src/test/java/io/github/bmarwell/jfmt/its/jreleaser/builtin/CharsetSupportIT.java

    • Integration test verifying charset availability in native image
    • Tests print, list, and diff commands with Cp1252 characters
    • Ensures no UnsupportedCharsetException is thrown
  • Added: integration-tests/jreleaser-builtin/src/test/resources/charset/Cp1252Test.java

    • Test resource file containing Windows-1252 specific characters (€, ™, ©, ®)
    • Used to verify charset handling in integration tests

Testing Notes

  • ✅ Tested on: Linux (current platform)
  • ⚠️ Requires testing on: Windows to verify Cp1252 support in native image
  • The integration test will run on the current platform and verify charset resources are included

Technical Details

The -H:+AddAllCharsets flag and explicit resource inclusion work together:

  • Flag: Includes charset classes and enables initialization
  • Resources: Provides the metadata and mapping data needed for Charset.forName() to work

This is the standard GraalVM approach for ensuring charset availability in native images.

Related Issues

Closes #190

@codecov

codecov Bot commented Jun 27, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 72.11%. Comparing base (cfcdf52) to head (8a013d4).
⚠️ Report is 18 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #227   +/-   ##
=======================================
  Coverage   72.11%   72.11%           
=======================================
  Files          26       26           
  Lines         563      563           
  Branches       52       52           
=======================================
  Hits          406      406           
  Misses        128      128           
  Partials       29       29           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

@bmarwell
bmarwell force-pushed the fix/issue-190-cp1252-charset-support branch from 53223de to 6181be0 Compare June 27, 2026 21:21

@bmarwell bmarwell left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • The test files were committed as UTF-8, and it would need to be converted before testing starts
  • The tests actually only run against the Java version. Instead they need to run against the current binary version.

Fixes #190

- Add charset provider SPI and resource patterns to resource-config.json
- Include sun/nio/cs/* for core charsets (UTF-8, ASCII, ISO-8859-1)
- Include sun/nio/cs/ext/* for extended charsets (Cp1252, Windows-1252)
- Add integration test CharsetSupportIT to verify charset availability
- Add test resource file with Cp1252 characters

The -H:+AddAllCharsets flag includes charset classes but not the
required resource files (SPI metadata and charset mapping data).
This change explicitly includes those resources to ensure charsets
like Cp1252 are available at runtime in the native image.

Tested on: Linux (current platform)
Requires testing on: Windows to verify Cp1252 support
@bmarwell
bmarwell force-pushed the fix/issue-190-cp1252-charset-support branch from 6181be0 to e381106 Compare June 27, 2026 21:25

@bmarwell bmarwell left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have reviewed the PR and have a few suggestions for improvement.

Summary of Suggestions

  1. Rename Test Class: Rename to to better reflect its purpose as a native image integration test.
  2. Refactor Duplication: and the new native test share significant logic for setup and path resolution. These should be moved to a base class or utility.
  3. Verify Maven Wrapper: Ensure the update to Maven 4 RC-5 is intentional.
  4. Standardize Scripts: The additions look good for cross-platform stability.

I will add specific line comments with suggested changes.

@bmarwell bmarwell left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have reviewed the PR and have a few suggestions for improvement.

Summary of Suggestions

  1. Rename Test Class: Rename CharsetSupportAdditionalIT to CharsetSupportNativeIT to better reflect its purpose as a native image integration test.
  2. Refactor Duplication: CharsetSupportIT and the new native test share significant logic for setup and path resolution. These should be moved to a base class or utility.
  3. Verify Maven Wrapper: Ensure the update to Maven 4 RC-5 is intentional.
  4. Standardize Scripts: The .gitattributes additions look good for cross-platform stability.

I will add specific line comments with suggested changes.

@bmarwell bmarwell left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-p integration-tests/jreleaser-builtin/src/test/java/io/github/bmarwell/jfmt/its/jreleaser/builtin/CharsetSupportAdditionalIT.java -b "Suggestion: Rename this class to 'CharsetSupportNativeIT' as requested. Also, we should consider refactoring the common setup logic shared with CharsetSupportIT into a base class."

@bmarwell bmarwell left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Rename 'CharsetSupportAdditionalIT' to 'CharsetSupportNativeIT' as requested. Also, we should consider refactoring the common setup logic shared with 'CharsetSupportIT' into a base class to reduce duplication.

@bmarwell bmarwell left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirm if the Maven Wrapper update from RC-4 to RC-5 is intentional and verified as stable for the project.

@bmarwell

Copy link
Copy Markdown
Owner Author

@copilot

Look at this run: https://github.com/bmarwell/jfmt/actions/runs/28373430791/job/84057044002?pr=227

The output is:

  set -euo pipefail
  DIST_FILE=$(ls cli/target/distributions/jfmt-*-linux-*.tar.gz | head -n1)
  mkdir -p cli/target/native-it
  tar -xzf "$DIST_FILE" -C cli/target/native-it
  JFMT_DIR=$(find cli/target/native-it -maxdepth 1 -type d -name "jfmt-*" | head -n1)
  "$JFMT_DIR/bin/jfmt" --help
  ./mvnw --batch-mode --strict-checksum --errors -Pci,native -pl integration-tests/jreleaser-builtin -am verify -Djfmt.directory="$JFMT_DIR"
  shell: /usr/bin/bash --noprofile --norc -e -o pipefail {0}
  env:
    JAVA_HOME: /opt/hostedtoolcache/Java_GraalVM_jdk/25/x64
    JAVA_HOME_25_X64: /opt/hostedtoolcache/Java_GraalVM_jdk/25/x64
mt [-hV] [COMMAND]
A command-line tool to format Java source code using JDT.
  -h, --help      Show this help message and exit.
  -V, --version   Print version information and exit.
Commands:
  list        List files which are not formatted correctly without printing a
                diff or writing changes.
              All files are processed by default.
  write, fix  Write the formatted source code back to the file(s).
              All files are processed by default.
              This is the default operation if no sub-command is given.
  print       Print the correctly formatted output for the given file(s).
              All files are processed by default.
              Use --no-all to stop after the first file.
              When multiple files are processed, the file name is printed
                before each output.
  diff        Output in diff format. Normal diff is used unless -u is also
                given.
              All files are processed by default.

If no subcommand is specified, 'write' is used as the default.
Run 'jfmt write --help' to see all available options and parameters.

as well as

[ERROR] Failed to execute goal org.graalvm.buildtools:native-maven-plugin:1.1.2:compile-no-fork (build-native) on project jfmt: Execution of /opt/hostedtoolcache/Java_GraalVM_jdk/25/x64/bin/native-image -cp /home/runner/work/jfmt/jfmt/cli/target/jfmt-0.2.0-SNAPSHOT.jar:/home/runner/.m2/repository/info/picocli/picocli/4.7.7/picocli-4.7.7.jar:/home/runner/.m2/repository/info/picocli/picocli-jansi-graalvm/1.2.0/picocli-jansi-graalvm-1.2.0.jar:/home/runner/.m2/repository/org/fusesource/jansi/jansi/1.18/jansi-1.18.jar:/home/runner/.m2/repository/io/github/java-diff-utils/java-diff-utils/4.17/java-diff-utils-4.17.jar:/home/runner/.m2/repository/org/eclipse/jdt/org.eclipse.jdt.core/3.43.0/org.eclipse.jdt.core-3.43.0.jar:/home/runner/.m2/repository/org/eclipse/platform/org.eclipse.core.resources/3.23.0/org.eclipse.core.resources-3.23.0.jar:/home/runner/.m2/repository/org/eclipse/platform/org.eclipse.core.expressions/3.9.500/org.eclipse.core.expressions-3.9.500.jar:/home/runner/.m2/repository/net/java/dev/jna/jna/5.17.0/jna-5.17.0.jar:/home/runner/.m2/repository/org/eclipse/platform/org.eclipse.osgi/3.23.200/org.eclipse.osgi-3.23.200.jar:/home/runner/.m2/repository/org/eclipse/platform/org.eclipse.core.runtime/3.34.0/org.eclipse.core.runtime-3.34.0.jar:/home/runner/.m2/repository/org/eclipse/platform/org.eclipse.equinox.common/3.20.200/org.eclipse.equinox.common-3.20.200.jar:/home/runner/.m2/repository/org/eclipse/platform/org.eclipse.core.jobs/3.15.700/org.eclipse.core.jobs-3.15.700.jar:/home/runner/.m2/repository/org/eclipse/platform/org.eclipse.equinox.registry/3.12.500/org.eclipse.equinox.registry-3.12.500.jar:/home/runner/.m2/repository/org/eclipse/platform/org.eclipse.equinox.preferences/3.12.0/org.eclipse.equinox.preferences-3.12.0.jar:/home/runner/.m2/repository/org/osgi/org.osgi.service.prefs/1.1.2/org.osgi.service.prefs-1.1.2.jar:/home/runner/.m2/repository/org/osgi/osgi.annotation/8.0.1/osgi.annotation-8.0.1.jar:/home/runner/.m2/repository/org/eclipse/platform/org.eclipse.core.contenttype/3.9.700/org.eclipse.core.contenttype-3.9.700.jar:/home/runner/.m2/repository/org/eclipse/platform/org.eclipse.equinox.app/1.7.500/org.eclipse.equinox.app-1.7.500.jar:/home/runner/.m2/repository/org/eclipse/platform/org.eclipse.core.filesystem/1.11.300/org.eclipse.core.filesystem-1.11.300.jar:/home/runner/.m2/repository/net/java/dev/jna/jna-platform/5.17.0/jna-platform-5.17.0.jar:/home/runner/.m2/repository/org/eclipse/platform/org.eclipse.text/3.14.400/org.eclipse.text-3.14.400.jar:/home/runner/.m2/repository/org/eclipse/platform/org.eclipse.core.commands/3.12.400/org.eclipse.core.commands-3.12.400.jar:/home/runner/.m2/repository/org/eclipse/jdt/ecj/3.43.0/ecj-3.43.0.jar:/home/runner/.m2/repository/org/jspecify/jspecify/1.0.0/jspecify-1.0.0.jar --no-fallback -Ob -o /home/runner/work/jfmt/jfmt/cli/target/jfmt-0.2.0-SNAPSHOT -Duser.country=US -Duser.language=en -J-Duser.language=en -J-Duser.country=US --static -march=compatibility --libc=musl -H:ConfigurationFileDirectories=/home/runner/work/jfmt/jfmt/cli/src/main/graalvm-native -H:ConfigurationFileDirectories=/home/runner/work/jfmt/jfmt/cli/src/main/graalvm-native -H:ConfigurationFileDirectories=/home/runner/work/jfmt/jfmt/cli/src/main/graalvm-native io.github.bmarwell.jfmt.JFmt returned non-zero result -[Help 1]

Further maven output:

[1/8] Initializing...                                                                                    (0.0s @ 0.16GB)
Error: Default native-compiler executable 'x86_64-linux-musl-gcc' not found via environment variable PATH
Error: To prevent native-toolchain checking provide command-line option -H:-CheckToolchain

Find the cause and fix the workflow.

Copilot AI review requested due to automatic review settings July 28, 2026 08:25

Copilot AI commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

@copilot

Look at this run: https://github.com/bmarwell/jfmt/actions/runs/28373430791/job/84057044002?pr=227
...

Fixed in a15a59e.

Cause: the Linux smoke-test step ran ./mvnw ... -Pci,native -pl integration-tests/jreleaser-builtin -am verify, which rebuilt cli with the native profile. In that second step, musl toolchain PATH was not exported, so native-image failed with missing x86_64-linux-musl-gcc.

Fix: updated the smoke-test Maven call to -Pci and added -Djfmt.native.profile.active=true. This keeps native-only ITs enabled while testing against the extracted native binary, without retriggering native compilation.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses #190 by ensuring extended charsets (notably Windows-1252 / Cp1252) work in the GraalVM native image by explicitly including the required charset provider resources, and by adding integration tests that exercise Cp1252 input through the native binary.

Changes:

  • Extend cli GraalVM native-image resource configuration to include charset SPI metadata and charset provider resources.
  • Add integration tests and a Cp1252-containing Java source fixture to validate print, list, and diff behavior without UnsupportedCharsetException.
  • Add CI “smoke test” steps and Maven properties to pass native-profile intent into integration test runs.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
pom.xml Introduces a default jfmt.native.profile.active property and toggles it in the native profile for test gating.
integration-tests/pom.xml Centralizes jfmt.directory and propagates jfmt.native.profile.active into IT JVM system properties.
integration-tests/jreleaser-builtin/src/test/resources/charset/Cp1252Test.java Adds a fixture containing Cp1252-specific characters used by the integration tests.
integration-tests/jreleaser-builtin/src/test/java/io/github/bmarwell/jfmt/its/jreleaser/builtin/NativeItConditions.java Adds assumptions to run charset native ITs only when the native profile is active and on GraalVM.
integration-tests/jreleaser-builtin/src/test/java/io/github/bmarwell/jfmt/its/jreleaser/builtin/CharsetSupportNativeIT.java Adds native-binary-focused charset tests for print and diff.
integration-tests/jreleaser-builtin/src/test/java/io/github/bmarwell/jfmt/its/jreleaser/builtin/CharsetSupportIT.java Adds broader charset integration coverage across print, list, and diff.
integration-tests/jreleaser-builtin/src/test/java/io/github/bmarwell/jfmt/its/jreleaser/builtin/AbstractCharsetIT.java Adds shared setup to generate a Windows-1252 encoded test file for the ITs.
integration-tests/it-extension/src/main/java/io/github/bmarwell/jfmt/its/extension/JFmtExtension.java Adjusts the spawned process environment (but currently does so in a platform-dependent way).
cli/src/main/graalvm-native/resource-config.json Adds charset-related resource include patterns for native-image.
.github/workflows/build-native.yml Adds smoke test steps that run the native binary and execute the relevant integration tests on Linux.

Comment thread cli/src/main/graalvm-native/resource-config.json Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Benjamin Marwell <bmarwell@apache.org>
Copilot AI review requested due to automatic review settings July 28, 2026 08:34
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Benjamin Marwell <bmarwell@apache.org>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Comment thread integration-tests/pom.xml
Comment on lines 74 to 79
<configuration>
<systemPropertyVariables>
<jfmt.directory>${project.build.directory}/jfmt/jfmt-${project.version}</jfmt.directory>
<jfmt.directory>${jfmt.directory}</jfmt.directory>
<jfmt.native.profile.active>${jfmt.native.profile.active}</jfmt.native.profile.active>
</systemPropertyVariables>
</configuration>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest commit by adding combine.self="merge" to the failsafe <systemPropertyVariables> element, matching the pattern already used for surefire.

Copilot AI review requested due to automatic review settings July 28, 2026 08:46

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Comment thread .github/workflows/build-native.yml
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Benjamin Marwell <bmarwell@apache.org>
Copilot AI review requested due to automatic review settings July 28, 2026 08:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (2)

integration-tests/jreleaser-builtin/src/test/java/io/github/bmarwell/jfmt/its/jreleaser/builtin/CharsetSupportNativeIT.java:15

  • CharsetSupportNativeIT duplicates the coverage already provided by CharsetSupportIT (same base class, same commands, overlapping assertions). Keeping both will increase native-IT runtime and maintenance cost; consider merging them into a single test class (or splitting into JVM vs native tests explicitly).
@JFmtTest
class CharsetSupportNativeIT extends AbstractCharsetIT {

    @Test
    @JFmtTest(args = { "print", "target/test-classes/charset/Cp1252Test.java" })

.github/workflows/build-native.yml:288

  • The Windows smoke-test block exits after --help, so the new charset native integration tests are never exercised on Windows (the platform where #190 was reported). Consider running the same integration-tests/jreleaser-builtin verify step here before exiting.
            JFMT_BAT=$(cygpath -w "$JFMT_DIR/bin/jfmt.bat")
            cmd.exe /c "\"$JFMT_BAT\" --help"
            exit 0

@bmarwell bmarwell closed this Jul 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

UnsupportedCharsetException: Cp1252 with Windows image

3 participants