与Jackson的convertValue问题 - 另类?

时间:2016-01-24 13:39:28

标签: java jackson

我试图了解 Jackson convertValue方法。最初我认为它有点等同于Gson#fromJson方法,但事实并非如此。

问题在于:

// Map<String, Object> map = ...
ObjectMapper mapper = new ObjectMapper();
MyPojo pojo = mapper.convertValue(map.get(key), MyPojo.class);
for (Map.Entry<String, Object> m : map.entrySet()) {
    System.out.println("k=" + m.getKey() + "    v=" + m.getValue());
}
pojo.name = "Banana";
for (Map.Entry<String, Object> m : map.entrySet()) {
    System.out.println("k=" + m.getKey() + "    v=" + m.getValue());
}

输出

k=66e8c013   v=MyPojo{name='Apple'} 
k=66e8c013   v=MyPojo{name='Banana'}

注意:代码和输出已被拆分为相关部分

因此,如果我修改我的 pojo 对象,它也会在原始Map中进行更改。对我而言,杰克逊似乎没有打电话给新的MyPojo()&#34;在内部并在之后设置每个找到的变量的值。

我该怎么做才能防止这种情况发生?有替代方法吗?我是否需要创建一个复制构造函数才能获得一个真正的新对象而不引用Map中的值?
另外,如果有人能告诉我convertValue实际上做了什么,那将会很酷。

1 个答案:

答案 0 :(得分:0)

查看convertValue的代码,找到

    if (targetType != Object.class
            && !toValueType.hasGenericTypes()
            && targetType.isAssignableFrom(fromValue.getClass())) {
        return fromValue;
    }

因此,如果map.get(key)的类型为MyPojo,则convertValue()方法确实会返回对输入的引用。这解释了为什么当您更改“已转换”对象时地图中的值会发生变化。

现在你的问题可以推断出如何克隆一个对象,这一般是一个复杂的话题。

  • 如果需要安全深层复制,可以序列化和反序列化对象。但是,此过程会导致性能下降。

  • 您可以实施clone()方法并标记班级Cloneable,这是一种相当常见的解决方案,可为您提供控制和良好的表现。

  • 您还可以查看具有cloneBean()方法的Apache Commons BeanUtils,该方法使用getter和setter来克隆对象的属性。