【问题标题】:JAXB & UTF-8 Unmarshal exception "Invalid byte 2 of 2-byte UTF-8 sequence"JAXB 和 UTF-8 解组异常“2 字节 UTF-8 序列的字节 2 无效”
【发布时间】:2013-08-14 03:00:33
【问题描述】:

我读过一些 SO 答案,说 JAXB 有一个错误,它归咎于 XML 的性质,导致它不能与 UTF-8 一起使用。我的问题是,那么解决方法是什么?我可能会得到用户输入的 unicode 字符,将其复制并粘贴到我需要在其他地方保存、编组、解组和重新显示的数据字段中。

(更新) 更多背景:

Candidate c = new Candidate();
c.addSubstitution("3 4ths", "\u00BE");
c.addSubstitution("n with tilde", "\u00F1");
    c.addSubstitution("schwa", "\u018F");
    c.addSubstitution("Sigma", "\u03A3");
    c.addSubstitution("Cyrillic Th", "\u040B");     
    jc = JAXBContext.newInstance(Candidate.class);
    Marshaller marshaller = jc.createMarshaller();
    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
    ByteArrayOutputStream os = new ByteArrayOutputStream();
    marshaller.marshal(c, os);
    String xml = os.toString();
    System.out.println(xml);    
    jc = JAXBContext.newInstance(Candidate.class);
    Unmarshaller jaxb = jc.createUnmarshaller();
    ByteArrayInputStream is = new ByteArrayInputStream(xml.getBytes());
    Candidate newCandidate = (Candidate) jaxb.unmarshal(is);
    for(Substitution s:c.getSubstitutions()) {
        System.out.println(s.getSubstitutionName() + "='" + s.getSubstitutionValue() + "'");
    }

这是我拼凑的一个小测试。我得到的确切字符并不完全在我的控制之下。用户可以将带有波浪号的 N 粘贴到该字段或其他任何内容中。

【问题讨论】:

  • 您应该提供更多背景信息 - 您到底在做什么?你有一个简短但完整的例子来说明这个问题吗?哪些字符会导致问题?
  • @JonSkeet 更新了更多上下文。上面的例子会例外。
  • Candidate 对象是我们的一个带有一些相当普通的 JAXB 注释的 bean。它工作正常,直到 unicode 字符。
  • “XML 的特性导致它无法与 UTF-8 一起使用” -- 只要 XML 都是 UTF-8,它就可以与 UTF-8 一起正常工作。显然,在您的数据流中的某个时刻,一个非 UTF-8 字节序列被插入到您的数据中。可能用户将 Windows-1252 字符粘贴到输入字段中,并且该数据未编码为 UTF-8。

标签: java xml unicode jaxb


【解决方案1】:

这是您的测试代码中的问题:

ByteArrayInputStream is = new ByteArrayInputStream(xml.getBytes());

您正在使用平台默认编码将字符串转换为字节数组。 不要这样做。您已指定要使用 UTF-8,因此在创建字节数组时必须这样做:

ByteArrayInputStream is = new ByteArrayInputStream(xml.getBytes("UTF-8"));

同样不要使用ByteArrayOutputStream.toString(),它再次使用平台默认编码。实际上,您根本不需要将输出转换为字符串:

ByteArrayOutputStream os = new ByteArrayOutputStream();
marshaller.marshal(c, os);
byte[] xml = os.toByteArray();
jc = JAXBContext.newInstance(Candidate.class);
Unmarshaller jaxb = jc.createUnmarshaller();
ByteArrayInputStream is = new ByteArrayInputStream(xml);

这对于您使用的字符应该没有问题 - 它仍然存在无法在 XML 1.0 中表示的问题(U+0020 以下的字符,\r、\n 和 \t 除外)仅此而已。

【讨论】:

    猜你喜欢
    • 2011-01-26
    • 2012-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-15
    • 1970-01-01
    • 2018-12-10
    • 1970-01-01
    相关资源
    最近更新 更多