Skip to content

Commit d4c7013

Browse files
committed
Tolerate Gson 2.10 and earlier
Closes gh-43442
1 parent c66514c commit d4c7013

File tree

4 files changed

+177
-4
lines changed

4 files changed

+177
-4
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/gson/GsonAutoConfiguration.java

+17-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2024 the original author or authors.
2+
* Copyright 2012-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,9 +17,11 @@
1717
package org.springframework.boot.autoconfigure.gson;
1818

1919
import java.util.List;
20+
import java.util.function.Consumer;
2021

2122
import com.google.gson.Gson;
2223
import com.google.gson.GsonBuilder;
24+
import com.google.gson.Strictness;
2325

2426
import org.springframework.boot.autoconfigure.AutoConfiguration;
2527
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@@ -29,6 +31,7 @@
2931
import org.springframework.boot.context.properties.PropertyMapper;
3032
import org.springframework.context.annotation.Bean;
3133
import org.springframework.core.Ordered;
34+
import org.springframework.util.ClassUtils;
3235

3336
/**
3437
* {@link EnableAutoConfiguration Auto-configuration} for Gson.
@@ -92,11 +95,23 @@ public void customize(GsonBuilder builder) {
9295
map.from(properties::getLongSerializationPolicy).to(builder::setLongSerializationPolicy);
9396
map.from(properties::getFieldNamingPolicy).to(builder::setFieldNamingPolicy);
9497
map.from(properties::getPrettyPrinting).whenTrue().toCall(builder::setPrettyPrinting);
95-
map.from(properties::getStrictness).to(builder::setStrictness);
98+
map.from(properties::getStrictness).to(strictnessOrLeniency(builder));
9699
map.from(properties::getDisableHtmlEscaping).whenTrue().toCall(builder::disableHtmlEscaping);
97100
map.from(properties::getDateFormat).to(builder::setDateFormat);
98101
}
99102

103+
@SuppressWarnings("deprecation")
104+
private Consumer<GsonProperties.Strictness> strictnessOrLeniency(GsonBuilder builder) {
105+
if (ClassUtils.isPresent("com.google.gson.Strictness", getClass().getClassLoader())) {
106+
return (strictness) -> builder.setStrictness(Strictness.valueOf(strictness.name()));
107+
}
108+
return (strictness) -> {
109+
if (strictness == GsonProperties.Strictness.LENIENT) {
110+
builder.setLenient();
111+
}
112+
};
113+
}
114+
100115
}
101116

102117
}

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/gson/GsonProperties.java

+27-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2024 the original author or authors.
2+
* Copyright 2012-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,7 +19,6 @@
1919
import com.google.gson.FieldNamingPolicy;
2020
import com.google.gson.Gson;
2121
import com.google.gson.LongSerializationPolicy;
22-
import com.google.gson.Strictness;
2322

2423
import org.springframework.boot.context.properties.ConfigurationProperties;
2524
import org.springframework.boot.context.properties.DeprecatedConfigurationProperty;
@@ -190,4 +189,30 @@ public void setDateFormat(String dateFormat) {
190189
this.dateFormat = dateFormat;
191190
}
192191

192+
/**
193+
* Enumeration of levels of strictness. Values are the same as those on
194+
* {@link com.google.gson.Strictness} that was introduced in Gson 2.11. To maximize
195+
* backwards compatibility, the Gson enum is not used directly.
196+
*
197+
* @since 3.4.1
198+
*/
199+
public enum Strictness {
200+
201+
/**
202+
* Lenient compliance.
203+
*/
204+
LENIENT,
205+
206+
/**
207+
* Strict compliance with some small deviations for legacy reasons.
208+
*/
209+
LEGACY_STRICT,
210+
211+
/**
212+
* Strict compliance.
213+
*/
214+
STRICT
215+
216+
}
217+
193218
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Copyright 2012-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.gson;
18+
19+
import com.google.gson.Gson;
20+
import org.junit.jupiter.api.Test;
21+
22+
import org.springframework.boot.autoconfigure.AutoConfigurations;
23+
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
24+
import org.springframework.boot.testsupport.classpath.ClassPathExclusions;
25+
import org.springframework.boot.testsupport.classpath.ClassPathOverrides;
26+
27+
import static org.assertj.core.api.Assertions.assertThat;
28+
29+
/**
30+
* Tests for {@link GsonAutoConfiguration} with Gson 2.10.
31+
*
32+
* @author Andy Wilkinson
33+
*/
34+
@ClassPathExclusions("gson-*.jar")
35+
@ClassPathOverrides("com.google.code.gson:gson:2.10")
36+
class Gson210AutoConfigurationTests {
37+
38+
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
39+
.withConfiguration(AutoConfigurations.of(GsonAutoConfiguration.class));
40+
41+
@Test
42+
void gsonRegistration() {
43+
this.contextRunner.run((context) -> {
44+
Gson gson = context.getBean(Gson.class);
45+
assertThat(gson.toJson(new DataObject())).isEqualTo("{\"data\":1}");
46+
});
47+
}
48+
49+
@Test
50+
@Deprecated(since = "3.4.0", forRemoval = true)
51+
void withoutLenient() {
52+
this.contextRunner.run((context) -> {
53+
Gson gson = context.getBean(Gson.class);
54+
assertThat(gson).hasFieldOrPropertyWithValue("lenient", false);
55+
});
56+
}
57+
58+
@Test
59+
@Deprecated(since = "3.4.0", forRemoval = true)
60+
void withLenientTrue() {
61+
this.contextRunner.withPropertyValues("spring.gson.lenient:true").run((context) -> {
62+
Gson gson = context.getBean(Gson.class);
63+
assertThat(gson).hasFieldOrPropertyWithValue("lenient", true);
64+
});
65+
}
66+
67+
@Test
68+
@Deprecated(since = "3.4.0", forRemoval = true)
69+
void withLenientFalse() {
70+
this.contextRunner.withPropertyValues("spring.gson.lenient:false").run((context) -> {
71+
Gson gson = context.getBean(Gson.class);
72+
assertThat(gson).hasFieldOrPropertyWithValue("lenient", false);
73+
});
74+
}
75+
76+
public class DataObject {
77+
78+
@SuppressWarnings("unused")
79+
private Long data = 1L;
80+
81+
@SuppressWarnings("unused")
82+
private final String owner = null;
83+
84+
public void setData(Long data) {
85+
this.data = data;
86+
}
87+
88+
}
89+
90+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright 2012-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.gson;
18+
19+
import java.util.List;
20+
import java.util.stream.Stream;
21+
22+
import com.google.gson.Strictness;
23+
import org.junit.jupiter.api.Test;
24+
25+
import static org.assertj.core.api.Assertions.assertThat;
26+
27+
/**
28+
* Tests for {@link GsonProperties}.
29+
*
30+
* @author Andy Wilkinson
31+
*/
32+
class GsonPropertiesTests {
33+
34+
@Test
35+
void valuesOfOurStrictnessMatchValuesOfGsonsStrictness() {
36+
assertThat(namesOf(GsonProperties.Strictness.values())).isEqualTo(namesOf(Strictness.values()));
37+
}
38+
39+
private List<String> namesOf(Enum<?>[] input) {
40+
return Stream.of(input).map(Enum::name).toList();
41+
}
42+
43+
}

0 commit comments

Comments
 (0)