我正在尝试序列化一个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。
我怀疑这是成功反序列化杰克逊不支持开箱即用的集合的推荐/唯一方法。