How to ignore enum fields in Jackson JSON-to-Object mapping?

@JsonCreator provides a more concise solution compared to @JsonDeserialize.

The idea is to annotate your valueOf() replacement ( called safeValueOf() in this example) with @JsonCreator and then Jackson would deserialize strings using your implementation.

Note that the implementation is inside the enum, you can use it as field in other objects with no change.

The solution below is wrapped in a unit test so you can run it directly.

import static junit.framework.TestCase.assertEquals;

import java.io.IOException;

import org.junit.Test;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.databind.ObjectMapper;

public class EmployeeGradeTest {

    public enum Grade {
        A, B, C, OTHER;

        @JsonCreator
        public static Grade safeValueOf(String string) {
            try {
                return Grade.valueOf(string);
            } catch (IllegalArgumentException e) {
                return OTHER;
            }
        }
    }

    @Test
    public void deserialize() throws IOException {
        assertEquals(Grade.A, new ObjectMapper().readValue("\"A\"", Grade.class));
    }

    @Test
    public void deserializeNewValue() throws IOException {
        assertEquals(Grade.OTHER, new ObjectMapper().readValue("\"D\"", Grade.class));
    }
}

I think you should define external deserializer for Grade enum.

I added additional field to enum - UNKNOWN:

enum Grade {
    A, B, C, UNKNOWN;

    public static Grade fromString(String value) {
        for (Grade grade : values()) {
            if (grade.name().equalsIgnoreCase(value)) {
                return grade;
            }
        }

        return UNKNOWN;
    }
}
class Employee {

    @JsonDeserialize(using = GradeDeserializer.class)
    private Grade grade;
    private String name;

    public Grade getGrade() {
        return grade;
    }

    public void setGrade(Grade grade) {
        this.grade = grade;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Employee [grade=" + grade + ", name=" + name + "]";
    }
}

Now, parser could look like that:

class GradeDeserializer extends JsonDeserializer<Grade> {
    @Override
    public Grade deserialize(JsonParser parser, DeserializationContext context)
            throws IOException, JsonProcessingException {
        return Grade.fromString(parser.getValueAsString());
    }
}

Example usage:

public class JacksonProgram {

    public static void main(String[] args) throws Exception {
        ObjectMapper objectMapper = new ObjectMapper();
        JsonFactory jsonFactory = new JsonFactory();
        JsonParser parser = jsonFactory
                .createJsonParser("{\"name\":\"John\", \"grade\":\"D\"}");
        Employee employee = objectMapper.readValue(parser, Employee.class);
        System.out.println(employee);
    }

}

Output:

Employee [grade=UNKNOWN, name=John]

If you don't want to add additional field, you would return null for example.


I have found a way to do this like follows:

public static void main(String[] args) throws JsonParseException, JsonMappingException, UnsupportedEncodingException, IOException {
    String json = "{\"name\":\"John\", \"grade\":\"D\"}";

    ObjectMapper mapper = new ObjectMapper();
    mapper.configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL, true);
    Employee employee = mapper.readValue(new ByteArrayInputStream(json.getBytes("UTF-8")), Employee.class);

    System.out.println(employee.getGrade());
}

This outputs :

null

other classes:

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown = true)
public class Employee {
    private String name;
    private Grade grade;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Grade getGrade() {
        return grade;
    }

    public void setGrade(Grade grade) {
        this.grade = grade;
    }
}



import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown = true)
public enum Grade {A, B, C}

I haven't come across a way to do this with an annotation yet.

I hope this helps.

Tags:

Java

Jackson