Java8中JAXB marshaller处理surrogate pairs输出无效XML实体如何解决
JAXB序列化Unicode代理对异常问题解决
问题排查前置校验
你当前使用的码点遍历逻辑存在错误:Java中char为16位存储,Unicode代理对会占用2个char的长度,调用codePointAt(i)获取完整码点后,需要根据码点长度动态步进索引,而不是每次固定+1。请先替换为正确的遍历逻辑验证是否真的存在多余输出:
int i = 0; while (i < xmlString.length()) { int ch = xmlString.codePointAt(i); System.out.print(ch); System.out.print("|"); i += Character.charCount(ch); }
如果替换后仍输出多余的低位代理码点56499,即为Java 8内置JAXB实现的已知BUG。
问题原因
Java 8内置的JAXB版本为2.2.x,存在Unicode代理对处理缺陷,序列化时会错误地将已经合并输出的代理对低位字符单独再输出一次,导致出现非法的孤立代理码点。
解决方案
方案1:升级JAXB依赖(优先推荐)
手动引入高版本JAXB实现替换内置版本,无需修改业务代码即可修复问题,Maven依赖示例如下:
<dependencies> <dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> <version>2.3.1</version> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-core</artifactId> <version>2.3.8</version> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-impl</artifactId> <version>2.3.8</version> </dependency> </dependencies>
方案2:自定义字符串序列化适配器
如果无法升级依赖,可以通过自定义XmlAdapter过滤非法孤立代理字符:
- 实现适配器类:
import javax.xml.bind.annotation.adapters.XmlAdapter; public class SurrogateFixAdapter extends XmlAdapter<String, String> { @Override public String unmarshal(String v) { return v; } @Override public String marshal(String v) { if (v == null) return null; StringBuilder sb = new StringBuilder(); int idx = 0; while (idx < v.length()) { int codePoint = v.codePointAt(idx); // 跳过孤立的低位代理字符 if (!(Character.isLowSurrogate(v.charAt(idx)) && (idx == 0 || !Character.isHighSurrogate(v.charAt(idx -1))))) { sb.appendCodePoint(codePoint); } idx += Character.charCount(codePoint); } return sb.toString(); } }
- 在需要处理的字段上添加绑定注解:
@XmlJavaTypeAdapter(SurrogateFixAdapter.class) private String text;
内容的提问来源于stack exchange,提问作者Giron
相关产品推荐
相关产品推荐

