0

我正在尝试通过 FasterJackson 的 ObjectMapper.convertValue(map, ComplexRecord.class) 方法从 Map(String, Object) 反序列化对象。

我的目标对象中包含许多其他对象。唯一有问题的对象是使用 FasterJackson(杰克逊)的 AnyGetter/AnySetter 方法的嵌入式“AnyObject”对象。

AnyObject 实例适用于 FasterJackson 的所有其他用例,但目前,它涉及更多“ComplexRecord”反序列化。

这是它的样子:

@Data
public class ComplexRecord {

    private String id;
    private AnyObject data;
    private String status;
    private Instant createdDateTime;

}
@Data
public class AnyObject {

    @Getter(AccessLevel.NONE)
    @Setter(AccessLevel.NONE)
    private final Map<String, Object> data;

    public AnyObject() {
        this(new LinkedHashMap<>());
    }

    public AnyObject(Map<String, Object> sourceData) {
        this.data = new LinkedHashMap<>(sourceData);
    }

    @JsonAnySetter
    public void setData(String name, Object value) {
        this.data.put(name, value);
    }

    @JsonAnyGetter
    public Map<String, Object> getData() {
        return Collections.unmodifiableMap(this.data);
    }

}

当我尝试使用 ObjectMapper.convertValue(map, ComplexRecord.class) 时,由于此错误,它无法反序列化“数据”字段:

Cannot construct instance of `AnyObject` 
  (although at least one Creator exists): no String-argument 
   constructor/factory method to deserialize from String value 
    ('{"id":"123","v":"anything"}')

at [Source: UNKNOWN; line: -1, column: -1]

我想为此找到一个非常干净的解决方法。这个问题似乎源于我使用 Map 的复杂源中的 ObjectMapper.convertValue 方法,其中键“数据”最初可作为字符串使用。如果我执行类似的操作,但使用 ObjectMapper.readValue() 而不是 ObjectMapper.convertValue(),那么反序列化到 AnyObject 就可以了。

由于我没有将 Map 的源对象更改为可以与 ObjectMapper.readValue() 方法一起使用的东西的奢侈,我可能只剩下几个选择。

我发现的一个选项是使用 FasterJackson 的 Custom Deserializer。我看到的唯一问题是没有明确的方法可以访问提供给 Deserializer 的内部 ObjectMapper。当我调试反序列化器时,我确实看到 JsonParser.getCodec() 是 ObjectMapper,但即使尝试在自定义反序列化器中执行 readValue,反序列化也会失败并出现相同的错误。IE

AnyObject value = jsonParser.getCodec().readValue(p, AnyObject.class);

然而,以下一组调用工作得很好:

String stringValue = jsonParser.getCodec().readValue(p, String.class);
AnyObject anyObject = objMapper.readValue(stringValue, AnyObject.class);

除了这是反序列化的 2 步过程,而不是 1 步过程;唯一的另一个问题是我没有一种干净的方法来使用上面提到的“objMapper”(ObjectMapper)实例,而无需将编解码器转换为 ObjectMapper 实例。

这对我来说似乎是一个黑客,但我想听听你的想法,并看看是否有其他更友好的解决方案可用。

还有一些想法/选项,但我想对此发表公正的意见,看看是否有更简单的方法来处理这种类型的“复杂”转换。

最理想的结果是强制将字符串强制转换为我想要的类型——AnyObject。通过注释或一些非常简单的策略。

但是如果我必须通过自定义反序列化器来处理这个问题,我的偏好是能够以一种干净的方式获得进程内 ObjectMapper 的句柄。

想法?

4

1 回答 1

0

通过实现自定义 FasterJackson 反序列化器,尝试了一些事情并实现了以下目标:

JsonNode node = jsonParser.readValueAsTree();
AnyObject val = jsonParser.getCodec().getFactory().createParser(node.asText().getBytes()).readValueAs(AnyObject.class);

我仍然对可能更简单或倾向于更好性能的解决方案持开放态度,在解析过程中产生的中间垃圾更少。

于 2018-03-12T13:02:24.237 回答