Skip to content

Commit

Permalink
Add builder option to specify charset for file encoding (#28)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
WiIIiam278 authored Jan 26, 2024
1 parent 9ff59e2 commit dcb8aaf
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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.
Expand All @@ -20,6 +23,7 @@ protected FileConfigurationProperties(Builder<?> builder) {
this.header = builder.header;
this.footer = builder.footer;
this.createParentDirectories = builder.createParentDirectories;
this.charset = builder.charset;
}

/**
Expand Down Expand Up @@ -57,6 +61,7 @@ public static abstract class Builder<B extends Builder<B>>
private String header = null;
private String footer = null;
private boolean createParentDirectories = true;
private Charset charset = Charset.defaultCharset();

/**
* The default constructor.
Expand All @@ -74,6 +79,7 @@ protected Builder(FileConfigurationProperties properties) {
this.header = properties.header;
this.footer = properties.footer;
this.createParentDirectories = properties.createParentDirectories;
this.charset = properties.charset;
}

/**
Expand Down Expand Up @@ -113,6 +119,19 @@ public final B createParentDirectories(boolean createParentDirectories) {
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.
*
Expand Down Expand Up @@ -155,4 +174,14 @@ public final String getFooter() {
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;
}

}
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -13,6 +15,7 @@ void builderDefaultValues() {
assertNull(properties.getHeader());
assertNull(properties.getFooter());
assertTrue(properties.createParentDirectories());
assertEquals(Charset.defaultCharset(), properties.getCharset());
}

@Test
Expand All @@ -21,10 +24,12 @@ void builderCopiesValues() {
.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
Expand All @@ -34,6 +39,7 @@ void builderCtorCopiesValues() {
.header("A")
.footer("B")
.createParentDirectories(false)
.charset(StandardCharsets.ISO_8859_1)
.build()
.toBuilder()
.build();
Expand All @@ -42,5 +48,6 @@ void builderCtorCopiesValues() {
assertThat(properties.getHeader(), is("A"));
assertThat(properties.getFooter(), is("B"));
assertThat(properties.createParentDirectories(), is(false));
assertThat(properties.getCharset(), is(StandardCharsets.ISO_8859_1));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
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;
Expand Down Expand Up @@ -276,14 +278,18 @@ public static <T, C extends Collection<T[]>> boolean collectionOfArraysDeepEqual
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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ public T read(InputStream inputStream) {
@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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

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;
Expand Down Expand Up @@ -499,16 +501,20 @@ void lengthCommonPrefix() {
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) {
Expand Down Expand Up @@ -566,4 +572,42 @@ static <T> YamlWriterArguments argsFromConfig(
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);
}

}

0 comments on commit dcb8aaf

Please sign in to comment.