将json源转换为java对象

时间:2017-03-23 09:26:07

标签: java json

我有一个网址(https://),其中包含json数据,但它有一个针对被叫JSON highjacking exploit的保护我认为因为源代码开头于: )]}', 而来源就像:

  [
  {
    "address": {
        "street": "Neuenfelder Str",
        "housenumber": "13A",
        "postalcode": "21109",
        "city": "Hamburg",
        "geoLocation": {
            "lat": "52.092309",
            "lng": "5.130041"
        }
    },
    "distance": 0
  },
  {
    "address": {
        "street": "Umber Str",
        "housenumber": "2",
        "postalcode": "22567",
        "city": "Berlin",
        "geoLocation": {
            "lat": "51.5761166",
            "lng": "5.0377286"
        }
    },
    "distance": 0
  },
  .....]

我尝试使用Jacksongson甚至org.json来创建客户端代码并使用此json,但我得到了解析错误:

  

无法读取文档:意外字符(')'(代码41)):   期望一个有效的值(数字,字符串,数组,对象,'真','假'   或'null')

我可以将json转换为Java对象,方法是保存为文件并删除这些字符)]}'

但是我需要知道有没有办法将此源转换为我们正常的方式而不保存为文档并只使用这些库(ObjectMapperResponseEntity)。

1 个答案:

答案 0 :(得分:1)

您提到的所有主要JSON库都没有提供任何解析您正在讨论的JSON文档的方法:它们只能使用格式良好的 JSON文档,没有别的,以及那些唯一的,合理的是他们的责任。您提到的文档不是有效的JSON,因此这就是为什么所有这些文档都无法解析它的唯一原因。但是,您在问题中提到的所有库都透明地使用Reader,并且刚刚删除了这五个字符,您可以修复损坏的JSON文档(以及它为JSON标准或任何JSON工具而破解,因此任何这些库都可以使用它。请注意,您不需要特殊的"任何类型的库(好吧,让我们假设这样的库存在,但如果它缺少你可以用你最喜欢的JSON库的任何功能,那会让你伤心吗?),因为你可以让它工作任何。性能说明:您不需要使用字符串来节省内存并且也能够处理大量JSON文档。

考虑以下" JSON"文件:

)]}',{"foo":"bar"}

知道前五个字符阻止任何JSON解析器解析它,你可以很容易地剥离它们:

private static final char[] protectingCharacters = {
        ')', ']', '}', '\'', ','
};

static Reader stripProtection(final Reader reader)
        throws IOException {
    // Allocating a temporary buffer
    final char[] buffer = new char[protectingCharacters.length];
    // Check if the given Reader instance supports reading ahead, and wrap if necessary
    // This is necessary in order to restore the reader position
    final Reader normalizedReader = reader.markSupported() ? reader : new BufferedReader(reader);
    // Memorizing the current position telling the reader to limit its internal buffer size just with five characters
    normalizedReader.mark(protectingCharacters.length);
    // Reading five characters to the buffer
    // We don't need to check how many characters were read -- we'll check it below
    normalizedReader.read(buffer, 0, protectingCharacters.length);
    // Not a protecting mark?
    if ( !Arrays.equals(protectingCharacters, buffer) ) {
        // Then just rewind the reader pointer to the position stored with the mark() invocation
        normalizedReader.reset();
    }
    // Or assume that skipping five characters is fine
    return normalizedReader;
}

以下示例使用stripProtection方法为Gson,Jackson和org.json库解析给定的输入流,以简化创建各自的JSON树模型:

static void testWithGson()
        throws IOException {
    try ( final Reader reader = stripProtection(getPackageResourceReader(Q42971905.class, "no-hijacking.json")) ) {
        final JsonParser parser = new JsonParser();
        final JsonElement jsonElement = parser.parse(reader);
        System.out.println(jsonElement);
    }
}

static void testWithJackson()
        throws IOException {
    try ( final Reader reader = stripProtection(getPackageResourceReader(Q42971905.class, "no-hijacking.json")) ) {
        final ObjectMapper objectMapper = new ObjectMapper();
        final JsonNode jsonNode = objectMapper.readTree(reader);
        System.out.println(jsonNode);
    }
}

static void testWithOrgJson()
        throws IOException {
    try ( final Reader reader = stripProtection(getPackageResourceReader(Q42971905.class, "no-hijacking.json")) ) {
        final JSONTokener jsonTokener = new JSONTokener(reader);
        final Object value = jsonTokener.nextValue();
        System.out.println(value);
    }
}

所有三种方法都产生以下输出:

  

{"富":"杆"}

如果由于某种原因,您需要生成此类文档,则只需编写如下方法:

static Writer coverWithProtection(final Writer writer)
        throws IOException {
    writer.write(protectingCharacters);
    return writer;
}

将作者传递给您正在使用的相应JSON库。此方法将使用)]}',前缀编写器输出。