From 4319554f8a721442993b4538f1828dbc5949a5dd Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 12 Feb 2024 10:13:04 +0000 Subject: [PATCH] Fix mapping of boolean properties to Gson's builder Fixes gh-39504 --- .../gson/GsonAutoConfiguration.java | 19 +++-- .../gson/GsonAutoConfigurationTests.java | 80 ++++++++++++++++--- 2 files changed, 82 insertions(+), 17 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/gson/GsonAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/gson/GsonAutoConfiguration.java index 4fd3f99778c..f81ecacf007 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/gson/GsonAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/gson/GsonAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -78,17 +78,22 @@ public class GsonAutoConfiguration { public void customize(GsonBuilder builder) { GsonProperties properties = this.properties; PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); - map.from(properties::getGenerateNonExecutableJson).toCall(builder::generateNonExecutableJson); + map.from(properties::getGenerateNonExecutableJson).whenTrue().toCall(builder::generateNonExecutableJson); map.from(properties::getExcludeFieldsWithoutExposeAnnotation) + .whenTrue() .toCall(builder::excludeFieldsWithoutExposeAnnotation); map.from(properties::getSerializeNulls).whenTrue().toCall(builder::serializeNulls); - map.from(properties::getEnableComplexMapKeySerialization).toCall(builder::enableComplexMapKeySerialization); - map.from(properties::getDisableInnerClassSerialization).toCall(builder::disableInnerClassSerialization); + map.from(properties::getEnableComplexMapKeySerialization) + .whenTrue() + .toCall(builder::enableComplexMapKeySerialization); + map.from(properties::getDisableInnerClassSerialization) + .whenTrue() + .toCall(builder::disableInnerClassSerialization); map.from(properties::getLongSerializationPolicy).to(builder::setLongSerializationPolicy); map.from(properties::getFieldNamingPolicy).to(builder::setFieldNamingPolicy); - map.from(properties::getPrettyPrinting).toCall(builder::setPrettyPrinting); - map.from(properties::getLenient).toCall(builder::setLenient); - map.from(properties::getDisableHtmlEscaping).toCall(builder::disableHtmlEscaping); + map.from(properties::getPrettyPrinting).whenTrue().toCall(builder::setPrettyPrinting); + map.from(properties::getLenient).whenTrue().toCall(builder::setLenient); + map.from(properties::getDisableHtmlEscaping).whenFalse().toCall(builder::disableHtmlEscaping); map.from(properties::getDateFormat).to(builder::setDateFormat); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/gson/GsonAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/gson/GsonAutoConfigurationTests.java index 9084e4a4940..e53b013aefa 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/gson/GsonAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/gson/GsonAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -59,7 +59,7 @@ class GsonAutoConfigurationTests { } @Test - void generateNonExecutableJson() { + void generateNonExecutableJsonTrue() { this.contextRunner.withPropertyValues("spring.gson.generate-non-executable-json:true").run((context) -> { Gson gson = context.getBean(Gson.class); assertThat(gson.toJson(new DataObject())).isNotEqualTo("{\"data\":1}"); @@ -68,7 +68,15 @@ class GsonAutoConfigurationTests { } @Test - void excludeFieldsWithoutExposeAnnotation() { + void generateNonExecutableJsonFalse() { + this.contextRunner.withPropertyValues("spring.gson.generate-non-executable-json:false").run((context) -> { + Gson gson = context.getBean(Gson.class); + assertThat(gson.toJson(new DataObject())).isEqualTo("{\"data\":1}"); + }); + } + + @Test + void excludeFieldsWithoutExposeAnnotationTrue() { this.contextRunner.withPropertyValues("spring.gson.exclude-fields-without-expose-annotation:true") .run((context) -> { Gson gson = context.getBean(Gson.class); @@ -76,6 +84,15 @@ class GsonAutoConfigurationTests { }); } + @Test + void excludeFieldsWithoutExposeAnnotationFalse() { + this.contextRunner.withPropertyValues("spring.gson.exclude-fields-without-expose-annotation:false") + .run((context) -> { + Gson gson = context.getBean(Gson.class); + assertThat(gson.toJson(new DataObject())).isEqualTo("{\"data\":1}"); + }); + } + @Test void serializeNullsTrue() { this.contextRunner.withPropertyValues("spring.gson.serialize-nulls:true").run((context) -> { @@ -93,7 +110,7 @@ class GsonAutoConfigurationTests { } @Test - void enableComplexMapKeySerialization() { + void enableComplexMapKeySerializationTrue() { this.contextRunner.withPropertyValues("spring.gson.enable-complex-map-key-serialization:true") .run((context) -> { Gson gson = context.getBean(Gson.class); @@ -103,6 +120,17 @@ class GsonAutoConfigurationTests { }); } + @Test + void enableComplexMapKeySerializationFalse() { + this.contextRunner.withPropertyValues("spring.gson.enable-complex-map-key-serialization:false") + .run((context) -> { + Gson gson = context.getBean(Gson.class); + Map original = new LinkedHashMap<>(); + original.put(new DataObject(), "a"); + assertThat(gson.toJson(original)).contains(DataObject.class.getName()).doesNotContain("\"data\":"); + }); + } + @Test void notDisableInnerClassSerialization() { this.contextRunner.run((context) -> { @@ -113,7 +141,7 @@ class GsonAutoConfigurationTests { } @Test - void disableInnerClassSerialization() { + void disableInnerClassSerializationTrue() { this.contextRunner.withPropertyValues("spring.gson.disable-inner-class-serialization:true").run((context) -> { Gson gson = context.getBean(Gson.class); WrapperObject wrapperObject = new WrapperObject(); @@ -121,6 +149,15 @@ class GsonAutoConfigurationTests { }); } + @Test + void disableInnerClassSerializationFalse() { + this.contextRunner.withPropertyValues("spring.gson.disable-inner-class-serialization:false").run((context) -> { + Gson gson = context.getBean(Gson.class); + WrapperObject wrapperObject = new WrapperObject(); + assertThat(gson.toJson(wrapperObject.new NestedObject())).isEqualTo("{\"data\":\"nested\"}"); + }); + } + @Test void withLongSerializationPolicy() { this.contextRunner.withPropertyValues("spring.gson.long-serialization-policy:" + LongSerializationPolicy.STRING) @@ -156,13 +193,21 @@ class GsonAutoConfigurationTests { } @Test - void withPrettyPrinting() { + void withPrettyPrintingTrue() { this.contextRunner.withPropertyValues("spring.gson.pretty-printing:true").run((context) -> { Gson gson = context.getBean(Gson.class); assertThat(gson.toJson(new DataObject())).isEqualTo("{\n \"data\": 1\n}"); }); } + @Test + void withPrettyPrintingFalse() { + this.contextRunner.withPropertyValues("spring.gson.pretty-printing:false").run((context) -> { + Gson gson = context.getBean(Gson.class); + assertThat(gson.toJson(new DataObject())).isEqualTo("{\"data\":1}"); + }); + } + @Test void withoutLenient() { this.contextRunner.run((context) -> { @@ -172,7 +217,7 @@ class GsonAutoConfigurationTests { } @Test - void withLenient() { + void withLenientTrue() { this.contextRunner.withPropertyValues("spring.gson.lenient:true").run((context) -> { Gson gson = context.getBean(Gson.class); assertThat(gson).hasFieldOrPropertyWithValue("lenient", true); @@ -180,7 +225,15 @@ class GsonAutoConfigurationTests { } @Test - void withHtmlEscaping() { + void withLenientFalse() { + this.contextRunner.withPropertyValues("spring.gson.lenient:false").run((context) -> { + Gson gson = context.getBean(Gson.class); + assertThat(gson).hasFieldOrPropertyWithValue("lenient", false); + }); + } + + @Test + void withoutDisableHtmlEscaping() { this.contextRunner.run((context) -> { Gson gson = context.getBean(Gson.class); assertThat(gson.htmlSafe()).isTrue(); @@ -188,12 +241,19 @@ class GsonAutoConfigurationTests { } @Test - void withoutHtmlEscaping() { + void withDisableHtmlEscapingTrue() { this.contextRunner.withPropertyValues("spring.gson.disable-html-escaping:true").run((context) -> { + Gson gson = context.getBean(Gson.class); + assertThat(gson.htmlSafe()).isTrue(); + }); + } + + @Test + void withDisableHtmlEscapingFalse() { + this.contextRunner.withPropertyValues("spring.gson.disable-html-escaping:false").run((context) -> { Gson gson = context.getBean(Gson.class); assertThat(gson.htmlSafe()).isFalse(); }); - } @Test