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
).