【问题标题】:Serializing and Deserializing Raw Json String using Jackson使用 Jackson 序列化和反序列化原始 Json 字符串
【发布时间】:2017-04-02 00:00:09
【问题描述】:

我正在使用Jackson Fasterxml 2.8.0版对json进行序列化和反序列化,如下:

public static byte[] serializeData(Object object){
   final ObjectMapper mapper = new ObjectMapper();
   return mapper.writeValueAsBytes(object);
}

public static void main(String [] args) {
  String json = "{ \"id\" : \"user1\" }"; // need to escape or else compiler complains

  byte[] result = serializeData(json);

  final ObjectMapper mapper = new ObjectMapper();
  final JsonNode jsonNode = mapper.readTree(result);

  System.out.println(json);
  System.out.println(jsonNode.toString());
  System.out.println(jsonNode.getNodeType());

  Iterator<String> fields = jsonNode.fieldNames();
  while(fields.hasNext()){
    System.out.println("field - " + fields.next());
  }
}

输出是:

{ "id" : "user1" }
"{ \"id\" : \"user1\" }"
STRING

请注意,没有用于打印字段名称的输出行。因此,JsonNode 似乎没有任何属性,并且由于某种原因,toString() 在其中包含转义字符。我是否以错误的方式使用这个库?为什么在反序列化字节数组时会导致我找不到最初添加的字段的行为?

更新

提供应用程序的更多上下文。应用程序接收 Json 作为字符串输入。反序列化 Json 的代码不知道 Json 的模型。它只是期望它是有效的 Json 对象,以便它可以遍历其中的各个字段。

【问题讨论】:

    标签: java json jackson


    【解决方案1】:

    您将 JSON 字符串误认为 java 对象,这是这里的关键问题。

      String json = "{ \"id\" : \"user1\" }"; // need to escape or else compiler complains
    
      byte[] result = serializeData(json);
    

    您的String json 只是一个字符串,它的内容是什么并不重要,使用mapper.writeValueAsBytes(object) 只是序列化一个字符串,从而产生一个字符串类型的 JSON 节点。

    要序列化具有字符串类型字段 id 的对象,您需要序列化具有类型为 String 的名为 id 的字段的对象。

    例如:

    public class User {
        private String id;
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    
        @Override
        public String toString() {
            return "User [id=" + id + "]";
        }
    }
    

    这个类型的User可以序列化为{"id":"User1"}(如果id字段设置为“User1”)。

    在以下示例中,您要么从 POJO (User user = new User();) 开始,要么从有效的 json 字符串 (String json = "{ \"id\" : \"user1\" }";) 开始。

    在第一种情况下,您首先将对象映射为 json 字节,然后解析这些字节以获得 JSONNode(一种 json 的 DOM 树)。

    在第二种情况下,您只需 parse 字节来获取节点,您不会 writeValueAsBytes 的 json 字符串,因为您只需 stringify 两次因此得到STRING 类型的值节点。

        User user = new User();
        user.setId("user1");
    
        ObjectMapper mapper = new ObjectMapper();
        byte[] jsonBytes = mapper.writeValueAsBytes(user);
    
    
        System.out.println(new String(jsonBytes)); // will print {"id":"user1"}
    
        JsonNode node = mapper.readTree(jsonBytes);
        Iterator<String> names = node.fieldNames();
        while (names.hasNext()) {
            String name = (String) names.next();
            JsonNodeType type = node.get(name).getNodeType();
            System.out.println(name+":"+type); //will print id:STRING
        }
    
        // This is not a object to serialize 
        // This is a string to parse into a json object
        String json = "{ \"id\" : \"user1\" }";
    
        JsonNode node2 = mapper.readTree(json.getBytes());
        names = node.fieldNames();
        while (names.hasNext()) {
            String name = (String) names.next();
            JsonNodeType type = node.get(name).getNodeType();
            System.out.println(name+":"+type); //will print id:STRING
        }
    

    【讨论】:

    • 我只是重写了整件事,因为评论在哪里失控并弄乱了答案。
    【解决方案2】:

    这是因为您在 writeValueAsBytes 方法中调用 toString() 将对象转换为字符串。以下应该可以正常工作:

    final ObjectMapper mapper = new ObjectMapper();
    ObjectNode node = JsonNodeFactory.instance.objectNode();
    node.put("id", "user1");
    byte[] result = mapper.writeValueAsBytes(node);
    final JsonNode json = mapper.readTree(result);
    System.out.println(json);
    Iterator<String> fieldNames = json.fieldNames();
    while(fieldNames.hasNext()){
        System.out.println(fieldNames.next());
    }
    if(json.has("id")){
      System.out.println("No id");
    }
    

    更新

    如果您不知道要将 json 反序列化为的对象的类型,则可以将其反序列化为 Map,例如:

    Map<String, Object> result = mapper.readValue(result, new TypeReference<Map<String,Object>>() {});
    

    【讨论】:

    • 在我的应用程序中,我实际上有可能将 json 作为字符串输入接收。我将如何处理这种情况?所以,我不能做类似mapper.writeValueAsBytes(node);
    • 您可以发布示例 json 吗?如果它没有转义双引号(即,如果它是一个有效的json 而不是json 转换为string),那么您可以使用ObjectMapper 轻松反序列化它。
    • 抱歉,看不到与我的问题相关的更新。无论如何,看起来您在反序列化时不知道对象的类型。在这种情况下,最好的办法是使用Map,我已经用一个例子更新了答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-10-31
    • 1970-01-01
    • 2012-08-09
    • 1970-01-01
    • 2019-06-23
    • 2023-03-04
    • 2014-08-02
    相关资源
    最近更新 更多