./mvnw spring-boot:build-image with default setup creates runtime image with encoding that is not utf-8. Java has default utf-8 encoding. e.g. reading env. variable with non ascii characters creates invalid String with question marks. As a workaround I set runtime image env. variable:

<configuration>
    <image>
        <env>
            <!-- set UTF-8 encoding for runtime image -->
            <BPE_LANG>C.UTF-8</BPE_LANG>
        </env>
    </image>
</configuration>

I believe the image should use by default same setup as java, which is utf-8

Comment From: wilkinsona

Java has default utf-8 encoding.

Only since Java 18 (JEP 400). Which version of Java are you using?

Comment From: michalgebauer

Right, I use java 21. So if you'll find my request valid, then proper logic should be to set utf-8 for java 18 and higher.

Comment From: wilkinsona

Thanks.

I don't think this is a problem with the JVM's encoding as it's UTF-8 when running a Paketo-generated image:

docker run docker.io/library/gh-43663:0.0.1-SNAPSHOT
Calculating JVM memory based on 6674064K available memory
For more information on this calculation, see https://paketo.io/docs/reference/java-reference/#memory-calculator
Calculated JVM Memory Configuration: -XX:MaxDirectMemorySize=10M -Xmx6082201K -XX:MaxMetaspaceSize=79862K -XX:ReservedCodeCacheSize=240M -Xss1M (Total Memory: 6674064K, Thread Count: 250, Loaded Class Count: 11686, Headroom: 0%)
Enabling Java Native Memory Tracking
Adding 146 container CA certificates to JVM truststore
Spring Cloud Bindings Enabled
Picked up JAVA_TOOL_OPTIONS: -Djava.security.properties=/layers/paketo-buildpacks_bellsoft-liberica/java-security-properties/java-security.properties -XX:+ExitOnOutOfMemoryError -XX:MaxDirectMemorySize=10M -Xmx6082201K -XX:MaxMetaspaceSize=79862K -XX:ReservedCodeCacheSize=240M -Xss1M -XX:+UnlockDiagnosticVMOptions -XX:NativeMemoryTracking=summary -XX:+PrintNMTStatistics -Dorg.springframework.cloud.bindings.boot.enable=true
UTF-8
UTF-8

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::                (v3.4.1)

2025-01-06T09:29:56.181Z  INFO 1 --- [gh-43663] [           main] c.example.gh_43663.Gh43663Application    : Starting Gh43663Application v0.0.1-SNAPSHOT using Java 21.0.5 with PID 1 (/workspace/BOOT-INF/classes started by cnb in /workspace)
2025-01-06T09:29:56.185Z  INFO 1 --- [gh-43663] [           main] c.example.gh_43663.Gh43663Application    : No active profile set, falling back to 1 default profile: "default"
2025-01-06T09:29:57.004Z  INFO 1 --- [gh-43663] [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port 8080 (http)
2025-01-06T09:29:57.020Z  INFO 1 --- [gh-43663] [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2025-01-06T09:29:57.021Z  INFO 1 --- [gh-43663] [           main] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.34]
2025-01-06T09:29:57.060Z  INFO 1 --- [gh-43663] [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2025-01-06T09:29:57.062Z  INFO 1 --- [gh-43663] [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 821 ms
2025-01-06T09:29:57.398Z  INFO 1 --- [gh-43663] [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port 8080 (http) with context path '/'
2025-01-06T09:29:57.413Z  INFO 1 --- [gh-43663] [           main] c.example.gh_43663.Gh43663Application    : Started Gh43663Application in 1.685 seconds (process running for 2.164)

Note that UTF-8 that is output twice before the banner. This is the file.encoding and default charset of the JVM. The output above was produced by an application with the following main class:

package com.example.gh_43663;

import java.nio.charset.Charset;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Gh43663Application {

    public static void main(String[] args) {
        System.out.println(System.getProperty("file.encoding"));
        System.out.println(Charset.defaultCharset());
        SpringApplication.run(Gh43663Application.class, args);
    }

}

However, I do see a problem when trying to pass in an environment variable with non-ASCII characters in its value. This affects both pack and Spring Boot's image building support so I don't think it's a Boot-specific problem.

Building a container with pack using paketobuildpacks/builder-jammy-base and running it with a problematic environment variable shows that the variable is set correctly in the container:

$ docker run -e NON_ASCII_ENV_VAR_TEST=åüéç -it --entrypoint /bin/bash gh-43663
cnb@efa876252910:/workspace$ printenv NON_ASCII_ENV_VAR_TEST
åüéç

Running the entrypoint, however, then shows that the value has been corrupted if the app dumps out System.getenv():

cnb@efa876252910:/workspace$ /cnb/process/web 
…
NON_ASCII_ENV_VAR_TEST=????????

This will have to be addressed on the buildpacks side. I'd recommend starting by discussing the problem with the community, probably in their Slack workspace.

Comment From: michalgebauer

Thanks, that's exactly the problem I was pointing out. I will to address this on the buildpacks side.