【问题标题】:convertValue issue with Jackson - alternative? [duplicate]杰克逊的 convertValue 问题 - 替代方案? [复制]
【发布时间】:2016-04-30 19:27:00
【问题描述】:

我正在尝试理解 JacksonconvertValue 方法。最初我认为它在某种程度上等同于 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 中发生变化。对我来说,杰克逊似乎没有在内部调用“new MyPojo()”并在之后为每个找到的变量设置值。

我能做些什么来防止这种情况发生?有替代方法吗?我是否需要创建一个复制构造函数才能在不引用 Map 中的值的情况下获得一个真正的新对象?
此外,如果有人能告诉我 convertValue 实际做了什么,那就太好了。

【问题讨论】:

  • 那么,您正在尝试将 MyPojo 转换为 MyPojo?当你这样做时,Jackson 不会做任何事情:它只会返回原始的 MyPojo,因为不需要转换任何东西。
  • 源代码永远是你最好的代码源代码。
  • @JBNizet 不一定。通常是LinkedHashMap,在这种情况下,错误没有发生。虽然在这种特殊情况下查看调试器是正确的 - 所以谢谢。
  • @JarrodRoberson 我不知道您为什么将其作为副本关闭?我没有问过“如何克隆一个对象”——我完全清楚我的选择。最初,我试图了解我的代码中发生了什么。所以关闭似乎不合适 - 没有冒犯。

标签: java jackson


【解决方案1】:

查看convertValue的代码,你会发现

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

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

现在您的问题可以推断为如何克隆对象,这通常是一个复杂的话题。

  • 如果你想要安全的深拷贝,你可以序列化和反序列化对象。但是,此过程的性能很差。

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

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

【讨论】:

  • 感谢解释和源代码sn-p。我现在确实更好地理解了这个问题。
猜你喜欢
  • 2014-08-29
  • 2016-05-15
  • 1970-01-01
  • 2015-08-19
  • 2020-12-24
  • 2019-04-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多