根据值反序列化为通用成员
Deserialize to generic member based on value
我有一个像这样的通用 class:
public class Pojo<T> {
@JsonProperty("value")
public T[] values;
};
T 可以容纳 String
、LocalDateTime
或 Integer
。 String 和 Integer 之间的区别似乎工作正常,很可能是因为这些类型在序列化 JSON 文件中的表示方式不同。但是,当我的 JSON 对象中有日期时间时(参见示例),它无论如何都会被解析为字符串。
value
字段实际使用的类型由输入决定。虽然我在以下最小示例中确实了解了这些知识,但对于我的程序中此代码的所有使用情况并非如此。我只能依赖字段 value
.
值的模式
public class Main {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
String json = "{\"value\": \"2022-02-22T12:00:00\"}";
Pojo<?> deserialized = mapper.readValue(json, Pojo.class);
assert deserialized.value[0] instanceof LocalDateTime;
}
我还没有成功修改 JsonTypeInfo
。如果此字段的所有值都匹配模式 yyyy-MM-dd'T'hh:mm:ss
?
,是否可以将值字段解析为 LocalDateTime
对象数组
这是您的问题 - Pojo<?> deserialized = mapper.readValue(json, Pojo.class)
。
ObjectMapper 不知道要将 T
解析为什么类型。要告诉它您需要使用 readValue
重载和 TypeReference, or the overload with JavaType 的类型。我发现 JavaType
更容易阅读,所以这里有一个例子:
public class Test {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
String json = "{\"value\": \"2022-02-22T12:00:00\"}";
JavaType javaType = TypeFactory.defaultInstance().constructParametricType(Pojo.class, LocalDateTime.class);
Pojo<LocalDateTime> deserialized = mapper.readValue(json, javaType);
System.out.println(deserialized.values[0].toLocalDate());
System.out.println(deserialized.values[0].toLocalTime());
}
}
构造参数时 JavaType
第一个参数是 class 本身,接下来是具体的泛型类型。
编辑: 考虑到新信息,我能想到的最好办法是自定义反序列化器,它在运行时解析类型。像这样:
public class UnknownTypeDeserializer<T> extends StdDeserializer<Pojo<T>> {
private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
public UnknownTypeDeserializer() {
super((Class<?>) null);
}
@Override
public Pojo<T> deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException, JacksonException {
JsonNode node = parser.getCodec().readTree(parser);
String value = node.get("value").asText();
Pojo<T> pojo = new Pojo<>();
T[] arr;
try {
arr = (T[]) new LocalDateTime[]{LocalDateTime.parse(value, this.formatter)};
} catch (Exception exc) {
try {
arr = (T[]) new Integer[]{Integer.parseInt(value)};
} catch (NumberFormatException numberFormatException) {
arr = (T[]) new String[]{value};
}
}
pojo.values = arr;
return pojo;
}
}
想法是尝试解析为 LocalDateTime
,如果不可能,请尝试解析为 int
,如果不可能,再次保留为 String
。这是相当丑陋的做法,但我只是想说明这个想法。与其捕获异常,不如检查格式,例如使用正则表达式,并根据哪个正则表达式匹配,解析为正确的类型可能更好。我用string和int测试了一下,确实可以。
public class Test {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
SimpleModule simpleModule = new SimpleModule();
simpleModule.addDeserializer(Pojo.class, new UnknownTypeDeserializer<>());
mapper.registerModule(simpleModule);
String json1 = "{\"value\": \"2022-02-22T12:00:00\"}";
Pojo<?> deserialized1 = mapper.readValue(json1, Pojo.class);
System.out.println("is date - " + (deserialized1.values[0] instanceof LocalDateTime));
String json2 = "{\"value\": \"bla bla bla\"}";
Pojo<?> deserialized2 = mapper.readValue(json2, Pojo.class);
System.out.println("is string - " + (deserialized2.values[0] instanceof String));
String json3 = "{\"value\": 41}";
Pojo<?> deserialized3 = mapper.readValue(json3, Pojo.class);
System.out.println("is int - " + (deserialized3.values[0] instanceof Integer));
}
}
我有一个像这样的通用 class:
public class Pojo<T> {
@JsonProperty("value")
public T[] values;
};
T 可以容纳 String
、LocalDateTime
或 Integer
。 String 和 Integer 之间的区别似乎工作正常,很可能是因为这些类型在序列化 JSON 文件中的表示方式不同。但是,当我的 JSON 对象中有日期时间时(参见示例),它无论如何都会被解析为字符串。
value
字段实际使用的类型由输入决定。虽然我在以下最小示例中确实了解了这些知识,但对于我的程序中此代码的所有使用情况并非如此。我只能依赖字段 value
.
public class Main {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
String json = "{\"value\": \"2022-02-22T12:00:00\"}";
Pojo<?> deserialized = mapper.readValue(json, Pojo.class);
assert deserialized.value[0] instanceof LocalDateTime;
}
我还没有成功修改 JsonTypeInfo
。如果此字段的所有值都匹配模式 yyyy-MM-dd'T'hh:mm:ss
?
LocalDateTime
对象数组
这是您的问题 - Pojo<?> deserialized = mapper.readValue(json, Pojo.class)
。
ObjectMapper 不知道要将 T
解析为什么类型。要告诉它您需要使用 readValue
重载和 TypeReference, or the overload with JavaType 的类型。我发现 JavaType
更容易阅读,所以这里有一个例子:
public class Test {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
String json = "{\"value\": \"2022-02-22T12:00:00\"}";
JavaType javaType = TypeFactory.defaultInstance().constructParametricType(Pojo.class, LocalDateTime.class);
Pojo<LocalDateTime> deserialized = mapper.readValue(json, javaType);
System.out.println(deserialized.values[0].toLocalDate());
System.out.println(deserialized.values[0].toLocalTime());
}
}
构造参数时 JavaType
第一个参数是 class 本身,接下来是具体的泛型类型。
编辑: 考虑到新信息,我能想到的最好办法是自定义反序列化器,它在运行时解析类型。像这样:
public class UnknownTypeDeserializer<T> extends StdDeserializer<Pojo<T>> {
private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
public UnknownTypeDeserializer() {
super((Class<?>) null);
}
@Override
public Pojo<T> deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException, JacksonException {
JsonNode node = parser.getCodec().readTree(parser);
String value = node.get("value").asText();
Pojo<T> pojo = new Pojo<>();
T[] arr;
try {
arr = (T[]) new LocalDateTime[]{LocalDateTime.parse(value, this.formatter)};
} catch (Exception exc) {
try {
arr = (T[]) new Integer[]{Integer.parseInt(value)};
} catch (NumberFormatException numberFormatException) {
arr = (T[]) new String[]{value};
}
}
pojo.values = arr;
return pojo;
}
}
想法是尝试解析为 LocalDateTime
,如果不可能,请尝试解析为 int
,如果不可能,再次保留为 String
。这是相当丑陋的做法,但我只是想说明这个想法。与其捕获异常,不如检查格式,例如使用正则表达式,并根据哪个正则表达式匹配,解析为正确的类型可能更好。我用string和int测试了一下,确实可以。
public class Test {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
SimpleModule simpleModule = new SimpleModule();
simpleModule.addDeserializer(Pojo.class, new UnknownTypeDeserializer<>());
mapper.registerModule(simpleModule);
String json1 = "{\"value\": \"2022-02-22T12:00:00\"}";
Pojo<?> deserialized1 = mapper.readValue(json1, Pojo.class);
System.out.println("is date - " + (deserialized1.values[0] instanceof LocalDateTime));
String json2 = "{\"value\": \"bla bla bla\"}";
Pojo<?> deserialized2 = mapper.readValue(json2, Pojo.class);
System.out.println("is string - " + (deserialized2.values[0] instanceof String));
String json3 = "{\"value\": 41}";
Pojo<?> deserialized3 = mapper.readValue(json3, Pojo.class);
System.out.println("is int - " + (deserialized3.values[0] instanceof Integer));
}
}