如何使用杰克逊 2 将集合的子类序列化和解义为已知集合



我正在尝试序列化一个jpa托管类(openjpa(。

此类包含一个集合。在运行时,这个集合的类型是org.apache.openjpa.util.java$util$LinkedHashSet$proxy (我们正在使用openjpa(。

杰克逊将序列化此罚款,但在反序列化时将失败,因为无法构造此类型(并且当使用Spring Security的杰克逊配置时,它不会被列入白名单(。

所以现在我认为解决方案是自定义序列化,以便将其分离和反序列化为更标准的集。当它被反序列化时,它只需要实现 Set。

我想尽量避免污染持久类(所以想使用 mixins(。

容器类是用户类,它包含角色类的集合。 到目前为止,我有:

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE)
public static class UserMixin {
@JsonDeserialize(as = LinkedHashSet.class, contentAs = LinkedHashSet.class)
@JsonSerialize(as = LinkedHashSet.class, contentAs = LinkedHashSet.class, typing = Typing.DYNAMIC)
private Set<Role> roles;
}

但是当我带着这个跑步时,我得到

Invalid definition for property roles (of type 'Lxxx/yyy/User;'): Can not refine serialization content type [simple type, class xxx.yyy.Role] into java.util.LinkedHashSet; types not related

序列化时会发生此错误。

所以它似乎不尊重设置容器或其他东西。

所以我确定的答案是基于杰克逊如何不支持开箱即用的非标准集合。按理说,只有java sdk集合才能开箱即用。

所以我最终所做的与 spring security 对它添加的非标准集合所做的相同。

context.setMixInAnnotations(Collections.<Object>unmodifiableSet(Collections.emptySet()).getClass(), UnmodifiableSetMixin.class);

(来自org.springframework.security.jackson2.CoreJackson2Module(

所以我也做了同样的事情:

context.setMixInAnnotations(org.apache.openjpa.util.java$util$LinkedHashSet$proxy.class, OpenJpaLinkedHashSetProxyMixin.class);

这意味着我可以自定义杰克逊对待这门课的方式。

现在杰克逊序列化这个集合没有问题。问题一直出在序列化上。杰克逊似乎在序列化方面支持 Set 的任何子类。它在反序列化方面挣扎。

Spring所做的是为该不可修改的集合提供了一个自定义的反序列化器,这似乎是唯一的方法。

那么混合:

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)
@JsonDeserialize(using = Deserializer.class)
public static class OpenJpaLinkedHashSetProxyMixin {
}

对从中复制的反序列化程序进行细微调整的地方

org.springframework.security.jackson2.UnmodifiableSetDeserializer

并且是:

class UnmodifiableSetDeserializer extends JsonDeserializer<Set> {
@Override
public Set deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
ObjectMapper mapper = (ObjectMapper) jp.getCodec();
JsonNode node = mapper.readTree(jp);
Set<Object> resultSet = new HashSet<Object>();
if (node != null) {
if (node instanceof ArrayNode) {
ArrayNode arrayNode = (ArrayNode) node;
Iterator<JsonNode> nodeIterator = arrayNode.iterator();
while (nodeIterator.hasNext()) {
JsonNode elementNode = nodeIterator.next();
resultSet.add(mapper.readValue(elementNode.traverse(mapper), Object.class));
}
} else {
resultSet.add(mapper.readValue(node.traverse(mapper), Object.class));
}
}
return Collections.unmodifiableSet(resultSet);
}
}

例如,我只是直接返回哈希集(不将其包装在不可修改的集中(。

我想底线是我不需要将集合序列化回它来自的同一类(org.apache.openjpa.util.java$util$LinkedHashSet$proxy(,所以只要它是一个 Set 它就无关紧要什么实现。在这种情况下,我认为实现是HashSet。

我怀疑这是成功反序列化杰克逊不支持开箱即用的集合的推荐/唯一方法。

最新更新