Skip to content

Commit

Permalink
feat(config): use HOCON format instead of YAML
Browse files Browse the repository at this point in the history
The motivation to change the config format come from a limitation of Configurate about YAML format. It is not possible to serialize a YAML content with comments whereas this is a requirement for the project.
More details can be found here about Configurate and YAML module: SpongePowered/Configurate#175
  • Loading branch information
Djaytan committed Feb 12, 2023
1 parent b8a1c3f commit a44c085
Show file tree
Hide file tree
Showing 100 changed files with 455 additions and 395 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@
</dependency>
<dependency>
<groupId>org.spongepowered</groupId>
<artifactId>configurate-yaml</artifactId>
<artifactId>configurate-hocon</artifactId>
<version>${configurate.version}</version>
</dependency>
<dependency>
Expand Down
2 changes: 1 addition & 1 deletion src/patch-place-break/patch-place-break-config/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
</dependency>
<dependency>
<groupId>org.spongepowered</groupId>
<artifactId>configurate-yaml</artifactId>
<artifactId>configurate-hocon</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
@Singleton
public class ConfigManager {

public static final String CONFIG_FILE_NAME = "config.yml";
public static final String CONFIG_FILE_NAME = "config.conf";

private final ClassLoader classLoader;
private final Path configFile;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,11 @@

import org.apache.commons.io.IOUtils;
import org.spongepowered.configurate.CommentedConfigurationNode;
import org.spongepowered.configurate.hocon.HoconConfigurationLoader;
import org.spongepowered.configurate.loader.ConfigurationLoader;
import org.spongepowered.configurate.loader.HeaderMode;
import org.spongepowered.configurate.objectmapping.ObjectMapper;
import org.spongepowered.configurate.util.NamingSchemes;
import org.spongepowered.configurate.yaml.NodeStyle;
import org.spongepowered.configurate.yaml.YamlConfigurationLoader;

import lombok.NonNull;

Expand Down Expand Up @@ -66,8 +65,8 @@ private ConfigLoaderFactory() {

String configHeader = createConfigHeader();

return YamlConfigurationLoader.builder().path(configFile).nodeStyle(NodeStyle.BLOCK)
.headerMode(HeaderMode.PRESET)
return HoconConfigurationLoader.builder().path(configFile).prettyPrinting(true)
.emitComments(true).emitJsonCompatible(false).headerMode(HeaderMode.PRESET)
.defaultOptions(
opts -> opts.serializers(builder -> builder.registerAnnotatedObjects(customFactory))
.header(configHeader))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ public final class ConfigSerializer {
* @param object The object to serialize.
* @throws ConfigSerializationException If something prevent the serialization.
*/
public void serialize(@NonNull Path destConfigFile, Object object) {

public void serialize(@NonNull Path destConfigFile, @NonNull Object object)
throws ConfigSerializationException {
try {
ConfigurationLoader<CommentedConfigurationNode> loader =
ConfigLoaderFactory.createLoader(destConfigFile);
Expand All @@ -62,7 +62,7 @@ public void serialize(@NonNull Path destConfigFile, Object object) {
throw ConfigSerializationException.failToSerialize();
}

ConfigurationNode configurationNode = loader.createNode(node -> node.set(object));
CommentedConfigurationNode configurationNode = loader.createNode(node -> node.set(object));
loader.save(configurationNode);
} catch (IOException e) {
throw ConfigSerializationException.failToSerialize(e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ void withExistingConfigFile_shouldDoNothing() throws IOException {
@DisplayName("With IOException thrown")
void withIOExceptionThrown_shouldThrowException() throws IOException {
// Given
String defaultConfigFileName = "whenCreatingConfig_withIOExceptionThrown.yml";
String defaultConfigFileName = "whenCreatingConfig_withIOExceptionThrown.conf";
Path defaultConfigFile = TestResourcesHelper.getClassResourceAsAbsolutePath(this.getClass(),
defaultConfigFileName);

Expand Down Expand Up @@ -163,7 +163,7 @@ class AndWithDefaultOne {
void beingNotEmpty_thenShouldNotThrow() throws IOException {
// Given
String defaultConfigFileName =
"whenCreatingConfig_withoutExistingOne_andWithDefaultOne_beingNotEmpty.yml";
"whenCreatingConfig_withoutExistingOne_andWithDefaultOne_beingNotEmpty.conf";
Path defaultConfigFile = TestResourcesHelper
.getClassResourceAsAbsolutePath(this.getClass(), defaultConfigFileName);

Expand All @@ -182,7 +182,7 @@ void beingNotEmpty_thenShouldNotThrow() throws IOException {
void beingEmpty_thenShouldThrowConfigException() throws IOException {
// Given
String defaultConfigFileName =
"whenCreatingConfig_withoutExistingOne_andWithDefaultOne_beingEmpty.yml";
"whenCreatingConfig_withoutExistingOne_andWithDefaultOne_beingEmpty.conf";
Path defaultConfigFile = TestResourcesHelper
.getClassResourceAsAbsolutePath(this.getClass(), defaultConfigFileName);

Expand All @@ -208,7 +208,7 @@ class WhenReadingAndValidatingConfig {
@DisplayName("With nominal config file")
void withNominalConfigFile_shouldSuccess() throws IOException {
// Given
String nominalConfigFileName = "whenReadingAndValidatingConfig_withNominalConfigFile.yml";
String nominalConfigFileName = "whenReadingAndValidatingConfig_withNominalConfigFile.conf";
Path nominalConfigFile = TestResourcesHelper.getClassResourceAsAbsolutePath(this.getClass(),
nominalConfigFileName);
Files.copy(nominalConfigFile, configFile);
Expand All @@ -229,7 +229,7 @@ void withNominalConfigFile_shouldSuccess() throws IOException {
void withMissingRequiredFieldsInConfigFile_shouldThrowException() throws IOException {
// Given
String invalidConfigFileName =
"whenReadingAndValidatingConfig_withMissingRequiredFieldsInConfigFile.yml";
"whenReadingAndValidatingConfig_withMissingRequiredFieldsInConfigFile.conf";
Path invalidConfigFile = TestResourcesHelper.getClassResourceAsAbsolutePath(this.getClass(),
invalidConfigFileName);
Files.copy(invalidConfigFile, configFile);
Expand All @@ -246,7 +246,7 @@ void withMissingRequiredFieldsInConfigFile_shouldThrowException() throws IOExcep
@DisplayName("With invalid config file")
void withInvalidConfigFile_shouldThrowException() throws IOException {
// Given
String invalidConfigFileName = "whenReadingAndValidatingConfig_withInvalidConfigFile.yml";
String invalidConfigFileName = "whenReadingAndValidatingConfig_withInvalidConfigFile.conf";
Path invalidConfigFile = TestResourcesHelper.getClassResourceAsAbsolutePath(this.getClass(),
invalidConfigFileName);
Files.copy(invalidConfigFile, configFile);
Expand All @@ -262,7 +262,7 @@ void withInvalidConfigFile_shouldThrowException() throws IOException {
@DisplayName("With empty config file")
void withEmptyConfigFile_shouldThrowException() throws IOException {
// Given
String emptyConfigFileName = "whenReadingAndValidatingConfig_withEmptyConfigFile.yml";
String emptyConfigFileName = "whenReadingAndValidatingConfig_withEmptyConfigFile.conf";
Path emptyConfigFile =
TestResourcesHelper.getClassResourceAsAbsolutePath(this.getClass(), emptyConfigFileName);
Files.copy(emptyConfigFile, configFile);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
import fr.djaytan.minecraft.jobsreborn.patchplacebreak.internal.storage.api.properties.DbmsHostProperties;
import fr.djaytan.minecraft.jobsreborn.patchplacebreak.internal.storage.api.properties.DbmsServerProperties;
import jakarta.validation.ConstraintViolation;
import lombok.NonNull;
import nl.jqno.equalsverifier.EqualsVerifier;
import nl.jqno.equalsverifier.Warning;

Expand Down Expand Up @@ -230,8 +231,8 @@ class WhenDeserializingFromYaml {
@ParameterizedTest(name = "{index} - {0}")
@MethodSource
@DisplayName("With valid content")
void withValidContent_shouldMatchExpectedValue(String yamlFileName,
ConfigValidatingProperties expectedValue) {
void withValidContent_shouldMatchExpectedValue(@NonNull String yamlFileName,
@NonNull ConfigValidatingProperties expectedValue) {
// Given
Path yamlFile =
TestResourcesHelper.getClassResourceAsAbsolutePath(this.getClass(), yamlFileName);
Expand All @@ -244,25 +245,25 @@ void withValidContent_shouldMatchExpectedValue(String yamlFileName,
assertThat(optionalConfigValidatingProperties).isPresent().get().isEqualTo(expectedValue);
}

private Stream<Arguments> withValidContent_shouldMatchExpectedValue() {
private @NonNull Stream<Arguments> withValidContent_shouldMatchExpectedValue() {
return Stream.of(
Arguments.of(Named.of("With valid values", "whenDeserializing_withValidValues.yml"),
Arguments.of(Named.of("With valid values", "whenDeserializing_withValidValues.conf"),
ConfigValidatingProperties
.of(DataSourceValidatingProperties.of(DataSourceType.MYSQL, "patch_place_break",
DbmsServerValidatingProperties.of(
DbmsHostValidatingProperties.of("example.com", 1234, true),
CredentialsValidatingProperties.of("foo", "bar"), "patch_database"),
ConnectionPoolValidatingProperties.of(60000, 10)))),
Arguments.of(
Named.of("With unexpected field", "whenDeserializing_withUnexpectedField.yml"),
Named.of("With unexpected field", "whenDeserializing_withUnexpectedField.conf"),
ConfigValidatingProperties
.of(DataSourceValidatingProperties.of(DataSourceType.MYSQL, "patch_place_break",
DbmsServerValidatingProperties.of(
DbmsHostValidatingProperties.of("example.com", 1234, true),
CredentialsValidatingProperties.of("foo", "bar"), "patch_database"),
ConnectionPoolValidatingProperties.of(60000, 10)))),
Arguments.of(
Named.of("With 'isValidated' field", "whenDeserializing_withIsValidatedField.yml"),
Named.of("With 'isValidated' field", "whenDeserializing_withIsValidatedField.conf"),
ConfigValidatingProperties
.of(DataSourceValidatingProperties.of(DataSourceType.MYSQL, "patch_place_break",
DbmsServerValidatingProperties.of(
Expand All @@ -275,7 +276,7 @@ private Stream<Arguments> withValidContent_shouldMatchExpectedValue() {
@DisplayName("With empty content")
void withEmptyContent_shouldGenerateNullValue() {
// Given
String yamlFileName = "whenDeserializing_withEmptyContent.yml";
String yamlFileName = "whenDeserializing_withEmptyContent.conf";
Path yamlFile =
TestResourcesHelper.getClassResourceAsAbsolutePath(this.getClass(), yamlFileName);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
import fr.djaytan.minecraft.jobsreborn.patchplacebreak.config.testutils.ValidatorTestWrapper;
import fr.djaytan.minecraft.jobsreborn.patchplacebreak.internal.storage.api.properties.ConnectionPoolProperties;
import jakarta.validation.ConstraintViolation;
import lombok.NonNull;
import nl.jqno.equalsverifier.EqualsVerifier;
import nl.jqno.equalsverifier.Warning;

Expand Down Expand Up @@ -209,7 +210,7 @@ void withValidValues_shouldNotGenerateConstraintViolations(long validConnectionT
assertThat(constraintViolations).isEmpty();
}

private Stream<Arguments> withValidValues_shouldNotGenerateConstraintViolations() {
private @NonNull Stream<Arguments> withValidValues_shouldNotGenerateConstraintViolations() {
return Stream.of(Arguments.of(Named.of("Highest allowed value", 600000)),
Arguments.of(Named.of("Lowest allowed value", 1)));
}
Expand All @@ -236,7 +237,7 @@ void withInvalidValues_shouldGenerateConstraintViolations(long invalidConnection
.equals("connectionTimeout"));
}

private Stream<Arguments> withInvalidValues_shouldGenerateConstraintViolations() {
private @NonNull Stream<Arguments> withInvalidValues_shouldGenerateConstraintViolations() {
return Stream.of(Arguments.of(Named.of("Null value", 0)),
Arguments.of(Named.of("Too high value", 600001)));
}
Expand All @@ -263,7 +264,7 @@ void withValidValues_shouldNotGenerateConstraintViolations(int validPoolSize) {
assertThat(constraintViolations).isEmpty();
}

private Stream<Arguments> withValidValues_shouldNotGenerateConstraintViolations() {
private @NonNull Stream<Arguments> withValidValues_shouldNotGenerateConstraintViolations() {
return Stream.of(Arguments.of(Named.of("Highest allowed value", 100)),
Arguments.of(Named.of("Lowest allowed value", 1)));
}
Expand All @@ -290,7 +291,7 @@ void withInvalidValues_shouldGenerateConstraintViolations(int invalidPoolSize) {
.equals("poolSize"));
}

private Stream<Arguments> withInvalidValues_shouldGenerateConstraintViolations() {
private @NonNull Stream<Arguments> withInvalidValues_shouldGenerateConstraintViolations() {
return Stream.of(Arguments.of(Named.of("Null value", 0)),
Arguments.of(Named.of("Too high value", 101)));
}
Expand All @@ -305,8 +306,8 @@ class WhenDeserializingFromYaml {
@ParameterizedTest(name = "{index} - {0}")
@MethodSource
@DisplayName("With valid content")
void withValidContent_shouldMatchExpectedValue(String yamlFileName,
ConnectionPoolValidatingProperties expectedValue) {
void withValidContent_shouldMatchExpectedValue(@NonNull String yamlFileName,
@NonNull ConnectionPoolValidatingProperties expectedValue) {
// Given
Path yamlFile =
TestResourcesHelper.getClassResourceAsAbsolutePath(this.getClass(), yamlFileName);
Expand All @@ -321,22 +322,22 @@ void withValidContent_shouldMatchExpectedValue(String yamlFileName,
.isEqualTo(expectedValue);
}

private Stream<Arguments> withValidContent_shouldMatchExpectedValue() {
private @NonNull Stream<Arguments> withValidContent_shouldMatchExpectedValue() {
return Stream.of(
Arguments.of(Named.of("With valid values", "whenDeserializing_withValidValues.yml"),
Arguments.of(Named.of("With valid values", "whenDeserializing_withValidValues.conf"),
ConnectionPoolValidatingProperties.of(60000, 10)),
Arguments.of(
Named.of("With unexpected field", "whenDeserializing_withUnexpectedField.yml"),
Named.of("With unexpected field", "whenDeserializing_withUnexpectedField.conf"),
ConnectionPoolValidatingProperties.of(60000, 10)),
Arguments.of(
Named.of("With 'isValidated' field", "whenDeserializing_withIsValidatedField.yml"),
Named.of("With 'isValidated' field", "whenDeserializing_withIsValidatedField.conf"),
ConnectionPoolValidatingProperties.of(60000, 10)));
}

@ParameterizedTest(name = "{index} - {0}")
@MethodSource
@DisplayName("With invalid content")
void withInvalidContent_shouldThrowException(String yamlFileName) {
void withInvalidContent_shouldThrowException(@NonNull String yamlFileName) {
// Given
Path yamlFile =
TestResourcesHelper.getClassResourceAsAbsolutePath(this.getClass(), yamlFileName);
Expand All @@ -350,19 +351,19 @@ void withInvalidContent_shouldThrowException(String yamlFileName) {
.hasCauseExactlyInstanceOf(SerializationException.class);
}

private Stream<Arguments> withInvalidContent_shouldThrowException() {
private @NonNull Stream<Arguments> withInvalidContent_shouldThrowException() {
return Stream.of(
Arguments.of(Named.of("With missing 'connectionTimeout' field",
"whenDeserializing_withMissingConnectionTimeoutField.yml")),
"whenDeserializing_withMissingConnectionTimeoutField.conf")),
Arguments.of(Named.of("With missing 'poolSize' field",
"whenDeserializing_withMissingPoolSizeField.yml")));
"whenDeserializing_withMissingPoolSizeField.conf")));
}

@Test
@DisplayName("With empty content")
void withEmptyContent_shouldGenerateNullValue() {
// Given
String yamlFileName = "whenDeserializing_withEmptyContent.yml";
String yamlFileName = "whenDeserializing_withEmptyContent.conf";
Path yamlFile =
TestResourcesHelper.getClassResourceAsAbsolutePath(this.getClass(), yamlFileName);

Expand Down
Loading

0 comments on commit a44c085

Please sign in to comment.