Search code examples
javaspring-bootgradlefreemarker

Why does setting freemarkers' default encoding break reading template (everything is in utf-8)?


I have a spring boot project with gradle kts, and I am using the standalone freemarker library implementation("org.freemarker:freemarker:2.3.32") for templating texts for frontend.

I put together the following code:

Configuration cfg = new Configuration(Configuration.VERSION_2_3_32);
cfg.setDirectoryForTemplateLoading(new ClassPathResource("templates").getFile());
cfg.setDefaultEncoding("utf-8");
cfg.setOutputEncoding("utf-8");

Template template = cfg.getTemplate("template.ftl");
System.out.println("template=" + template);

Map<String, Object> data = new HashMap<>();
data.put("vehicles", List.of(new Vehicle("auto", 60), new Vehicle("koloběžka", 5)));

StringWriter stringWriter = new StringWriter();
template.process(data, stringWriter);
String result = stringWriter.toString();

System.out.println(result);

Template file template.ftl contains (for testing purpuses):

jůůů

Both the data I am passing to the template ("koloběžka") and the template itself ("jůůů") contain czech characters.

Problem
The template file's encoding is utf-8 (at least that's what I see in intellj).
If I don't set default encoding on the Configuration object, it uses the one from my locale (I guess), and that's "windows-1250". Then the template is printed (the line with template=) correctly (diacritics).
But if I set the default encoding explicitly to utf-8, the line prints j���.

Question
How is that possible?
I would assume that if both the template and the Configuration use utf-8, then diacritics should be red correctly.
And the other way bothers me as well - how is it possible that the encoding windows-1250 the Configuration object uses by default is able to read diacritics from the utf-8 encoded file well?


Solution

  • Your problem is that the console you are using is not set up to print out utf-8 properly. You should be able to do this in PowerShell but at the moment I am finding it difficult to find out the way to do this.

    Update: the following worked for me, using PowerShell for my Java console: $OutputEncoding = [Console]::InputEncoding = [Console]::OutputEncoding = New-Object System.Text.UTF8Encoding Executed code: System.out.println(new Vehicle("koloběžka", 5)); Output:

    PS C:\Users\goose> java Vehicle
    name=koloběžka,id=5
    PS C:\Users\goose>