【问题标题】:org.codehaus.jackson.JsonParseException: Invalid UTF-8 middle byte 0xdforg.codehaus.jackson.JsonParseException:无效的 UTF-8 中间字节 0xdf
【发布时间】:2013-08-11 19:34:52
【问题描述】:

我正在使用 jackson 框架在 JSON 和 Java 之间编组和解组数据。一切正常,只要输入不包含任何字符,例如:

  • ö
  • ä
  • ü
  • Ö
  • Ü
  • ß

对于我尝试过的输入数据:

String jsonData = "{\"id\":1,\"street\":\"Straße\",\"number\":\"1c\",\"zipCode\":1111,\"city\":\"MyCity\"}";

还有:

String jsonData = "{\"id\":1,\"street\":\"Stra\u00DFe\",\"number\":\"1c\",\"zipCode\":1111,\"city\":\"MyCity\"}";

而且我总是遇到同样的异常。

从json数据到java实体对象的映射是通过:

/*
 * Convert stream to data entity
 */
ObjectMapper m = new ObjectMapper();
T entity = (T) m.readValue(stringToStream(jsonData), readableClass);

我还执行了一个 json 数据验证,其工作方式与预期一样,也使用上述字符。

这些数据应该如何处理?

更新 这些是MessageBodyReader 类的重要部分

@Override
public T readFrom(Class<T> type, Type genericType,
        Annotation[] annotations, MediaType mediaType,
        MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
        throws IOException, WebApplicationException {

    final String jsonData = getStringFromInputStream(entityStream);
    System.out.println(jsonData);

    InputStream isSchema = new FileInputStream(jsonSchemaFile);
    String jsonSchema = getStringFromInputStream(isSchema);

    /*
     * Perform JSON data validation against schema
     */
    validateJsonData(jsonSchema, jsonData);

    /*
     * Convert stream to data entity
     */
    ObjectMapper m = new ObjectMapper();
    T entity = (T) m.readValue(stringToStream(jsonData), readableClass);

    return entity;
}

/**
 * Validate the given JSON data against the given JSON schema
 * 
 * @param jsonSchema
 *            as String
 * @param jsonData
 *            as String
 * @throws MessageBodyReaderValidationException
 *             in case of an error during validation process
 */
private void validateJsonData(final String jsonSchema, final String jsonData)
        throws MessageBodyReaderValidationException {
    try {
        final JsonNode d = JsonLoader.fromString(jsonData);
        final JsonNode s = JsonLoader.fromString(jsonSchema);

        final JsonSchemaFactory factory = JsonSchemaFactory.byDefault();
        JsonValidator v = factory.getValidator();

        ProcessingReport report = v.validate(s, d);
        System.out.println(report);
        if (!report.toString().contains("success")) {
            throw new MessageBodyReaderValidationException(
                    report.toString());
        }

    } catch (IOException e) {
        throw new MessageBodyReaderValidationException(
                "Failed to validate json data", e);
    } catch (ProcessingException e) {
        throw new MessageBodyReaderValidationException(
                "Failed to validate json data", e);
    }
}

/**
 * Taken from <a href=
 * "http://www.mkyong.com/java/how-to-convert-inputstream-to-string-in-java/"
 * >www.mkyong.com</a>
 * 
 * @param is
 *            {@link InputStream}
 * @return Stream content as String
 */
private String getStringFromInputStream(InputStream is) {
    BufferedReader br = null;
    StringBuilder sb = new StringBuilder();

    String line;
    try {

        br = new BufferedReader(new InputStreamReader(is));
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }

    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (br != null) {
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    return sb.toString();
}

private InputStream stringToStream(final String str) {
    return new ByteArrayInputStream(str.getBytes());
}

【问题讨论】:

标签: json jackson


【解决方案1】:

JSON 规范指出,只有 UTF-8、UTF-16 和 UTF-32 才是有效的编码。不能使用其他编码(如 Latin-1)。您的 stringToStream 实现未明确设置编码,因此使用系统默认值。这就是你获得非utf流的方式。在下一步中,Jakson 尝试使用一种 UTF 编码(它具有内置的检测算法)解析流,但失败了。尝试设置显式编码:

new ByteArrayInputStream(str.getBytes("UTF-8"));

【讨论】:

    【解决方案2】:

    您已经得到了答案,但这里有一个明显的问题:您为什么要从 String 转换为流?这是不必要和浪费的事情——所以只需按原样传递字符串。这也将消除问题;字符串本身没有编码(即:只有一个内存表示,不需要转换)。

    【讨论】:

    • 哦,谢谢!您指的是解组调用,可以简化为:T entity = (T) m.readValue(jsonData, readableClass); 是否有进一步改进?
    • 当以字符串形式读取文件时,最好使用基本的InputStreamReader,使用StringBuilder追加,而不是逐行。或者,如果 JSON Schema Validator 可以从 ReaderInputStream 读取数据,则通过这些 - 它很可能也在后台使用 Jackson。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-04
    • 2012-03-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多