
1. Introduction
In this article, we will learn to deserialize the snake case to the camel case using Jackson library. Let’s first understand the differences between camel case and snake case.
A camel case (CamelCase
or camelCase
) is a convention of writing a compound word with no spaces, expressing the separation of words with a single capitalized letter, and the first word starting with either lower case or upper case. If the first word starts with lower case (camelCase), then we refer to it as lower camel case or dromedary case.
In Java, we normally use the lower camel case as a naming convention for methods and fields.
A Snake case (snake_case
) is a convention of writing a compound word separated by underscore (_) character and the first letter of each word stating with lowercase.
2. Jackson default behavior - deserialize snake to camel case
Assume your JSON uses the snake case style for its fields, whereas your Java class uses the camel case. Since both JSON and Java class uses a different naming style, deserialization will not work. So you need to configure your Jackson library to handle this.
For example, the below Student
class contains fields id
and studentName
that uses lower camel case.
@JsonAutoDetect(fieldVisibility = Visibility.ANY) public class Student { public Student(long id, String studentName) { this.id = id; this.studentName = studentName; } public Student() { } private long id; private String studentName; @Override public String toString() { return "Student [id=" + id + ", studentName=" + studentName + "]"; } }
The below json
contains fields id
and student_name
using snake case as naming style.
@Test void snakeToCamel_Default() throws JsonMappingException, JsonProcessingException { ObjectMapper mapper = new ObjectMapper(); String json = "{\"id\": 1001, \"student_name\":\"Praj\"}"; Student student = mapper.readValue(json, Student.class); System.out.println(student); }
When you convert or deserialize the json
to java class Student
using the ObjectMapper jackson class, then the following error shows up.
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "student_name" (class com.tedblob.jackson.examples.models.snaketocamel.Student), not marked as ignorable (2 known properties: "id", "studentName"]) at [Source: (String)"{"id": 1001, "student_name":"Praj"}"; line: 1, column: 30] (through reference chain: com.tedblob.jackson.examples.models.snaketocamel.Student["student_name"])
All the below solutions would work with both serialization (camel case Java object to snake case) and deserialization (JSON snake case to camel case Java object).
3. Jackson deserialize snake case to camel case
Let’s see the solutions to change this default behavior and make Jackson overcome underscores in favor of the camel case.
3.1. Using properties file
If you are using Spring Boot in your project, then you can update the below property in your application.properties
file. The property should reflect the style of JSON.
spring.jackson.property-naming-strategy=SNAKE_CASE spring.jackson.property-naming-strategy=CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES spring: jackson: property-naming-strategy: SNAKE_CASE
The above property accepts the constants of class PropertyNamingStrategies
as input: LOWER_CAMEL_CASE, UPPER_CAMEL_CASE, SNAKE_CASE, LOWER_CASE, LOWER_DOT_CASE, KEBAB_CASE
In order for this property to work, your ObjectMapper instance should be created by Spring.
You can use Jackson2ObjectMapperBuilder
to build your ObjectMapper instance as follows:
@SpringBootTest public class JacksonSnakeToCamelTest { @Autowired Jackson2ObjectMapperBuilder builder; @Test void snakeToCamel_Builder() throws JsonMappingException, JsonProcessingException { ObjectMapper mapper = builder.build(); String json = "{\"id\": 1001, \"student_name\":\"Praj\"}"; Student student = mapper.readValue(json, Student.class); System.out.println(student); } }
Alternatively, you can create an ObjectMapper
Bean and use it. For example, create a @Bean
method that returns an ObjectMapper
in a @Configuration
class.
@TestConfiguration public class TestConfig { @Bean public ObjectMapper objectMapper() { return new ObjectMapper(); } } @Autowired ObjectMapper mapper; @Test void snakeToCamel_Bean() throws JsonMappingException, JsonProcessingException { String json = "{\"id\": 1001, \"student_name\":\"Praj\"}"; Student student = mapper.readValue(json, Student.class); System.out.println(student); }
The ObjectMapper
correctly converts the JSON snake case fields to Java camel case fields. So running the above @Test
methods returns:
Student [id=1001, studentName=Praj]
3.2. Configure the ObjectMapper
Alternatively, you can configure the ObjectMapper directly. We can use the setPropertyNamingStrategy
method to configure ObjectMapper
.
This method accepts constants of either PropertyNamingStrategies
or PropertyNamingStrategy
. As of Jackson 2.12, PropertyNamingStrategy
is deprecated and PropertyNamingStrategies
class is added.
mapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE); mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); mapper.setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
@Test void snakeToCamel_NamingStrategy() throws JsonMappingException, JsonProcessingException { ObjectMapper mapper = new ObjectMapper(); mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); String json = "{\"id\": 1001, \"student_name\":\"Praj\"}"; Student student = mapper.readValue(json, Student.class); System.out.println(student); }
The above test runs fine and prints the result in the console:
Student [id=1001, studentName=Praj]
3.3. @JsonNaming annotation
You can use @JsonNaming
annotation to mention the property naming strategy. This annotation accepts PropertyNamingStrategy
implementation classes. As of Jackson 2.12, PropertyNamingStrategy
is deprecated and PropertyNamingStrategies
class is added.
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) @JsonNaming(PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy.class)
3.3.1. Jackson deserialize snake to camel case
For example, the below Dapartment
class contains deptId
and deptName
with lower case style. Also, we annotated the class with @JsonNaming
to inform Jackson about the JSON’s naming style.
@JsonAutoDetect(fieldVisibility = Visibility.ANY) @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class Department { private String deptName; private long deptId; @Override public String toString() { return "Department [deptName=" + deptName + ", deptId=" + deptId + "]"; } }
@Test void snakeToCamel_JsonNaming() throws JsonMappingException, JsonProcessingException { ObjectMapper mapper = new ObjectMapper(); String json = "{\"dept_id\": 1001, \"dept_name\":\"Praj\"}"; Department department = mapper.readValue(json, Department.class); System.out.println(department); }
When you deserialize using the ObjectMapper class, the result Department
object would be:
Department [deptName=Praj, deptId=1001]
3.3.2. Serialize from camel to snake case
Similarly, you can serialize from Java lower camel case to snake case JSON fields using the @JsonNaming
annotation.
@Test void CamelToSnake_JsonNaming() throws JsonMappingException, JsonProcessingException { ObjectMapper mapper = new ObjectMapper(); Department department = new Department(12123, "Mike"); System.out.println(mapper.writeValueAsString(department)); }
If you run the above test case, you would see the following JSON with snake case fields in the console:
{"dept_name":"Mike","dept_id":12123}
3.4. @JsonProperty to overcome underscore in favor of camel case
If you have only very few fields, then you can use @JsonProperty on each Java field to inform Jackson on the corresponding JSON field to be used. To know more about changing the name of a property, refer to this article.
The below code contains the Employee
object with empId
and employeeName
fields annotated with @JsonProperty.
@JsonAutoDetect(fieldVisibility = Visibility.ANY) public class Employee { @JsonProperty("emp_id") private long empId; @JsonProperty("emp_name") private String employeeName; @Override public String toString() { return "Employee [id=" + empId + ", name=" + employeeName + "]"; } }
@Test void snakeToCamel_JsonProperty() throws JsonMappingException, JsonProcessingException { ObjectMapper mapper = new ObjectMapper(); String json = "{\"emp_id\": 1001, \"emp_name\":\"Praj\"}"; Employee emp = mapper.readValue(json, Employee.class); System.out.println(emp); }
Running the above code results in the below Employee
object:
Employee [id=1001, name=Praj]
4. Conclusion
To sum up, we learned the solutions to overcome underscores in favor of camel case. Above solutions work in case of both serialization and deserialization.