Skip to content

Commit 2f5e9b5

Browse files
committed
Auto-configure XmlMapper.Builder and XmlMapper
Closes gh-47942
1 parent 2f33f73 commit 2f5e9b5

File tree

4 files changed

+295
-4
lines changed

4 files changed

+295
-4
lines changed

module/spring-boot-jackson/src/main/java/org/springframework/boot/jackson/autoconfigure/JacksonAutoConfiguration.java

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import tools.jackson.databind.cfg.MapperBuilder;
4141
import tools.jackson.databind.json.JsonMapper;
4242
import tools.jackson.dataformat.cbor.CBORMapper;
43+
import tools.jackson.dataformat.xml.XmlMapper;
4344

4445
import org.springframework.aot.hint.ReflectionHints;
4546
import org.springframework.aot.hint.RuntimeHints;
@@ -163,7 +164,7 @@ public void customize(JsonMapper.Builder builder) {
163164

164165
@Configuration(proxyBeanMethods = false)
165166
@ConditionalOnClass(ProblemDetail.class)
166-
static class ProblemDetailsConfiguration {
167+
static class JsonProblemDetailsConfiguration {
167168

168169
@Bean
169170
ProblemDetailJsonMapperBuilderCustomizer problemDetailJsonMapperBuilderCustomizer() {
@@ -236,6 +237,80 @@ public void customize(CBORMapper.Builder builder) {
236237

237238
}
238239

240+
@Configuration(proxyBeanMethods = false)
241+
@ConditionalOnClass(XmlMapper.class)
242+
@EnableConfigurationProperties(JacksonXmlProperties.class)
243+
static class XmlConfiguration {
244+
245+
@Bean
246+
@ConditionalOnMissingBean
247+
XmlMapper xmlMapper(XmlMapper.Builder builder) {
248+
return builder.build();
249+
}
250+
251+
@Bean
252+
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
253+
@ConditionalOnMissingBean
254+
XmlMapper.Builder xmlMapperBuilder(List<XmlMapperBuilderCustomizer> customizers) {
255+
XmlMapper.Builder builder = XmlMapper.builder();
256+
customize(builder, customizers);
257+
return builder;
258+
}
259+
260+
private void customize(XmlMapper.Builder builder, List<XmlMapperBuilderCustomizer> customizers) {
261+
for (XmlMapperBuilderCustomizer customizer : customizers) {
262+
customizer.customize(builder);
263+
}
264+
}
265+
266+
@Bean
267+
StandardXmlMapperBuilderCustomizer standardXmlMapperBuilderCustomizer(JacksonProperties jacksonProperties,
268+
ObjectProvider<JacksonModule> modules, JacksonXmlProperties xmlProperties) {
269+
return new StandardXmlMapperBuilderCustomizer(jacksonProperties, modules.stream().toList(), xmlProperties);
270+
}
271+
272+
@Configuration(proxyBeanMethods = false)
273+
@ConditionalOnClass(ProblemDetail.class)
274+
static class XmlProblemDetailsConfiguration {
275+
276+
@Bean
277+
ProblemDetailXmlMapperBuilderCustomizer problemDetailXmlMapperBuilderCustomizer() {
278+
return new ProblemDetailXmlMapperBuilderCustomizer();
279+
}
280+
281+
static final class ProblemDetailXmlMapperBuilderCustomizer implements XmlMapperBuilderCustomizer {
282+
283+
@Override
284+
public void customize(XmlMapper.Builder builder) {
285+
builder.addMixIn(ProblemDetail.class, ProblemDetailJacksonMixin.class);
286+
}
287+
288+
}
289+
290+
}
291+
292+
static class StandardXmlMapperBuilderCustomizer extends AbstractMapperBuilderCustomizer<XmlMapper.Builder>
293+
implements XmlMapperBuilderCustomizer {
294+
295+
private final JacksonXmlProperties xmlProperties;
296+
297+
StandardXmlMapperBuilderCustomizer(JacksonProperties jacksonProperties, Collection<JacksonModule> modules,
298+
JacksonXmlProperties xmlProperties) {
299+
super(jacksonProperties, modules);
300+
this.xmlProperties = xmlProperties;
301+
}
302+
303+
@Override
304+
public void customize(XmlMapper.Builder builder) {
305+
super.customize(builder);
306+
configureFeatures(builder, this.xmlProperties.getRead(), builder::configure);
307+
configureFeatures(builder, this.xmlProperties.getWrite(), builder::configure);
308+
}
309+
310+
}
311+
312+
}
313+
239314
static class JacksonAutoConfigurationRuntimeHints implements RuntimeHintsRegistrar {
240315

241316
@Override
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright 2012-present 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.jackson.autoconfigure;
18+
19+
import java.util.EnumMap;
20+
import java.util.Map;
21+
22+
import tools.jackson.dataformat.xml.XmlReadFeature;
23+
import tools.jackson.dataformat.xml.XmlWriteFeature;
24+
25+
import org.springframework.boot.context.properties.ConfigurationProperties;
26+
27+
/**
28+
* Configuration properties to configure Jackson's XML support.
29+
*
30+
* @author Andy Wilkinson
31+
* @since 4.0.0
32+
*/
33+
@ConfigurationProperties("spring.jackson.xml")
34+
public class JacksonXmlProperties {
35+
36+
/**
37+
* Jackson on/off token reader features that are specific to XML.
38+
*/
39+
private final Map<XmlReadFeature, Boolean> read = new EnumMap<>(XmlReadFeature.class);
40+
41+
/**
42+
* Jackson on/off token writer features that are specific to XML.
43+
*/
44+
private final Map<XmlWriteFeature, Boolean> write = new EnumMap<>(XmlWriteFeature.class);
45+
46+
public Map<XmlReadFeature, Boolean> getRead() {
47+
return this.read;
48+
}
49+
50+
public Map<XmlWriteFeature, Boolean> getWrite() {
51+
return this.write;
52+
}
53+
54+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright 2012-present 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.jackson.autoconfigure;
18+
19+
import tools.jackson.dataformat.cbor.CBORMapper.Builder;
20+
import tools.jackson.dataformat.xml.XmlMapper;
21+
22+
/**
23+
* Callback interface that can be implemented by beans wishing to further customize the
24+
* {@link XmlMapper} through {@link Builder XmlMapper.Builder} to fine-tune its
25+
* auto-configuration.
26+
*
27+
* @author Andy Wilkinson
28+
* @since 4.0.0
29+
*/
30+
@FunctionalInterface
31+
public interface XmlMapperBuilderCustomizer {
32+
33+
/**
34+
* Customize the XmlMapper.Builder.
35+
* @param xmlMapperBuilder the builder to customize
36+
*/
37+
void customize(XmlMapper.Builder xmlMapperBuilder);
38+
39+
}

0 commit comments

Comments
 (0)