java - 如何在注册 DefaultScalaModule 的 Spring 应用程序中使用 Jackson 将 JSON 对象反序列化为 Java 集合?
问题描述
我正在创作一个通过 Spring 控制器提供 REST 端点的 Java 库。一个端点的有效负载是我的JavaRoutine
类的一个实例,我为此提供了一个 JSON 序列化器/解串器对。这是(稍微简化):
@JsonSerialize(using = JavaRoutine.Serializer.class)
@JsonDeserialize(using = JavaRoutine.Deserializer.class)
public class JavaRoutine {
private final String jobId;
private final List<Object> inputValues;
private final List<ExpressionType> inputTypes; // ExpressionType is defined in my lib
public JavaRoutine(String jobId) {
this.jobId = jobId;
this.inputValues = new ArrayList<>();
this.inputTypes = new ArrayList<>();
}
public String getJobId() { return jobId; }
public void addInput(Object value) {
inputValues.add(value);
inputTypes.add(value == null ? null : ExpressionType.getTypeForValue(value));
}
public static class Serializer extends StdSerializer<JavaRoutine> {
private static final ObjectMapper mapper = new ObjectMapper();
public Serializer() {
super(JavaRoutine.class);
}
@Override
public void serialize(JavaRoutine routine, JsonGenerator gen, SerializerProvider provider) throws IOException {
gen.writeStartObject();
gen.writeStringField("jobId", routine.jobId);
gen.writeArrayFieldStart("inputs");
int inputCount = routine.inputValues.size();
for (int i = 0; i < inputCount; i++) {
gen.writeStartObject();
gen.writeStringField("type", mapper.writeValueAsString(routine.inputTypes.get(i)));
gen.writeStringField("value", mapper.writeValueAsString(routine.inputValues.get(i)));
gen.writeEndObject();
}
gen.writeEndArray();
gen.writeEndObject();
}
}
public static class Deserializer extends StdDeserializer<JavaRoutine> {
private static final ObjectMapper mapper = new ObjectMapper();
public Deserializer() {
super(JavaRoutine.class);
}
@Override
public JavaRoutine deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
Map<String, Object> fields = p.readValueAs(new TypeReference<Map<String, Object>>() {});
JavaRoutine routine = new JavaRoutine((String) fields.get("jobId");
List<Map<String, String>> inputs = (List<Map<String, String>>) fields.get("inputs");
for (Map<String, String> input: inputs) {
ExpressionType inputType = mapper.readValue(input.get("type"), ExpressionType.class);
Object inputValue = inputType == null ? null : mapper.readValue(input.get("value"), inputType.getJavaType());
routine.addInput(inputValue);
}
return routine;
}
}
}
这行得通。除非链接库的应用程序已经为 Scala 注册了 Jackson 模块,它需要它来实现自己的目的。(简而言之,这个 Jackson 模块的目的是将 JSON 结构反序列化为 Scala 集合,而不是 Java 集合。)因此,调用将p.readValueAs()
“输入”数组反序列化为 Scala 列表,这会导致转换为List<Map<String, String>>
两个线以后失败。
你会推荐什么解决方案?
解决方案
没有试过你的例子。但是在谷歌的多个节点的 Kubernetes 上运行,在节点之间跳转时得到了奇怪的 scala 集合对象。这帮助了我一半。
尝试在(我的猜测)反序列化器中创建如下映射器。
ObjectMapper mapper.registerModule(new DefaultScalaModule());
scala映射也有一些问题。对我来说,现在订单没有保留。所以 Lists and Maps (LinkedHashMap) 会失去原来的顺序。:(
推荐阅读
- ios - 如何在 UITableView 中的最后一个单元格之后提供动态额外空间
- token - 如何将变量与javacc中的令牌匹配?
- javascript - 处理 Ajax 自动重定向
- c++ - 在 Linux 和 Windows 中启用 curses
- c# - WPF中网格可见性的多重绑定
- javascript - 滚动到顶部 - 纯香草 JS
- java - 创建一个空列表
基于泛型 - excel - GetValueInvocationException 从 Excel 电子表格中读取单元格
- php - 如何将额外的畅销产品添加到 Storefront 主题 Woocommerce?
- python - QLineEdit 返回空字符串