簡體   English   中英

如何忽略 Jackson JSON-to-Object 映射中的枚舉字段?

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

我有一個類似的 JSON 對象:

{"name":"John", "grade":"A"}

要么

{"name":"Mike", "grade":"B"}

要么

{"name":"Simon", "grade":"C"}

等等

我正在嘗試將上述 JSON 映射到:

@JsonIgnoreProperties(ignoreUnknown = true)
public class Employee{
      @JsonIgnoreProperties(ignoreUnknown = true)
      public enum Grade{ A, B, C }
      Grade grade;
      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;
  }
}

上面的映射工作正常,但將來會有更多的“等級”類型,比如 D、E 等,這會破壞現有的映射並拋出以下異常

05-08 09:56:28.130: W/System.err(21309): org.codehaus.jackson.map.JsonMappingException: Can not construct instance of Employee from String value 'D': value not one of declared Enum instance names

有沒有辦法忽略枚舉類型中的未知字段?

謝謝

我找到了一種方法來做到這一點,如下所示:

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());
}

這輸出:

無效的

其他類:

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}

我還沒有遇到用注釋來做到這一點的方法。

我希望這有幫助。

我認為您應該為Grade枚舉定義外部解串器

我向枚舉添加了額外的字段 - 未知:

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 + "]";
    }
}

現在,解析器看起來像這樣:

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

用法示例:

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);
    }

}

輸出:

Employee [grade=UNKNOWN, name=John]

例如,如果您不想添加其他字段,則可以返回null

@JsonDeserialize相比, @JsonDeserialize @JsonCreator提供了更簡潔的解決方案。

我們的想法是來注釋valueOf()替代(稱為safeValueOf()在這個例子中)與@JsonCreator ,然后傑克遜會使用您的實現反序列化的字符串。

請注意,實現位於枚舉內部,您可以將其用作其他對象中的字段而無需更改。

下面的解決方案包含在單元測試中,因此您可以直接運行它。

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));
    }
}

我正在使用 boot2(盡管這也可以在引導 1 中工作)但您可以在應用程序屬性/yaml 中啟用反序列化功能;

spring:
  jackson:
    deserialization:
      READ_UNKNOWN_ENUM_VALUES_AS_NULL: true

這種情況有兩種處理方式:

選項 1:將未知枚舉值替換為null

為此,在ObjectMapper啟用READ_UNKNOWN_ENUM_VALUES_AS_NULL設置。 在此之后,當您解析具有未知枚舉字段值的 Object 時,它將被反序列化為null 參考下面的示例代碼:

import com.fasterxml.jackson.databind.*;

public static ObjectMapper getMapper() {
    return ObjectMapper().enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL);
}

選項 2:用默認枚舉值替換未知枚舉值(比如UNKNOWN

為此,首先在ObjectMapper啟用READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE設置。 然后,在您的枚舉類中,使用@JsonEnumDefaultValue注釋要用作默認枚舉值的@JsonEnumDefaultValue 參考下面的代碼示例:

import com.fasterxml.jackson.databind.*;

public static ObjectMapper getMapper() {
    return ObjectMapper().enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE);
}


public enum YourEnum {
   A,
   B,
   C,
   @JsonEnumDefaultValue UNKNOWN;

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM