Skip to content

Commit 7b861c9

Browse files
committed
Add defaultUseWrapper support to Jackson builder
Issue: SPR-13975
1 parent ffbf264 commit 7b861c9

File tree

3 files changed

+68
-2
lines changed

3 files changed

+68
-2
lines changed

spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@
4747
import com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder;
4848
import com.fasterxml.jackson.databind.module.SimpleModule;
4949
import com.fasterxml.jackson.databind.ser.FilterProvider;
50+
import com.fasterxml.jackson.dataformat.xml.JacksonXmlModule;
51+
import com.fasterxml.jackson.dataformat.xml.XmlFactory;
5052
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
5153

5254
import org.springframework.beans.BeanUtils;
@@ -127,6 +129,8 @@ public class Jackson2ObjectMapperBuilder {
127129

128130
private ApplicationContext applicationContext;
129131

132+
private Boolean defaultUseWrapper;
133+
130134

131135
/**
132136
* If set to {@code true}, an {@link XmlMapper} will be created using its
@@ -392,6 +396,16 @@ public Jackson2ObjectMapperBuilder indentOutput(boolean indentOutput) {
392396
return this;
393397
}
394398

399+
/**
400+
* Define if a wrapper will be used for indexed (List, array) properties or not by
401+
* default (only applies to {@link XmlMapper}).
402+
* @since 4.3
403+
*/
404+
public Jackson2ObjectMapperBuilder defaultUseWrapper(boolean defaultUseWrapper) {
405+
this.defaultUseWrapper = defaultUseWrapper;
406+
return this;
407+
}
408+
395409
/**
396410
* Specify features to enable.
397411
* @see com.fasterxml.jackson.core.JsonParser.Feature
@@ -547,7 +561,8 @@ public Jackson2ObjectMapperBuilder applicationContext(ApplicationContext applica
547561
public <T extends ObjectMapper> T build() {
548562
ObjectMapper mapper;
549563
if (this.createXmlMapper) {
550-
mapper = new XmlObjectMapperInitializer().create();
564+
mapper = (this.defaultUseWrapper == null ? new XmlObjectMapperInitializer().create()
565+
: new XmlObjectMapperInitializer().create(this.defaultUseWrapper));
551566
}
552567
else {
553568
mapper = new ObjectMapper();
@@ -757,11 +772,21 @@ public static Jackson2ObjectMapperBuilder xml() {
757772
private static class XmlObjectMapperInitializer {
758773

759774
public ObjectMapper create() {
775+
return new XmlMapper(xmlInputFactory());
776+
}
777+
778+
public ObjectMapper create(boolean defaultUseWrapper) {
779+
JacksonXmlModule module = new JacksonXmlModule();
780+
module.setDefaultUseWrapper(defaultUseWrapper);
781+
return new XmlMapper(new XmlFactory(xmlInputFactory()), module);
782+
}
783+
784+
private static final XMLInputFactory xmlInputFactory() {
760785
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
761786
inputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
762787
inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
763788
inputFactory.setXMLResolver(NO_OP_XML_RESOLVER);
764-
return new XmlMapper(inputFactory);
789+
return inputFactory;
765790
}
766791

767792
private static final XMLResolver NO_OP_XML_RESOLVER = new XMLResolver() {

spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBean.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,15 @@ public void setIndentOutput(boolean indentOutput) {
324324
this.builder.indentOutput(indentOutput);
325325
}
326326

327+
/**
328+
* Define if a wrapper will be used for indexed (List, array) properties or not by
329+
* default (only applies to {@link XmlMapper}).
330+
* @since 4.3
331+
*/
332+
public void setDefaultUseWrapper(boolean defaultUseWrapper) {
333+
this.builder.defaultUseWrapper(defaultUseWrapper);
334+
}
335+
327336
/**
328337
* Specify features to enable.
329338
* @see com.fasterxml.jackson.core.JsonParser.Feature

spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilderTests.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@
2222
import java.nio.file.Paths;
2323
import java.text.SimpleDateFormat;
2424
import java.util.ArrayList;
25+
import java.util.Arrays;
2526
import java.util.Collections;
2627
import java.util.Date;
2728
import java.util.HashMap;
29+
import java.util.List;
2830
import java.util.Locale;
2931
import java.util.Map;
3032
import java.util.Optional;
@@ -437,6 +439,16 @@ public void createXmlMapper() {
437439
assertTrue(xmlObjectMapper.getClass().isAssignableFrom(XmlMapper.class));
438440
}
439441

442+
@Test // SPR-13975
443+
public void defaultUseWrapper() throws JsonProcessingException {
444+
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.xml().defaultUseWrapper(false).build();
445+
assertNotNull(objectMapper);
446+
assertEquals(XmlMapper.class, objectMapper.getClass());
447+
ListContainer<String> container = new ListContainer<>(Arrays.asList("foo", "bar"));
448+
String output = objectMapper.writeValueAsString(container);
449+
assertThat(output, containsString("<list>foo</list><list>bar</list></ListContainer>"));
450+
}
451+
440452

441453
public static class CustomIntegerModule extends Module {
442454

@@ -501,4 +513,24 @@ public void setProperty2(String property2) {
501513
}
502514
}
503515

516+
public static class ListContainer<T> {
517+
518+
private List<T> list;
519+
520+
public ListContainer() {
521+
}
522+
523+
public ListContainer(List<T> list) {
524+
this.list = list;
525+
}
526+
527+
public List<T> getList() {
528+
return list;
529+
}
530+
531+
public void setList(List<T> list) {
532+
this.list = list;
533+
}
534+
}
535+
504536
}

0 commit comments

Comments
 (0)