From ac9bc48241aa72dc16e292f6b463a5218103ed4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Mino?= Date: Thu, 19 Sep 2024 17:37:52 +0200 Subject: [PATCH] fix(spring-yaml-properties): preserve order of an existing property when updating its value See #10909 --- .../YamlFileSpringPropertiesHandler.java | 48 ++++++++----------- .../YamlFileSpringPropertiesHandlerTest.java | 31 ++++++++++++ .../more-complex-application.yml | 14 ++++++ 3 files changed, 64 insertions(+), 29 deletions(-) create mode 100644 src/test/resources/projects/project-with-spring-application-yaml/more-complex-application.yml diff --git a/src/main/java/tech/jhipster/lite/module/infrastructure/secondary/YamlFileSpringPropertiesHandler.java b/src/main/java/tech/jhipster/lite/module/infrastructure/secondary/YamlFileSpringPropertiesHandler.java index 8b2813f390f..3f24e9f0a01 100644 --- a/src/main/java/tech/jhipster/lite/module/infrastructure/secondary/YamlFileSpringPropertiesHandler.java +++ b/src/main/java/tech/jhipster/lite/module/infrastructure/secondary/YamlFileSpringPropertiesHandler.java @@ -1,39 +1,21 @@ package tech.jhipster.lite.module.infrastructure.secondary; -import static org.yaml.snakeyaml.comments.CommentType.*; +import static org.yaml.snakeyaml.comments.CommentType.BLOCK; -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.Writer; +import java.io.*; import java.nio.file.Files; import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.function.Consumer; +import java.util.*; import java.util.function.Function; import java.util.function.Predicate; -import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.*; import org.yaml.snakeyaml.DumperOptions.FlowStyle; -import org.yaml.snakeyaml.LoaderOptions; -import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.comments.CommentLine; import org.yaml.snakeyaml.constructor.Constructor; -import org.yaml.snakeyaml.nodes.MappingNode; -import org.yaml.snakeyaml.nodes.Node; -import org.yaml.snakeyaml.nodes.NodeTuple; -import org.yaml.snakeyaml.nodes.ScalarNode; -import org.yaml.snakeyaml.nodes.SequenceNode; -import org.yaml.snakeyaml.nodes.Tag; +import org.yaml.snakeyaml.nodes.*; import org.yaml.snakeyaml.representer.Representer; import tech.jhipster.lite.module.domain.Indentation; -import tech.jhipster.lite.module.domain.javaproperties.Comment; -import tech.jhipster.lite.module.domain.javaproperties.PropertyKey; -import tech.jhipster.lite.module.domain.javaproperties.PropertyValue; +import tech.jhipster.lite.module.domain.javaproperties.*; import tech.jhipster.lite.shared.error.domain.Assert; import tech.jhipster.lite.shared.error.domain.GeneratorException; import tech.jhipster.lite.shared.generation.domain.ExcludeFromGeneratedCodeCoverage; @@ -91,13 +73,21 @@ private void appendPropertyToConfiguration(PropertyKey key, PropertyValue value, List parentValue = parentPropertyNode(key, configuration).getValue(); - parentValue.stream().filter(nodeTupleKeyEquals(localKey)).findFirst().ifPresent(removeNode(parentValue)); - - parentValue.add(new NodeTuple(buildScalarNode(localKey), buildValueNode(value))); + NodeTuple nodeProperty = new NodeTuple(buildScalarNode(localKey), buildValueNode(value)); + indexInCollection(parentValue, localKey).ifPresentOrElse( + index -> parentValue.set(index, nodeProperty), + () -> parentValue.add(nodeProperty) + ); } - private Consumer removeNode(List parentValue) { - return parentValue::remove; + private Optional indexInCollection(List nodesTuples, String key) { + Predicate matchesKey = nodeTupleKeyEquals(key); + for (int i = 0; i < nodesTuples.size(); i++) { + if (matchesKey.test(nodesTuples.get(i))) { + return Optional.of(i); + } + } + return Optional.empty(); } private Node buildValueNode(PropertyValue value) { diff --git a/src/test/java/tech/jhipster/lite/module/infrastructure/secondary/YamlFileSpringPropertiesHandlerTest.java b/src/test/java/tech/jhipster/lite/module/infrastructure/secondary/YamlFileSpringPropertiesHandlerTest.java index 21293d4bd56..4d7643e5783 100644 --- a/src/test/java/tech/jhipster/lite/module/infrastructure/secondary/YamlFileSpringPropertiesHandlerTest.java +++ b/src/test/java/tech/jhipster/lite/module/infrastructure/secondary/YamlFileSpringPropertiesHandlerTest.java @@ -68,6 +68,37 @@ void shouldAppendPropertyToFileWithProperties() { ); } + @Test + void shouldKeepExistingOrderWhenReplacingAProperty() { + Path yamlFile = Paths.get(TestFileUtils.tmpDirForTest(), "src/main/resources/application.yml"); + loadDefaultProperties( + Paths.get("src/test/resources/projects/project-with-spring-application-yaml/more-complex-application.yml"), + yamlFile + ); + YamlFileSpringPropertiesHandler handler = new YamlFileSpringPropertiesHandler(yamlFile, Indentation.DEFAULT); + + handler.setValue(propertyKey("spring.datasource.driver-class-name"), propertyValue("org.postgresql.Driver")); + + assertThat(content(yamlFile)).contains( + """ + spring: + data: + jpa: + repositories: + bootstrap-mode: deferred + datasource: + driver-class-name: org.postgresql.Driver + hikari: + auto-commit: false + poolName: Hikari + password: '' + type: com.zaxxer.hikari.HikariDataSource + url: jdbc:postgresql://localhost:5432/myapp + username: myapp + """ + ); + } + @Test void shouldRespectProjectIndentation() { Path yamlFile = Paths.get(TestFileUtils.tmpDirForTest(), "src/main/resources/application.yml"); diff --git a/src/test/resources/projects/project-with-spring-application-yaml/more-complex-application.yml b/src/test/resources/projects/project-with-spring-application-yaml/more-complex-application.yml new file mode 100644 index 00000000000..774bacf79cc --- /dev/null +++ b/src/test/resources/projects/project-with-spring-application-yaml/more-complex-application.yml @@ -0,0 +1,14 @@ +spring: + data: + jpa: + repositories: + bootstrap-mode: deferred + datasource: + driver-class-name: org.postgresql.Driver + hikari: + auto-commit: false + poolName: Hikari + password: '' + type: com.zaxxer.hikari.HikariDataSource + url: jdbc:postgresql://localhost:5432/myapp + username: myapp