我正在尝试序列化一个jpa托管类(openjpa)。
此类包含一个集合。在运行时,这个集合的类型是org.apache.openjpa.util.java $ util $ LinkedHashSet $ proxy(我们正在使用openjpa)。
杰克逊将序列化此罚款,但在反序列化时将失败,因为无法构造此类型(并且当使用spring security的jackson配置时,它不会列入白名单。)
所以现在我认为解决方案是定制序列化,以便将其作为更标准的集合进行分类和反序列化。在反序列化时,只需要实现Set。
我想尝试避免污染持久化类(所以想要使用mixins)。
容器类是User类,它包含Role类的集合。 到目前为止,我有:
@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
序列化时会出现此错误。
所以它似乎没有尊重集合容器或其他东西。
答案 0 :(得分:2)
所以我解决的答案是基于杰克逊如何不支持开箱即用的非标准集合。按理说,只有java sdk集合可以开箱即用。
所以我最终做的就是Spring安全性与它添加的非标准集合相同。
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确实为这个不可修改的集合提供了一个自定义的反序列化器,而这似乎是唯一可行的方法。
然后是mixin:
@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);
}
}
我只是直接返回哈希集(例如,不将其包装在不可修改的集合中)。
我想底线是我不需要将set序列化回到它所来自的同一个类(org.apache.openjpa.util.java $ util $ LinkedHashSet $ proxy)所以只要它是一个Set什么实施并不重要。在这种情况下,我认为实现是HashSet。
我怀疑这是成功反序列化杰克逊不支持开箱即用的集合的唯一方法。