![](/img/trans.png)
[英]Including Morphia for JSON-to-object mapping with JAX-RS+Jersey
[英]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
這種情況有兩種處理方式:
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);
}
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.