【问题标题】:Jackson stops reading input string after first closing curly bracket杰克逊在第一次关闭大括号后停止读取输入字符串
【发布时间】:2016-10-19 22:41:54
【问题描述】:

我有一些代码需要一个字节数组。这些字节在转换为字符串时应该是有效的 JSON 字符串。如果不是,它将使用“Uknown”作为键将字符串转换为有效的 JSON。

除了我发现的一个边缘情况外,它工作正常。如果我向它传递一个包含多个有效 JSON 字符串的字符串,它只会解析第一个字符串并认为它是有效的 JSON。我宁愿它评估整个字符串并确定它不是有效的 JSON,因为它是 2 个或更多单独的有效 JSON 字符串。然后,它会将单独的 JSON 字符串转换为一个有效的 JSON 字符串,就像它对任何其他不是有效 JSON 的字符串所做的那样。

我使用的是 Jackson 2.8.1。

下面是一个演示问题的小应用程序。任何帮助将不胜感激。

import java.io.IOException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;

public class EnsureValidJSON {

  private static ObjectMapper objectMapper = new ObjectMapper();

  public static void main(String[] args) {

    String input = "{\"Message1\" : \"This is the first message\"}{\"Message2\" : \"This is the second message.\"}";
    System.out.println("input: " + input);

    byte[] msg = input.getBytes();
    try {
      msg = ensureMsgIsValidJson(msg);
    } catch (IOException e) {
      // Default to Unknown:Unknown
      msg = "{\"Unknown\" : \"Unknown\"}".getBytes();
    }

    System.out.println("output: " + new String(msg));
  }

  private static boolean isJSONValid(byte[] msg) {
    boolean isValid = false;
    try {
      JsonNode jsonNode = objectMapper.readTree(msg);

      // Print out the field names and their values to show that it is only parsing the first Json String.
      Iterator<String> itr = jsonNode.fieldNames();
      while (itr.hasNext()) {
        String fieldName = itr.next();
        System.out.print(fieldName + ": ");
        System.out.println(jsonNode.get(fieldName));
      }
      isValid = true;
    } catch (IOException e) {
      String err = String.format("%s is an invalid JSON message. We will attempt to make the message valid JSON. Its key will be 'Unknown'.", new String(msg));
      System.out.println(err);
    }

    return isValid;
  }

  private static byte[] ensureMsgIsValidJson(byte[] msg) throws IOException {
    if (isJSONValid(msg)) {
      return msg;
    }
    return createValidJSON(msg);

  }

  private static byte[] createValidJSON(byte[] msg) throws IOException {
    JsonFactory factory = new JsonFactory();
    try (OutputStream out = new ByteArrayOutputStream()) {
      JsonGenerator generator = factory.createGenerator(out);
      generator.writeBinary(msg);

      JsonNodeFactory nodeFactory = new JsonNodeFactory(false);
      ObjectNode validated = nodeFactory.objectNode();
      objectMapper.writeTree(generator, validated);
      validated.put("Unknown", new String(msg));
      byte[] validatedBytes = objectMapper.writeValueAsBytes(validated);
      String message = String.format("Message(%s) was successfully converted to a valid JSON message: %s", new String(msg), new String(validatedBytes));
      System.out.println(message);
      return validatedBytes;
    }
  }

}

【问题讨论】:

    标签: java json jackson


    【解决方案1】:

    我不得不使用 jackson JsonParser 对象来计算打开和关闭大括号的数量。如果计数为 0 并且字符串中没有任何内容,则它只有一个 JSON 字符串。我还必须添加代码来检查值是否为数字,因为如果值计算为数字,ObjectMapper 的 readTree 方法不会抛出 IOException。

    我想编写更多代码来完成这项工作,但它确实有效:

    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.util.Scanner;
    
    import com.fasterxml.jackson.core.JsonFactory;
    import com.fasterxml.jackson.core.JsonGenerator;
    import com.fasterxml.jackson.core.JsonParser;
    import com.fasterxml.jackson.core.JsonToken;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.node.JsonNodeFactory;
    import com.fasterxml.jackson.databind.node.ObjectNode;
    
    public class EnsureValidJSON {
    
      private static ObjectMapper objectMapper = new ObjectMapper();
    
      public static void main(String[] args) {
        if (args.length == 0) {
          System.err.println("You must pass at least one String to be validated.");
        } else {
    
          for (String arg : args) {
            System.out.println("input: " + arg);
            byte[] msg = arg.getBytes();
            try {
              msg = ensureMsgIsValidJson(msg);
            } catch (IOException e) {
              msg = "{\"Unknown\" : \"Unknown\"}".getBytes();
            }
            System.out.println("output: " + new String(msg));
          }
        }
      }
    
      private static boolean isJSONValid(byte[] msg) {
        return isJSONFormat(msg) && isJSONOneMessage(msg);
      }
    
      private static boolean isJSONFormat(byte[] msg) {
        boolean isValid = false;
        String rawString = new String(msg).trim();
        try (Scanner sc = new Scanner(rawString)) {
          objectMapper.readTree(msg);
          // If the value evaluates to a number, objectMapper.readTree will not throw an Exception, so check that here.
          if (sc.hasNextLong() || sc.hasNextDouble()) {
            String err = String.format("%s is an invalid JSON message because it is numeric.", rawString);
            System.out.println(err);
          } else {
            isValid = true;
          }
        } catch (IOException e) {
          String err = String.format("%s is an invalid JSON message. We will attempt to make the message valid JSON. Its key will be 'Unknown'.", rawString);
          System.out.println(err);
        }
    
        return isValid;
      }
    
      private static boolean isJSONOneMessage(byte[] msg) {
        boolean isValid = false;
        try {
          JsonParser parser = objectMapper.getFactory().createParser(msg);
          JsonToken token;
          // balance will increment with each opening curly bracket and decrement with each closing curly bracket. We'll use this to ensure that this is only one JSON message.
          int balance = 0;
          while ((token = parser.nextToken()) != null) {
            if (token.isStructStart()) {
              balance++;
            } else if (token.isStructEnd()) {
              balance--;
            }
            if (balance == 0) {
              break;
            }
          }
          isValid = parser.nextToken() == null;
        } catch (IOException e) {
          String err = String.format("'%s' is an invalid JSON message due to the following error: '%s'. We will attempt to make the message valid JSON. Its key will be 'Unknown'.", new String(msg),
              e.getMessage());
          System.out.println(err);
        }
    
        return isValid;
      }
    
      private static byte[] ensureMsgIsValidJson(byte[] msg) throws IOException {
        return isJSONValid(msg) ? msg : createValidJSON(msg);
      }
    
      private static byte[] createValidJSON(byte[] msg) throws IOException {
        JsonFactory factory = new JsonFactory();
        try (OutputStream out = new ByteArrayOutputStream()) {
          JsonGenerator generator = factory.createGenerator(out);
          generator.writeBinary(msg);
    
          JsonNodeFactory nodeFactory = new JsonNodeFactory(false);
          ObjectNode validated = nodeFactory.objectNode();
          objectMapper.writeTree(generator, validated);
          validated.put("Unknown", new String(msg));
          byte[] validatedBytes = objectMapper.writeValueAsBytes(validated);
          String message = String.format("Message(%s) was successfully converted to a valid JSON message: %s", new String(msg), new String(validatedBytes));
          System.out.println(message);
          return validatedBytes;
        }
      }
    
    }
    

    【讨论】:

      猜你喜欢
      • 2019-08-19
      • 1970-01-01
      • 2021-04-01
      • 2015-07-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多