How to configure Jackson to use SNAKE_CASE in Micronaut?

半世苍凉 提交于 2021-01-27 06:28:41

问题


I have tried to configure jackson to accept JSON using SNAKE_CASE when using Micronaut, however, it doesn't recognize the property jackson.property-naming-strategy: SNAKE_CASE.


回答1:


From Micronaut 1.1.1

application.yml

jackson:
    property-naming-strategy: SNAKE_CASE

Before Micronaut 1.1.1

Micronaut constructs ObjectMapper using ObjectMapperFactory that does not set property naming strategy (at least in Micronaut 1.0 GA version, this may change in future releases). The configuration option you have mentioned in the question is not supported by the configuration class, so using it simply does nothing. However, you can replace ObjectMapperFactory class with your own custom implementation that constructs ObjectMapper in the default way + it sets property naming strategy. Consider following example:

package com.github.wololock.micronaut;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import io.micronaut.context.annotation.Factory;
import io.micronaut.context.annotation.Replaces;
import io.micronaut.jackson.JacksonConfiguration;
import io.micronaut.jackson.ObjectMapperFactory;
import io.micronaut.runtime.Micronaut;

import javax.inject.Singleton;
import java.util.Optional;

public class Application {

    public static void main(String[] args) {
        Micronaut.run(Application.class);
    }

    @Factory
    @Replaces(ObjectMapperFactory.class)
    static class CustomObjectMapperFactory extends ObjectMapperFactory {

        @Override
        @Singleton
        @Replaces(ObjectMapper.class)
        public ObjectMapper objectMapper(Optional<JacksonConfiguration> jacksonConfiguration, Optional<JsonFactory> jsonFactory) {
            final ObjectMapper mapper = super.objectMapper(jacksonConfiguration, jsonFactory);
            mapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
            return mapper;
        }
    }
}

In this example I have added a static class CustomObjectMapperFactory to the main Application class and I have used @Replaces annotation to instruct Micronaut to use this factory class and objectMapper() method provided by this custom factory class. The ObjectMapper instance we return from this factory is based on the default factory method + it adds:

mapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);

to set expected property naming strategy.

And here is exemplary output I get back in the response after adding this custom factory class:

HTTP/1.1 200 OK
Date: Wed, 7 Nov 2018 19:15:10 GMT
connection: keep-alive
content-length: 38
content-type: application/json

{
    "first_name": "Joe",
    "last_name": "Doe"
}

By default (without this custom factory class) the response looked like this:

HTTP/1.1 200 OK
Date: Wed, 7 Nov 2018 19:04:14 GMT
connection: keep-alive
content-length: 36
content-type: application/json

{
    "firstName": "Joe",
    "lastName": "Doe"
}

UPDATE: Using BeanCreatedEventListener<ObjectMapper> instead

There is an alternative way to achieve the same effect that requires even less amount of lines of code. Credits goes to Micronaut Framework Twitter account :)

We can use BeanCreatedEventListener<T> that reacts to bean creation event and allows us extending the bean that just got created. In this case it means adding a class that implements BeanCreatedEventListener<ObjectMapper> and sets property naming strategy:

package com.github.wololock.micronaut;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import io.micronaut.context.event.BeanCreatedEvent;
import io.micronaut.context.event.BeanCreatedEventListener;
import io.micronaut.runtime.Micronaut;

import javax.inject.Singleton;

public class Application {

    public static void main(String[] args) {
        Micronaut.run(Application.class);
    }

    @Singleton
    static class ObjectMapperBeanEventListener implements BeanCreatedEventListener<ObjectMapper> {

        @Override
        public ObjectMapper onCreated(BeanCreatedEvent<ObjectMapper> event) {
            final ObjectMapper mapper = event.getBean();
            mapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
            return mapper;
        }
    }
}

Advantages of this solution:

  • less lines of code
  • one abstraction layer less (we don't have to bother with ObjectMapperFactory, we just care about configuring existing ObjectMapper bean).



回答2:


This is fixed as of Micronaut 1.1.1 in this issue: https://github.com/micronaut-projects/micronaut-core/issues/1599

Add this to your application.yml

jackson:
    property-naming-strategy: SNAKE_CASE

And you can test it with:

    @Test
    fun testJackson() {
        val applicationContext = ApplicationContext.run()

        assertThat(applicationContext.getBean(JacksonConfiguration::class.java).propertyNamingStrategy).isEqualTo(PropertyNamingStrategy.SNAKE_CASE)
    }


来源:https://stackoverflow.com/questions/53195071/how-to-configure-jackson-to-use-snake-case-in-micronaut

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!