diff --git a/src/main/java/com/hubspot/jinjava/JinjavaConfig.java b/src/main/java/com/hubspot/jinjava/JinjavaConfig.java index 99a54a784..d2b1a0f71 100644 --- a/src/main/java/com/hubspot/jinjava/JinjavaConfig.java +++ b/src/main/java/com/hubspot/jinjava/JinjavaConfig.java @@ -17,8 +17,10 @@ import static com.hubspot.jinjava.lib.fn.Functions.DEFAULT_RANGE_LIMIT; +import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.SerializationFeature; import com.google.common.collect.ImmutableSet; import com.hubspot.jinjava.el.JinjavaInterpreterResolver; import com.hubspot.jinjava.el.JinjavaObjectUnwrapper; @@ -161,6 +163,10 @@ private ObjectMapper setupObjectMapper(@Nullable ObjectMapper objectMapper) { if (legacyOverrides.isUseSnakeCasePropertyNaming()) { objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); } + return objectMapper + .copy() + .configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true) + .configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true); } return objectMapper; } diff --git a/src/test/java/com/hubspot/jinjava/lib/filter/ToJsonFilterTest.java b/src/test/java/com/hubspot/jinjava/lib/filter/ToJsonFilterTest.java index deeced69e..5ed0d6a26 100644 --- a/src/test/java/com/hubspot/jinjava/lib/filter/ToJsonFilterTest.java +++ b/src/test/java/com/hubspot/jinjava/lib/filter/ToJsonFilterTest.java @@ -2,7 +2,12 @@ import static org.assertj.core.api.Java6Assertions.assertThat; +import com.fasterxml.jackson.databind.ObjectMapper; import com.hubspot.jinjava.BaseInterpretingTest; +import com.hubspot.jinjava.Jinjava; +import com.hubspot.jinjava.JinjavaConfig; +import com.hubspot.jinjava.interpret.JinjavaInterpreter; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import org.junit.Before; @@ -27,4 +32,44 @@ public void itWritesObjectAsString() { assertThat(filter.filter(testMap, interpreter)) .isEqualTo("{\"testArray\":[4,1,2],\"testString\":\"testString\"}"); } + + @Test + public void itWritesObjectWithOrderedKeyAsString() { + int[] testArray = new int[] { 4, 1, 2 }; + Map testMap = new HashMap<>(); + testMap.put("testString", "testString"); + testMap.put("testArray", testArray); + testMap.put("another", "ab"); + Map nested = new HashMap<>(); + nested.put("innerKey2", "v2"); + nested.put("innerKey1", "v1"); + testMap.put("nested", nested); + assertThat(filter.filter(testMap, interpreter)) + .isEqualTo( + "{\"another\":\"ab\",\"nested\":{\"innerKey1\":\"v1\",\"innerKey2\":\"v2\"},\"testArray\":[4,1,2],\"testString\":\"testString\"}" + ); + } + + @Test + public void itWritesObjectWithoutOrderedKeyAsString() { + int[] testArray = new int[] { 4, 1, 2 }; + Map testMap = new HashMap<>(); + testMap.put("testString", "testString"); + testMap.put("testArray", testArray); + testMap.put("another", "ab"); + Map nested = new HashMap<>(); + nested.put("innerKey2", "v2"); + nested.put("innerKey1", "v1"); + testMap.put("nested", nested); + + Jinjava jinjava = new Jinjava( + JinjavaConfig.newBuilder().withObjectMapper(new ObjectMapper()).build() + ); + JinjavaInterpreter interpreter = jinjava.newInterpreter(); + assertThat(filter.filter(testMap, interpreter)) + .isEqualTo( + """ +{"testArray":[4,1,2],"another":"ab","testString":"testString","nested":{"innerKey2":"v2","innerKey1":"v1"}}""" + ); + } }