【问题标题】:Generic object serialization in Jackson with Java使用 Java 实现 Jackson 中的通用对象序列化
【发布时间】:2011-02-14 16:32:15
【问题描述】:

我想将字符串 {"a": 1.0} 作为通用 Java 对象读取,同时保持相同的字符串格式。但是,当我尝试时,Jackson 会自动将内部表示更改为 {a = 1}。换句话说,我怎样才能得到下面的代码来打印{"a": 1.0} 而不是{a = 1}?请注意,我必须将其作为Object 读入(由于其他程序限制)。

import org.codehaus.jackson.map.ObjectMapper;

public class Main {

    public static void main(String[] args) {
        try
    {
            ObjectMapper mapper = new ObjectMapper();
            Object myObject = mapper.readValue("{\"a\": 1.0}", Object.class);
            System.out.println(myObject.toString());            
    }
    catch (Exception e)
    {
        e.printStackTrace();
      System.err.println(e.getMessage()); 
    }
    }

}

【问题讨论】:

  • 这对我来说没有意义。对象没有键“a”的任何属性,那么如何读取它呢?你不需要用这个属性创建一个类吗?
  • 也许他假设 Jackson 以某种方式通过心灵感应计算出预期的类型......实际发生的是 Object.class 类型对 Jackson 进行了特殊处理:它将创建到 Maps、Lists 和包装器的“自然”映射类型(显然都是对象)

标签: java json jackson


【解决方案1】:

创建的对象将是一个地图(与其他 cmets 一样),因此它的 toString 会生成您所看到的 {a = 1}。为了让您的代码打印出更接近输入值的内容,您需要使用 Jackson 将其写回,如下所示:

System.out.println(mapper.writeValueAsString(myObject));

这给了我我相信你正在寻找的东西:

{"a":1.0}

换句话说,Jackson 已将您的输入字符串反序列化为任意 Java 对象。当您在对象上调用toString 时,当然会使用它自己的toString。这可以随心所欲地编写对象,包括使用来自Object 的方法。要重现输入字符串,您必须使用 Jackson 将我们的对象序列化回来。

【讨论】:

    【解决方案2】:

    您需要一个与所需 json 结构匹配的现有类。对象不是这样的类。如果需要,您仍然可以将其称为Object:

    Object myObject = mapper.readValue("{\"a\": 1.0}", SomeClass.class);
    

    【讨论】:

      【解决方案3】:

      如果你使用调试器,你会看到返回的 Object 的类型是LinkedHashMap。所以你看到的是LinkedHashMap.toString() 的输出。 Jackson 无法更改这一点,因此您可以将其转换为 Map 并自己创建字符串,或者要求另一种返回类型为您生成 JSON 字符串:

      if(myObject instanceof Map<?, ?>){
          final Map<?, ?> map = (Map<?, ?>) myObject;
          final StringBuilder sb = new StringBuilder("{");
          boolean first = true;
          for(final Entry<?, ?> entry : map.entrySet()){
              if(first){
                  first = false;
              } else{
                  sb.append(",");
              }
              sb.append("\n\t'")
                  .append(entry.getKey())
                  .append("':'")
                  .append(entry.getValue())
                  .append("'");
          }
          if(!first){
              sb.append("\n");
          }
          sb.append("}");
          System.out.println(sb.toString());
      
      } else{
          System.out.println(myObject);
      }
      

      输出:

      {
          'a':'1.0'
      }
      

      【讨论】:

      • Jackson 支持写出地图,因此您可以执行以下操作:System.out.println(mapper.writeValueAsString(myObject)),而不是编写自己的序列化程序。
      【解决方案4】:

      当告诉 Jackson 将 JSON 绑定到 Object.class 时,它就是这样做的;但由于它不知道 JSON 中可能包含什么(或可能想要使用的类),它必须使用大多数基本的 Java 类型:地图、列表、数字、布尔值和字符串。所以任何 JSON 对象都用 Map 表示; JSON Array by List,等等。

      如果你想要一个自定义对象,你必须指定它的类型;或者,在序列化时,启用显式类型信息(“多态类型处理”)。这将添加类名或类型名,并可用于反序列化回确切的类型。

      为此,类型本身(或其超类型之一)必须使用@JsonTypeInfo 注解;或者,如果是 Object 属性,则为属性(字段或方法)@JsonTypeInfo。

      【讨论】:

        猜你喜欢
        • 2011-12-23
        • 1970-01-01
        • 1970-01-01
        • 2019-12-01
        • 2021-06-03
        • 2020-08-07
        • 1970-01-01
        • 2014-03-11
        • 1970-01-01
        相关资源
        最近更新 更多