Repository: jhipster/jhipster-lite
Pull request #10911 (2024-09-19 15:38:43)

fix(spring-yaml-properties): preserve order of an existing property when updating its value
See #10909


Patch:
diff --git a/pom.xml b/pom.xml
index d059265a6..49f6b6e74 100644
--- a/pom.xml
+++ b/pom.xml
@@ -69,7 +69,7 @@
     <springdoc-openapi-starter-webmvc-ui.version>2.6.0</springdoc-openapi-starter-webmvc-ui.version>
     <properties-maven-plugin.version>1.2.1</properties-maven-plugin.version>
     <sonar-maven-plugin.version>4.0.0.4121</sonar-maven-plugin.version>
-    <apache-commons-io.version>2.17.0</apache-commons-io.version>
+    <apache-commons-io.version>2.16.1</apache-commons-io.version>
     <cucumber.version>7.18.1</cucumber.version>
     <maven-model-helper.version>37</maven-model-helper.version>
     <mustache.java.version>0.9.14</mustache.java.version>
@@ -82,7 +82,7 @@
     <frontend-maven-plugin.version>1.15.0</frontend-maven-plugin.version>
     <checksum-maven-plugin.version>1.11</checksum-maven-plugin.version>
     <maven-antrun-plugin.version>3.1.0</maven-antrun-plugin.version>
-    <approvaltests.version>24.5.0</approvaltests.version>
+    <approvaltests.version>24.4.0</approvaltests.version>
   </properties>
 
   <dependencyManagement>
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 8b2813f39..3f24e9f0a 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 @@ class YamlFileSpringPropertiesHandler {
 
     List<NodeTuple> 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<NodeTuple> removeNode(List<NodeTuple> parentValue) {
-    return parentValue::remove;
+  private Optional<Integer> indexInCollection(List<NodeTuple> nodesTuples, String key) {
+    Predicate<NodeTuple> 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/main/resources/generator/dependencies/pom.xml b/src/main/resources/generator/dependencies/pom.xml
index a383ae80c..a8ac30e5d 100644
--- a/src/main/resources/generator/dependencies/pom.xml
+++ b/src/main/resources/generator/dependencies/pom.xml
@@ -34,7 +34,7 @@
     <webjars-locator.version>0.52</webjars-locator.version>
     <htmx-webjars.version>2.0.2</htmx-webjars.version>
     <alpinejs-webjars.version>3.14.1</alpinejs-webjars.version>
-    <protobuf.version>4.28.2</protobuf.version>
+    <protobuf.version>4.28.1</protobuf.version>
     <proto-backwards-compatibility.version>1.0.7</proto-backwards-compatibility.version>
     <jmolecules-bom.version>2023.1.4</jmolecules-bom.version>
     <jqassistant.version>2.4.0</jqassistant.version>
diff --git a/src/main/resources/generator/dependencies/react/package.json b/src/main/resources/generator/dependencies/react/package.json
index cfbfc60e9..5a28a1ee1 100644
--- a/src/main/resources/generator/dependencies/react/package.json
+++ b/src/main/resources/generator/dependencies/react/package.json
@@ -5,7 +5,7 @@
   "license": "Apache-2.0",
   "type": "module",
   "dependencies": {
-    "@nextui-org/react": "2.4.8",
+    "@nextui-org/react": "2.4.7",
     "axios": "1.7.7",
     "react": "18.3.1",
     "react-dom": "18.3.1",


Test patch:
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 21293d4bd..4d7643e57 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 @@ class YamlFileSpringPropertiesHandlerTest {
       );
     }
 
+    @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 000000000..774bacf79
--- /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