जैक्सन JSON मैपर को अंतर्निहित रूप से स्प्रिंग बूट द्वारा कैसे अनुकूलित किया जाए?


101

मैं स्प्रिंग बूट (१.२.१) का उपयोग कर रहा हूं, इसी तरह से उनके भवन में एक वेब सेवा ट्यूटोरियल के रूप में:

@RestController
public class EventController {

    @RequestMapping("/events/all")
    EventList events() {
        return proxyService.getAllEvents();
    }

}

तो ऊपर, स्प्रिंग एमवीसी ने जेन्स में मेरी EventListवस्तु को क्रमबद्ध करने के लिए जैक्सन का उपयोग किया।

लेकिन मैं JSON प्रारूप में कुछ सरल अनुकूलन करना चाहता हूं, जैसे:

setSerializationInclusion(JsonInclude.Include.NON_NULL)

प्रश्न है, निहित JSON मैपर को अनुकूलित करने का सबसे सरल तरीका क्या है?

मैंने इस ब्लॉग पोस्ट में एक CustomObjectMapper और इतने पर बनाने की कोशिश की , लेकिन चरण 3, "स्प्रिंग संदर्भ में कक्षाएं पंजीकृत करें", विफल रहता है:

org.springframework.beans.factory.BeanCreationException: 
  Error creating bean with name 'jacksonFix': Injection of autowired dependencies failed; 
  nested exception is org.springframework.beans.factory.BeanCreationException: 
  Could not autowire method: public void com.acme.project.JacksonFix.setAnnotationMethodHandlerAdapter(org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter); 
  nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: 
  No qualifying bean of type [org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter]   
  found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}

ऐसा लगता है कि वे निर्देश स्प्रिंग एमवीसी के पुराने संस्करणों के लिए हैं, जबकि मैं नवीनतम स्प्रिंग बूट के साथ इस काम को प्राप्त करने का एक सरल तरीका ढूंढ रहा हूं।


क्या आपके पास यह एनोटेशन डाला गया है ?: @SuppressWarnings ({"SpringJavaAutowiringInspection"})
sven.kwiotek

ध्यान दें कि यदि आप स्प्रिंग वेब का उपयोग कर रहे हैं, तो आपको इस ऑब्जेक्टमैपर का उपयोग करने के लिए इसे मैन्युअल रूप से बताना होगा अन्यथा यह स्वयं का उदाहरण बनाएगा जिसे कॉन्फ़िगर नहीं किया जाएगा। देखें stackoverflow.com/questions/7854030/…
कॉन्स्टेंटिनो क्रोनमबर्गर

जवाबों:


116

यदि आप स्प्रिंग बूट 1.3 का उपयोग कर रहे हैं, तो आप इसके माध्यम से क्रमिक समावेशन को कॉन्फ़िगर कर सकते हैं application.properties:

spring.jackson.serialization-inclusion=non_null

जैक्सन 2.7 में बदलाव के बाद, स्प्रिंग बूट 1.4 spring.jackson.default-property-inclusionइसके बजाय नाम की एक संपत्ति का उपयोग करता है :

spring.jackson.default-property-inclusion=non_null

स्प्रिंग बूट दस्तावेज़ीकरण में " जैक्सन ऑब्जेक्टमेपर को अनुकूलित करें " अनुभाग देखें ।

यदि आप स्प्रिंग बूट के पुराने संस्करण का उपयोग कर रहे हैं, तो स्प्रिंग बूट में क्रमिक समावेशन को कॉन्फ़िगर करने का सबसे आसान तरीका है कि आप अपनी खुद की, उचित रूप से कॉन्फ़िगर की गई Jackson2ObjectMapperBuilderसेम की घोषणा करें । उदाहरण के लिए:

@Bean
public Jackson2ObjectMapperBuilder objectMapperBuilder() {
    Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
    builder.serializationInclusion(JsonInclude.Include.NON_NULL);
    return builder;
}

1
ठीक है, यह काम करने लगता है। आप ऐसी विधि कहां से करेंगे? शायद एक मुख्य अनुप्रयोग वर्ग (के साथ @ComponentScan, @EnableAutoConfigurationआदि) में?
जोनिक

2
हाँ। यह तरीका @Configurationआपके ऐप में किसी भी क्लास में जा सकता है । मुख्य Applicationवर्ग इसके लिए एक अच्छी जगह है।
एंडी विल्किंसन

2
महत्वपूर्ण नोट: जैक्सन 2 ओब्जेक्टमैपरब्यूलर क्लास स्प्रिंग-वेब घटक का हिस्सा है और इसे 4.1.1 संस्करण में जोड़ा गया था।
गौआगोंग

2
@Deprecated setSerializationInclusion
दिमित्री कोपरिवा

6
पदावनत: ObjectMapper.setSerializationInclusion जैक्सन 2.7 में पदावनत किया गया था ... stackoverflow.com/a/44137972/6785908 spring.jackson.default-प्रोपर्टी-इंक्रीमेंट = non_null के बजाय उपयोग करें
so-random-dude

24

मैं इस प्रश्न का उत्तर थोड़ी देर से दे रहा हूं, लेकिन भविष्य में कोई व्यक्ति इसे उपयोगी समझ सकता है। नीचे दिए गए दृष्टिकोण, बहुत सारे अन्य तरीकों के अलावा, सबसे अच्छा काम करता है, और मुझे व्यक्तिगत रूप से लगता है कि यह एक वेब एप्लिकेशन के लिए बेहतर होगा।

@Configuration
@EnableWebMvc
public class WebConfiguration extends WebMvcConfigurerAdapter {

 ... other configurations

@Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
        builder.serializationInclusion(JsonInclude.Include.NON_NULL);
        builder.propertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
        builder.serializationInclusion(Include.NON_EMPTY);
        builder.indentOutput(true).dateFormat(new SimpleDateFormat("yyyy-MM-dd"));
        converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
        converters.add(new MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build()));
    }
}

1
हाल के संस्करण में आपको लागू करना होगाWebMvcConfigurer
जोओ पेड्रो श्मिट

हाँ, लोगों, इस समाधान का प्रयास करें, मैंने बीन को ऑब्जेक्टमैपर के लिए प्रदान करने की कोशिश की है, फिर बीन के लिए जैक्सन 2 एक्सबिजट मैपरबर्ल खरीदें जो काम नहीं किया और मुझे अभी भी पता नहीं क्यों। कवर करने वाले ने काम किया!
सोमाल सोमालस्की

23

एप्लिकेशनप्रोपरेटी में बहुत सी चीजें कॉन्फ़िगर की जा सकती हैं। दुर्भाग्य से यह सुविधा केवल संस्करण 1.3 में है, लेकिन आप एक कॉन्फ़िगर-क्लास में जोड़ सकते हैं

@Autowired(required = true)
public void configureJackson(ObjectMapper jackson2ObjectMapper) {
    jackson2ObjectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
}

[अद्यतन करें: आपको build()ऑब्जेक्टमैपर पर काम करना चाहिए क्योंकि -मिथोड को विन्यास के चलने से पहले कहा जाता है।]


यही वह उपाय था जिसने मेरा दिन बचाया। सिवाय मैंने विन्यास विधि के बजाय इस विधि को REST नियंत्रक में जोड़े हुए।
नेस्टर मिलियाव

20

प्रलेखन ऐसा करने के लिए कई तरीके बताता है।

यदि आप डिफ़ॉल्ट को ObjectMapperपूरी तरह से बदलना चाहते हैं , तो @Beanउस प्रकार को परिभाषित करें और इसे चिह्नित करें @Primary

एक @Beanप्रकार Jackson2ObjectMapperBuilderको परिभाषित करना आपको डिफ़ॉल्ट ObjectMapperऔर XmlMapper( क्रमशः MappingJackson2HttpMessageConverterऔर MappingJackson2XmlHttpMessageConverterक्रमशः) दोनों को अनुकूलित करने की अनुमति देगा ।


2
डिफ़ॉल्ट को प्रतिस्थापित किए बिना समान कैसे करें ObjectMapper? मेरा मतलब है कि डिफ़ॉल्ट के साथ-साथ एक कस्टम।
सूपरफ्रॉक

12

आप अपने बूटस्ट्रैप वर्ग के अंदर एक निम्न विधि जोड़ सकते हैं जिसके साथ एनोटेट किया गया है @SpringBootApplication

    @Bean
    @Primary
    public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
    ObjectMapper objectMapper = builder.createXmlMapper(false).build();
    objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
    objectMapper.configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, false);

    objectMapper.registerModule(new JodaModule());

    return objectMapper;
}

इसने बूट 2.1.3 का उपयोग करके मेरे लिए काम किया। स्प्रिंग.जैकसन के गुणों का कोई प्रभाव नहीं था।
रिचटॉपिया

9

spring.jackson.serialization-inclusion=non_null हमारे लिए काम करते थे

लेकिन जब हमने स्प्रिंग बूट संस्करण को 1.4.2 तक उन्नत किया। कृपया या उच्चतर, इसने काम करना बंद कर दिया।

अब, एक और संपत्ति spring.jackson.default-property-inclusion=non_null जादू कर रही है।

वास्तव में, serialization-inclusionपदावनत है। यह वही है जो मेरा इंटेलीजेंस मुझ पर फेंकता है।

पदावनत: ObjectMapper.setSerializationInclusion जैक्सन 2.7 में पदावनत किया गया था

इसलिए, spring.jackson.default-property-inclusion=non_nullइसके बजाय उपयोग करना शुरू करें


4

मैं एक और समाधान पर ठोकर खाई, जो काफी अच्छा है।

मूल रूप से, पोस्ट किए गए ब्लॉग से केवल चरण 2 करें , और एक स्प्रिंग के रूप में एक कस्टम ऑब्जेक्टमैपर को परिभाषित करें @Component। (चीजें तब काम करने लगीं, जब मैंने अभी चरण 3 से सभी एनोटेशनमेथहैंडलर एडेप्टर सामान हटा दिए ।)

@Component
@Primary
public class CustomObjectMapper extends ObjectMapper {
    public CustomObjectMapper() {
        setSerializationInclusion(JsonInclude.Include.NON_NULL); 
        configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 
    }
}

जब तक घटक वसंत द्वारा स्कैन किए गए पैकेज में काम करता है। (उपयोग करना @Primaryमेरे मामले में अनिवार्य नहीं है, लेकिन चीजों को स्पष्ट क्यों नहीं किया गया है।)

मेरे लिए अन्य दृष्टिकोण की तुलना में दो लाभ हैं:

  • यह सरल है; मैं सिर्फ जैक्सन से एक वर्ग का विस्तार कर सकता हूं और अत्यधिक स्प्रिंग-विशिष्ट सामान जैसे के बारे में जानने की आवश्यकता नहीं है Jackson2ObjectMapperBuilder
  • मैं अपने ऐप के दूसरे हिस्से में JSON को डिसेर्लिज़ करने के लिए उसी जैक्सन कॉन्फिगर का उपयोग करना चाहता हूं, और इस तरह से यह बहुत आसान है: new CustomObjectMapper()इसके बजाय new ObjectMapper()

इस दृष्टिकोण के लिए नकारात्मक पक्ष यह है कि आपका कस्टम कॉन्फ़िगरेशन ObjectMapperस्प्रिंग बूट द्वारा बनाए या कॉन्फ़िगर किए गए किसी भी उदाहरण पर लागू नहीं किया जाएगा ।
एंडी विल्किंसन

हम्म, कस्टम विन्यास का उपयोग उन @RestControllerवर्गों में निहित धारावाहिकीकरण के लिए किया जाता है जो वर्तमान में मेरे लिए पर्याप्त हैं। (तो आप का मतलब है कि उन उदाहरणों को स्प्रिंग एमवीसी द्वारा बनाया गया है, न कि स्प्रिंग बूट?) लेकिन अगर मैं अन्य मामलों में भाग लेता हूं, जहां ऑब्जेक्टमैपर को तुरंत तैयार करने की आवश्यकता होती है, तो मैं जैक्सनकोबजेबजेक्ट मैपरबेरल दृष्टिकोण को ध्यान में रखूंगा!
जोनीक

3

जब मैंने स्प्रिंग बूट 2.0.6 में ऑब्जेक्टमैपर को प्राथमिक बनाने की कोशिश की, तो मुझे त्रुटियां मिलीं, इसलिए मैंने अपने लिए बनाए गए स्प्रिंग बूट को संशोधित किया

इसके अलावा https://stackoverflow.com/a/48519868/255139 देखें

@Lazy
@Autowired
ObjectMapper mapper;

@PostConstruct
public ObjectMapper configureMapper() {
    mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
    mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);

    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    mapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);

    mapper.configure(MapperFeature.ALLOW_COERCION_OF_SCALARS, true);
    mapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);

    SimpleModule module = new SimpleModule();
    module.addDeserializer(LocalDate.class, new LocalDateDeserializer());
    module.addSerializer(LocalDate.class, new LocalDateSerializer());
    mapper.registerModule(module);

    return mapper;
}

1

मैंने ऊपर वर्णित समाधान पाया:

spring.jackson.serialization समावेशन = non_null

केवल स्प्रिंग बूट के 1.4.0.RELEASE संस्करण पर काम शुरू करने के लिए। अन्य सभी मामलों में कॉन्फ़िगरेशन को अनदेखा किया जाता है।

मैंने इसे स्प्रिंग बूट नमूने "स्प्रिंग-बूट-सैंपल-जर्सी" के संशोधन के साथ प्रयोग करके सत्यापित किया


0

मैं स्प्रिंग बूट के लिए पूछ रहा सवाल जानता हूं, लेकिन मुझे विश्वास है कि बहुत से लोग गैर स्प्रिंग बूट में यह करना चाहते हैं, जैसे कि मैं लगभग पूरे दिन खोज रहा हूं।

MappingJacksonHttpMessageConverterयदि आप केवल कॉन्फ़िगर करने का इरादा रखते हैं , तो स्प्रिंग 4 से ऊपर, कॉन्फ़िगर करने की कोई आवश्यकता नहीं हैObjectMapper

आपको बस करने की आवश्यकता है:

public class MyObjectMapper extends ObjectMapper {

    private static final long serialVersionUID = 4219938065516862637L;

    public MyObjectMapper() {
        super();
        enable(SerializationFeature.INDENT_OUTPUT);
    }       
}

और अपने स्प्रिंग कॉन्फ़िगरेशन में, यह बीन बनाएँ:

@Bean 
public MyObjectMapper myObjectMapper() {        
    return new MyObjectMapper();
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.