213

I retrieve a JSON string from internet; like most JSON I've seen it includes long keys that are separated by underscores. Essentially, my goal is to deserialize JSON into java-objects, but I don't use underscores in java-code.

For instance, I might have a User class with firstName field in camel-case, simultaneously I need somehow to tell Jackson to map first_name key from JSON to firstName class field. Is it possible?

class User{
    protected String firstName;
    protected String getFirstName(){return firstName;}
}
Maciej Lach
  • 1,622
  • 3
  • 20
  • 27
user1384991
  • 2,559
  • 3
  • 17
  • 20

11 Answers11

471

In Jackson 2.12+, you can configure the ObjectMapper to convert camel case to names with an underscore:

objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);

Or annotate a specific model class with this annotation:

@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class;)

Before Jackson 2.7, the constant was named:

PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES
Michael M.
  • 10,486
  • 9
  • 18
  • 34
thehpi
  • 5,683
  • 4
  • 17
  • 24
  • 5
    Note that this was only introduced in Jackson 1.9. – David Moles Jul 11 '13 at 20:50
  • 63
    @deprecated Since 2.7 use SNAKE_CASE instead; – Thermech Mar 21 '16 at 12:36
  • 1
    one qq: when i use snake_case naming strategy will the json files with underscores be deserialized to camel case? – Ram Patra Aug 05 '16 at 23:28
  • 2
    @Ramswaroop Yes, this makes Jackson both speak and expect snake_case – Drew Stephens Sep 20 '16 at 20:21
  • @DrewStephens But I couldn't get this behaviour, I had to explicitly add `@JsonProperty("some_property")` to my camel case java variable to properly deserialise. – Ram Patra Sep 21 '16 at 04:28
  • 1
    @Ramswaroop For me with Jackson 2.7.3 and properties annotated with just `@JsonProperty` (name inferred from normal `camelCase` Java properties) `PropertyNamingStrategy.SNAKE_CASE` made deserialization stop working with camelCase JSON (as I had been using) and require snake_case. – Drew Stephens Sep 21 '16 at 13:13
  • 1
    @DrewStephens Just so that we are on the same page, this is the question which I am referring to: http://stackoverflow.com/questions/38809959/deserialising-json-with-underscores-to-camel-case-in-java-using-jackson. I had an assumption in mind that using `PropertyNamingStrategy` as `SNAKE_CASE` will make it work both ways instead of requiring me to use `@JsonProperty`. – Ram Patra Sep 21 '16 at 14:24
  • @RamPatra naming strategy does work both ways, reading and writing. There is nothing in javadocs (`PropertyNamingStrategy`, `@JsonNaming`) that claims it to only work for serialization, and there are unit tests to verify it also works for reading. You only should use `@JsonProperty` for overriding naming of individual properties. – StaxMan Mar 08 '17 at 21:47
  • Not working for me. Using Spring Boot 2.1.5. Will update comment once I figure out why. – mljohns89 Jun 18 '19 at 14:58
  • 11
    Since Jackson 2.12 it's `PropertyNamingStrategies.SNAKE_CASE` – Trynkiewicz Mariusz Apr 04 '21 at 17:10
  • 7
    When using an annotation with Jackson 2.12+: `@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)` – Drew Stephens Apr 29 '21 at 15:15
  • 2
    I see Jackson as a not very consistent library, always changing their constants back and forth. – Praytic Jul 06 '22 at 01:42
141

If its a spring boot application, In application.properties file, just use

spring.jackson.property-naming-strategy=SNAKE_CASE

Or Annotate the model class with this annotation.

@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)

adam.smithsonian01
  • 1,410
  • 1
  • 8
  • 4
  • 3
    If i annotate my class with the "@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)" it works. But if i use "spring.jackson.property-naming-strategy=SNAKE_CASE" in "application.properties" it won't. I'm using "Spring Boot (v2.0.0.BUILD-SNAPSHOT)". Do you have any ideas ? – Bruno Apr 17 '17 at 20:02
  • 2
    same here, `spring.jackson.property-naming-strategy=SNAKE_CASE` doesn't work, I'm using Spring Boot 2.0 – soulmachine Apr 05 '18 at 00:44
  • 1
    same here, spring.jackson.property-naming-strategy=SNAKE_CASE doesn't work, I'm using Spring Boot 2.0.5. But using annotation is working for me – Neo Pham Sep 26 '18 at 09:31
  • Maybe your `ObjectMapper` is not created by Spring? Create a @Configuration class with a @Bean method that returns an ObjectMapper. Not sure if this is necessary. – Ondra Žižka Jun 09 '19 at 00:24
  • I am using Spring boot 2.4.1 and ```spring.jackson.property-naming-strategy=SNAKE_CASE``` works for me – Darotudeen Dec 30 '20 at 16:50
130

You should use the @JsonProperty on the field you want to change the default name mapping.

class User{
    @JsonProperty("first_name")
    protected String firstName;
    protected String getFirstName(){return firstName;}
}

For more info: the API

Alex
  • 25,147
  • 6
  • 59
  • 55
  • 108
    Don't do this, or else you'll have to do it for every property. See thehpi's response below. – Ryan Shillington Sep 11 '13 at 15:47
  • 1
    I was able to only annotate one property, but it did change the order of properties in the generated string: annotated properties showed up last. (Jackson 2.3.0) – eebbesen Dec 30 '13 at 18:00
  • 1
    @RyanShillington - Correct me if I'm wrong, but this is your only option if the JSON string you are parsing from does not use a consistent format, i.e., uses both camelCase and underscore? – DavidR Nov 16 '15 at 23:45
  • @DavidR That is correct. I'm assuming you can't fix the source data? That sucks. – Ryan Shillington Nov 17 '15 at 18:56
  • @PaulTsai ok, so feel free to use them :) – Alex Jul 20 '19 at 17:22
  • Using `propertyNamingStrategy` is a much better way than annotating each property. – TonyLxc Sep 17 '19 at 00:12
58

If you want this for a Single Class, you can use the PropertyNamingStrategies with the @JsonNaming, annotation, like this:

@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public static class Request {

    String businessName;
    String businessLegalName;

}

Will serialize to:

{
    "business_name" : "",
    "business_legal_name" : ""
}

Before Jackson 2.7, use PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy.class:

@JsonNaming(PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy.class)
public static class Request {

    String businessName;
    String businessLegalName;

}

From Jackson 2.7 to Jackson 2.12 the LowerCaseWithUnderscoresStrategy is deprecated in favor of SnakeCaseStrategy, so you should use:

@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
public static class Request {

    String businessName;
    String businessLegalName;

}

Since Jackson 2.12 the PropertyNamingStrategy.SnakeCaseStrategy is deprecated in favor of PropertyNamingStrategies.SnakeCaseStrategy, you should use:

    @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
    public static class Request {

        String businessName;
        String businessLegalName;

    }
Arturo Volpe
  • 3,442
  • 3
  • 25
  • 40
  • 1
    Since `Jackson 2.12` use `PropertyNamingStrategies.LowerCaseStrategy` instead. (Note change from `PropertyNamingStrategy` to `PropertyNamingStrategies`): https://fasterxml.github.io/jackson-databind/javadoc/2.13/com/fasterxml/jackson/databind/PropertyNamingStrategies.LowerCaseStrategy.html – SiliconMind Nov 05 '22 at 12:58
31

The above answers regarding @JsonProperty and CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES are 100% accurate, although some people (like me) might be trying to do this inside a Spring MVC application with code-based configuration. Here's sample code (that I have inside Beans.java) to achieve the desired effect:

@Bean
public ObjectMapper jacksonObjectMapper() {
    return new ObjectMapper().setPropertyNamingStrategy(
            PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
}
Dawngerpony
  • 3,288
  • 2
  • 34
  • 32
  • 9
    An alternative for Spring Boot, if you're using Spring Boot <=1.3, in `application.properties` add `spring.jackson.property-naming-strategy=CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCOR‌​ES`. For Spring Boot 1.4 use `spring.jackson.property-naming-strategy=SNAKE_CASE` instead. – Dump Cake May 04 '16 at 19:26
  • 1
    @zapl yes you're right, I probably mentioned jackson's version instead of spring-boot's version. Let me delete that comment to avoid confusion. – Ram Patra Sep 06 '16 at 19:04
  • 1
    As of version 2.7 of Jackson it is SNAKE_CASE. This worked for me: `final ObjectMapper objectMapper = new ObjectMapper().setPropertyNamingStrategy( PropertyNamingStrategy.SNAKE_CASE);` – Jonathan Sep 20 '17 at 11:23
18

The current best practice is to configure Jackson within the application.yml (or properties) file.

Example:

spring:
  jackson:
    property-naming-strategy: SNAKE_CASE

If you have more complex configuration requirements, you can also configure Jackson programmatically.

import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;

@Configuration
public class JacksonConfiguration {

    @Bean
    public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() {
        return new Jackson2ObjectMapperBuilder()
                .propertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
        // insert other configurations
    }

} 
Kenny Cason
  • 12,109
  • 11
  • 47
  • 72
13

In order to annotate the model class use:

@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)

Instead of:

@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)

It was deprecated since 2.12.

andreyt
  • 131
  • 1
  • 2
6

There are few answers here indicating both strategies for 2 different versions of Jackson library below:

For Jackson 2.6.*

ObjectMapper objMapper = new ObjectMapper(new JsonFactory()); // or YAMLFactory()
objMapper.setNamingStrategy(
     PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);

For Jackson 2.7.*

ObjectMapper objMapper = new ObjectMapper(new JsonFactory()); // or YAMLFactory()
objMapper.setNamingStrategy(
     PropertyNamingStrategy.SNAKE_CASE);
Amit Kaneria
  • 5,466
  • 2
  • 35
  • 38
4

Annotating all model classes looks to me as an overkill and Kenny's answer didn't work for me https://stackoverflow.com/a/43271115/4437153. The result of serialization was still camel case.

I realised that there is a problem with my spring configuration, so I had to tackle that problem from another side. Hopefully someone finds it useful, but if I'm doing something against springs' rules then please let me know.

Solution for Spring MVC 5.2.5 and Jackson 2.11.2

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);           

        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        converter.setObjectMapper(objectMapper);
        converters.add(converter);
    }
}
rudald
  • 364
  • 5
  • 18
0
  1. You can use the @JsonProperty annotation on the fields of our class to map the fields to the exact names in our JSON

    @JsonProperty("my_name")
    private String myName;
    
  2. You can use @JsonNaming annotation on the class, and all fields will be deserialized using snake case

    @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) 
    public class MyClassWithSnakeStrategy { ... 
    

}

  1. You can use the setPropertyNamingStrategy method on ObjectMapper to configure it for all serialization

    ObjectMapper objectMapper = new ObjectMapper()
    .setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);

Forgery
  • 88
  • 6
0

PropertyNamingStrategy should be replaced with PropertyNamingStrategies for @JsonNaming