Как настроить Джексона для использования SNAKE_CASE в Micronaut? - PullRequest
0 голосов
/ 07 ноября 2018

Я попытался настроить Джексона на прием JSON с использованием SNAKE_CASE при использовании Micronaut, однако он не распознает свойство jackson.property-naming-strategy: SNAKE_CASE.

Ответы [ 2 ]

0 голосов
/ 14 мая 2019

Это исправлено в Micronaut 1.1.1 в этом выпуске: https://github.com/micronaut-projects/micronaut-core/issues/1599

Добавьте это в application.yml

jackson:
    property-naming-strategy: SNAKE_CASE

И вы можете проверить это с:

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

        assertThat(applicationContext.getBean(JacksonConfiguration::class.java).propertyNamingStrategy).isEqualTo(PropertyNamingStrategy.SNAKE_CASE)
    }
0 голосов
/ 07 ноября 2018

Micronaut создает ObjectMapper, используя ObjectMapperFactory, который не устанавливает стратегию именования свойств (по крайней мере, в версии Micronaut 1.0 GA, это может измениться в будущих выпусках). Класс конфигурации, который вы упомянули в вопросе, не поддерживается классом конфигурации, поэтому его использование просто ничего не делает. Тем не менее, вы можете заменить класс ObjectMapperFactory собственной пользовательской реализацией, которая создает ObjectMapper способом по умолчанию + он устанавливает стратегию именования свойств. Рассмотрим следующий пример:

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;
        }
    }
}

В этом примере я добавил статический класс CustomObjectMapperFactory к основному классу Application и использовал аннотацию @Replaces, чтобы указать Micronaut использовать этот класс фабрики и метод objectMapper(), предоставляемый этим пользовательским классом фабрики. Экземпляр ObjectMapper, который мы возвращаем из этой фабрики, основан на методе фабрики по умолчанию +, который добавляет:

mapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);

для установки ожидаемой стратегии именования свойств.

А вот примерный вывод, который я получаю в ответе после добавления этого пользовательского фабричного класса:

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"
}

По умолчанию (без этого пользовательского фабричного класса) ответ выглядел так:

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"
}

ОБНОВЛЕНИЕ: использование BeanCreatedEventListener<ObjectMapper> вместо

Существует альтернативный способ достижения того же эффекта, который требует еще меньше строк кода. Кредиты поступают на Twitter-аккаунт Micronaut Framework :)

Мы можем использовать BeanCreatedEventListener<T>, который реагирует на событие создания компонента и позволяет нам расширять только что созданный компонент. В этом случае это означает добавление класса, который реализует BeanCreatedEventListener<ObjectMapper> и устанавливает стратегию именования свойств:

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;
        }
    }
}

Преимущества этого решения:

  • меньше строк кода
  • на один уровень абстракции меньше (нам не нужно беспокоиться о ObjectMapperFactory, мы просто заботимся о настройке существующего компонента ObjectMapper).
...