Case insensitive JSON to POJO mapping without changing the POJO

JavaJsonData BindingCase InsensitiveFasterxml

Java Problem Overview


Does anyone know how com.fasterxml.jackson.databind.ObjectMapper is able to map JSON properties to POJO properties case insensitive?

JSON-String: >[{"FIRSTNAME":"John","LASTNAME":"Doe","DATEOFBIRTH":"1980-07-16T18:25:00.000Z"}]

POJO-Class:

public class Person {

	private String firstName;
	private String lastName;
	private Date dateOfBirth;

	public String getFirstName() {
		return firstName;
	}
	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}
	public String getLastName() {
		return lastName;
	}
	public void setLastName(String lastName) {
		this.lastName = lastName;
	}
	public Date getDateOfBirth() {
		return dateOfBirth;
	}
	public void setDateOfBirth(Date dateOfBirth) {
		this.dateOfBirth = dateOfBirth;
	}
}

Test-Class:

@Test
public final void testDeserializingPersonJsonToPersonClass()
		throws JsonParseException, JsonMappingException, IOException {
	final String jsonAsString = "[{\"FIRSTNAME\":\"John\",\"LASTNAME\":\"Doe\",\"DATEOFBIRTH\":\"1980-07-16T18:25:00.000Z\"}]";
	final ObjectMapper mapper = new ObjectMapper();

	final Person person = mapper.readValue(jsonAsString, Person.class);

	assertNotNull(person);
	assertThat(person.getFirstName(), equalTo("John"));
}

This ends up in following error:
com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of ...

It's not possible to change neither JSON-String nor POJO-Class.

Java Solutions


Solution 1 - Java

This behaviour was introduced in Jackson 2.5.0. You can configure the mapper to be case insensitive using MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES.

For example :

ObjectMapper mapper = new ObjectMapper();
mapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);

Solution 2 - Java

You can solve this problem by configuring the mapper, as described by the @Nicolas Riousset.

In addition, since version Jackson 2.9 you can do the same using annotation @JsonFormat(with = JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES) over a field or class, which is a more flexible option.

@JsonFormat(with = JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
private String firstName;

Solution 3 - Java

I had the same problem and couldn't find a global way of solving this. However you can have 2 setters per property to achieve this:

@JsonSetter("FIRSTNAME")
public void setFirstNameCaps(String firstName) {
    this.firstName = firstName;
}

@JsonSetter("firstName")
public void setFirstName(String firstName) {
    this.firstName = firstName;
}

Not elegant but will work for both upper and lower case json fields. You can also try the solution mentioned here but this might have a performance overhead

Solution 4 - Java

package br.com.marcusvoltolim.util;


import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.log4j.Log4j;

@Log4j
public class JsonUtils {

    private static final ObjectMapper OBJECT_MAPPER;

    static {
        OBJECT_MAPPER = new ObjectMapper();
        OBJECT_MAPPER.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
        OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    public static <T> T fromJson(final String json, final Class<T> classe) {
        try {
            return OBJECT_MAPPER.readValue(json, classe);
        } catch (Exception e) {
            log.error(e);
            try {
                return classe.newInstance();
            } catch (InstantiationException | IllegalAccessException ex) {
                return null;
            }
        }
    }

}

Solution 5 - Java

As of Jackson version 2.12, you can finally annotate on class:

@JsonFormat(with = JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
public class Person {
    private String firstName;
    private String lastName;
    private Date dateOfBirth;
    // setters and getters ...
}

As noted in the Github issue, there is still no support for single-property case-insensitivity!

Solution 6 - Java

I was in the same kind of situation and had to convert to a map and then copy the values over manually.

import com.fasterxml.jackson.core.type.TypeReference;

Map<String, String> map = 
    mapper.readValue(jsonAsString, new TypeReference<Map<String, String>>(){});

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMark FellnerView Question on Stackoverflow
Solution 1 - JavaNicolas RioussetView Answer on Stackoverflow
Solution 2 - JavaDmitry KokoraView Answer on Stackoverflow
Solution 3 - JavaDhananjayView Answer on Stackoverflow
Solution 4 - JavaMarcus Vinícius VoltolimView Answer on Stackoverflow
Solution 5 - Javaholmis83View Answer on Stackoverflow
Solution 6 - JavaHarry GlasgowView Answer on Stackoverflow