XStream默认省略类名和字段名以实现简洁XML,需用alias()设别名、autodetectAnnotations()启注解、setMode()配processAnnotations()保留类型信息。

为什么 XStream 序列化出来的 XML 没有类名或字段名?
默认情况下,XStream 会省略类型信息和冗余标签,比如把 User 对象直接序列化成 <name>Alice</name><age>30</age>,而不是带根元素 <User>...</User>。这不是 bug,是它“简洁模式”的默认行为。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 用
xstream.alias("user", User.class)给类起别名,让根元素变成<user> - 调用
xstream.autodetectAnnotations(true)启用注解支持(但注意:它不自动处理@XStreamAlias,得手动注册) - 如果必须保留完整类型路径,加
xstream.setMode(XStream.NO_REFERENCES)并配合xstream.processAnnotations(User.class)
XStream 反序列化时抛出 ConversionException 怎么办?
最常见原因是字段类型不匹配或 XML 中多/少了一个节点,比如 Java 字段是 int,XML 里传了空字符串或 null;或者用了 java.time.LocalDate 但没注册对应转换器。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 检查错误堆栈里具体哪一行、哪个字段失败,定位到
com.thoughtworks.xstream.converters.ConversionException的 message - 对非基础类型(如
LocalDateTime、BigDecimal)必须显式注册转换器:xstream.registerConverter(new LocalDateTimeConverter()) - 避免直接反序列化不可信的 XML ——
XStream默认不限制类加载,存在反序列化漏洞,务必调用xstream.allowTypesByWildcard(new String[]{"com.myapp.**"})
Java 17+ 下 XStream 报 java.lang.ClassNotFoundException: sun.reflect.ReflectionFactory
这是 JDK 17 移除了 sun.* 包导致的,XStream < 1.4.20 依赖内部 API 做反射操作,运行时直接崩。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 升级到
XStream 1.4.20或更高(目前最新是1.4.21),它已切换为使用java.lang.invoke替代sun.reflect - 如果卡在旧版本无法升级,临时方案是加 JVM 参数:
--add-opens java.base/sun.reflect=ALL-UNNAMED(仅限测试环境) - Maven 里确认排除掉旧版传递依赖:
<exclusion><groupId>com.thoughtworks.xstream</groupId><artifactId>xstream</artifactId></exclusion>
怎么让 XStream 忽略某个字段,又不加注解?
不是所有场景都能改源码加 @XStreamOmitField,比如用的是第三方 jar 里的类,或者字段是 transient 但依然被序列化出来了。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 用
xstream.omitField(User.class, "password")显式忽略字段(字段名必须拼写完全一致) - 如果字段是继承来的,得指定定义它的那个父类,不能只写子类
- 注意:
omitField不影响已注册的转换器逻辑,如果该字段有自定义Converter,还得一并移除,否则可能报 NPE
真正麻烦的不是怎么写几行序列化代码,而是当 XML 结构要和老系统对齐、字段命名要驼峰转中划线、还夹着 CDATA 块的时候,XStream 的转换器链很容易漏掉一层配置。这时候别硬调,先打印 xstream.getMapper() 看实际映射规则,比猜快得多。






