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
.

- 193
- 2
- 8
2 Answers
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 existingObjectMapper
bean).

- 40,216
- 10
- 104
- 131
-
1Nice! I've tried using `BeanInitializedEventListener` to accomplish the same , but the hook has not been picked. Should it work as well? – Bruno Barin Nov 07 '18 at 18:53
-
1Is there anything else that needs to be done for this to work with the `BeanCreatedEventListener
` approach? So far it doesn't...not sure what am I missing O:) – x80486 Dec 30 '18 at 01:39 -
1Any luck with BeanCreatedEventListener
? In my case it is going inside the onCreated method but no impact on objectmapper. I am trying to set mapper.setSerializationInclusion(JsonInclude.Include.ALWAYS); and mapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);. Any help will be appreciated. – mayur tanna May 20 '21 at 11:39 -
For all folks asking here if there is anything wrong with this configuration using the `ObjectMapperBeanEventListener`, I don't think so. I have read the documentation multiple times, trying to implement the same configuration proposed here and that is not working. It's very frustrating. One of the downsides of Micronaut is the poor documentation for its sub-projects (like Micronaut Serialization), the high number of bugs, and the reduced number of contributors for sub-projects. – Alexandre V. Mar 05 '23 at 16:32
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)
}

- 4,939
- 3
- 30
- 51