Add builder option to specify charset for file encoding (#28)

* feat: Make read/write charset configurable, default to UTF-8

* refactor: Make charset final in FileConfigurationProperties

* test: add unit tests

* refactor: use system/environment encoding by default

* test: fix spacing in test class

* test: removed unused import
dev
William 10 months ago committed by GitHub
parent 9ff59e2ca4
commit dcb8aafb4a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -1,5 +1,7 @@
package de.exlll.configlib;
import java.nio.charset.Charset;
/**
* An extension of the {@code ConfigurationProperties} class that allows configuring properties
* that are more specific to files.
@ -8,6 +10,7 @@ public class FileConfigurationProperties extends ConfigurationProperties {
private final String header;
private final String footer;
private final boolean createParentDirectories;
private final Charset charset;
/**
* Constructs a new instance of this class with values taken from the given builder.
@ -20,6 +23,7 @@ public class FileConfigurationProperties extends ConfigurationProperties {
this.header = builder.header;
this.footer = builder.footer;
this.createParentDirectories = builder.createParentDirectories;
this.charset = builder.charset;
}
/**
@ -57,6 +61,7 @@ public class FileConfigurationProperties extends ConfigurationProperties {
private String header = null;
private String footer = null;
private boolean createParentDirectories = true;
private Charset charset = Charset.defaultCharset();
/**
* The default constructor.
@ -74,6 +79,7 @@ public class FileConfigurationProperties extends ConfigurationProperties {
this.header = properties.header;
this.footer = properties.footer;
this.createParentDirectories = properties.createParentDirectories;
this.charset = properties.charset;
}
/**
@ -113,6 +119,19 @@ public class FileConfigurationProperties extends ConfigurationProperties {
return getThis();
}
/**
* Sets the charset used to read and write configuration files.
* <p>
* Defaults to the system's default charset ({@code Charset.defaultCharset()}).
*
* @param charset the charset
* @return this builder
*/
public final B charset(Charset charset) {
this.charset = charset;
return getThis();
}
/**
* Builds a {@code ConfigurationProperties} instance.
*
@ -155,4 +174,14 @@ public class FileConfigurationProperties extends ConfigurationProperties {
public final boolean createParentDirectories() {
return createParentDirectories;
}
/**
* Returns the charset used to read and write configuration files.
*
* @return the charset
*/
public final Charset getCharset() {
return charset;
}
}

@ -1,6 +1,8 @@
package de.exlll.configlib;
import org.junit.jupiter.api.Test;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
@ -13,6 +15,7 @@ class FileConfigurationPropertiesTest {
assertNull(properties.getHeader());
assertNull(properties.getFooter());
assertTrue(properties.createParentDirectories());
assertEquals(Charset.defaultCharset(), properties.getCharset());
}
@Test
@ -21,10 +24,12 @@ class FileConfigurationPropertiesTest {
.header("THE HEADER")
.footer("THE FOOTER")
.createParentDirectories(false)
.charset(StandardCharsets.ISO_8859_1)
.build();
assertEquals("THE HEADER", properties.getHeader());
assertEquals("THE FOOTER", properties.getFooter());
assertFalse(properties.createParentDirectories());
assertEquals(StandardCharsets.ISO_8859_1, properties.getCharset());
}
@Test
@ -34,6 +39,7 @@ class FileConfigurationPropertiesTest {
.header("A")
.footer("B")
.createParentDirectories(false)
.charset(StandardCharsets.ISO_8859_1)
.build()
.toBuilder()
.build();
@ -42,5 +48,6 @@ class FileConfigurationPropertiesTest {
assertThat(properties.getHeader(), is("A"));
assertThat(properties.getFooter(), is("B"));
assertThat(properties.createParentDirectories(), is(false));
assertThat(properties.getCharset(), is(StandardCharsets.ISO_8859_1));
}
}

@ -3,13 +3,15 @@ package de.exlll.configlib;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.function.Executable;
import java.awt.Point;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.*;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@ -276,14 +278,18 @@ public final class TestUtils {
return c1.equals(c2);
}
public static String readFile(Path file) {
public static String readFile(Path file, Charset charset) {
try {
return Files.readString(file);
return Files.readString(file, charset);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static String readFile(Path file) {
return readFile(file, Charset.defaultCharset());
}
public static ConfigurationElement<?> fieldAsElement(Class<?> type, String fieldName) {
Field field = getField(type, fieldName);
return new ConfigurationElements.FieldElement(field);

@ -126,7 +126,7 @@ public final class YamlConfigurationStore<T> implements
@Override
public T load(Path configurationFile) {
requireNonNull(configurationFile, "configuration file");
try (var reader = Files.newBufferedReader(configurationFile)) {
try (var reader = Files.newBufferedReader(configurationFile, properties.getCharset())) {
var yaml = YAML_LOADER.loadFromReader(reader);
var conf = requireYamlMapForLoad(yaml, configurationFile);
return serializer.deserialize(conf);

@ -36,7 +36,8 @@ final class YamlWriter {
}
public void writeYaml(String yaml, Queue<CommentNode> nodes) {
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream))) {
try (BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(outputStream, properties.getCharset()))) {
this.writer = writer;
writeHeader();
writeContent(yaml, nodes);

@ -8,6 +8,8 @@ import org.snakeyaml.engine.v2.api.Dump;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.Path;
@ -499,16 +501,20 @@ class YamlWriterTest {
assertEquals(0, YamlWriter.lengthCommonPrefix(abcd, def));
}
String readFile() {
return TestUtils.readFile(yamlFile);
String readFile(Charset charset) {
return TestUtils.readFile(yamlFile, charset);
}
String readOutputStream() {
return outputStream.toString();
}
void assertFileContentEquals(String expected, Charset charset) {
assertEquals(expected, readFile(charset));
}
void assertFileContentEquals(String expected) {
assertEquals(expected, readFile());
assertFileContentEquals(expected, Charset.defaultCharset());
}
void assertStreamContentEquals(String expected) {
@ -566,4 +572,42 @@ class YamlWriterTest {
Queue<CommentNode> nodes = extractor.extractCommentNodes(c);
return new YamlWriterArguments(yaml, nodes, properties);
}
@Configuration
static class N {
@Comment("テスト")
String s = "テスト test";
}
@Test
void writeYamlToFileInUTF8WithUnicodeCharacters() {
Consumer<YamlConfigurationProperties.Builder<?>> builderConsumer = builder -> builder
.charset(StandardCharsets.UTF_8);
writeConfigToFile(N.class, builderConsumer);
String expected = """
#
s: test
""";
assertFileContentEquals(expected, StandardCharsets.UTF_8);
}
@Test
void writeYamlToFileInASCIIWithUnicodeCharacters() {
Consumer<YamlConfigurationProperties.Builder<?>> builderConsumer = builder -> builder
.charset(StandardCharsets.US_ASCII);
writeConfigToFile(N.class, builderConsumer);
// UTF-8 characters will be replaced with question mark points
String expected = """
# ???
s: ??? test
""";
assertFileContentEquals(expected, StandardCharsets.US_ASCII);
}
}

Loading…
Cancel
Save