newfactory() 在 java 8u291+ 和 java 11+ 中常返回 null 或抛 npe,因 jaxp 默认查找机制失效且 jdk 移除了内置 stax 实现;应手动指定 woodstox 工厂类并添加对应依赖。

newFactory() 为什么总返回 null 或抛 NPE
直接调用 XMLOutputFactory.newFactory() 在某些 JDK 版本(尤其是 Java 8u291+ 和 Java 11+)下会返回 null,或者后续调用 createXMLStreamWriter() 时抛 NullPointerException。这不是你代码写错了,而是 JAXP 默认查找机制失效了——它找不到可用的 StAX 实现。
- Java 9+ 移除了内置的
com.sun.xml.internal.stream.XMLOutputFactoryImpl,而 OpenJDK 默认不带任何第三方 StAX 实现 - 如果你没在 classpath 里显式引入
stax-api+stax2-api或woodstox-core,newFactory()就只能干瞪眼 - 别依赖系统属性
javax.xml.stream.XMLOutputFactory自动加载:它在模块化环境下大概率被忽略
怎么安全创建 XMLOutputFactory 实例
绕过自动发现,手动指定实现类最稳。推荐用 Woodstox(性能好、兼容强、 actively maintained),避免用已废弃的 stax-api 参考实现。
- Maven 加依赖:
<dependency> <groupId>com.fasterxml.woodstox</groupId> <artifactId>woodstox-core</artifactId> <version>6.5.1</version> </dependency>
- 创建工厂:
XMLOutputFactory factory = XMLOutputFactory.newInstance( "com.fasterxml.woodstox.stax.WoodstaxOutputFactory", null); - 或者更保守一点,捕获异常后 fallback:
try { factory = XMLOutputFactory.newInstance(); } catch (Exception e) { factory = new com.fasterxml.woodstox.stax.WoodstaxOutputFactory(); }
setPropertyValue() 配置项哪些真有用
StAX 工厂支持一堆 setProperty(),但多数只是摆设。真正影响输出行为且跨实现稳定的只有几个:
-
javax.xml.stream.isRepairingNamespaces:设为true可自动补xmlns声明,避免手动处理前缀冲突 -
javax.xml.stream.supportDTD:设为false(默认)可禁用 DTD 解析,防止 XXE;设为true仅当你要写带 DTD 的老格式 XML -
com.fasterxml.woodstox.outputEscapeCr(Woodstox 专属):控制是否把\r转成,默认false,一般不用动 - 别碰
javax.xml.stream.isNamespaceAware—— 它对XMLOutputFactory无效,只作用于XMLInputFactory
写入时中文乱码或换行丢失
不是编码问题,是 XMLStreamWriter 默认不写 XML 声明,也不保证换行。生成的 XML 看起来“挤在一起”,甚至 IDE 打开显示乱码,其实是缺少 <?xml version="1.0" encoding="UTF-8"?> 声明 + 没启用缩进。
立即学习“Java免费学习笔记(深入)”;
- 必须手动写声明:
writer.writeStartDocument("UTF-8", "1.0"); - Woodstox 支持缩进,但得显式开启:
factory.setProperty("org.codehaus.stax2.automaticEmptyElements", true); factory.setProperty("org.codehaus.stax2.formatting", true); // 启用格式化 - 注意:缩进只对
writeStartElement()/writeEndElement()生效,writeCharacters()的空白不会被美化——别指望它自动排版文本内容
StAX 写入的核心矛盾在于:工厂实例的获取高度依赖运行时环境,而一旦配错,错误往往延迟到第一次写入才爆发。最保险的做法不是查文档,是把 Woodstox 实现类名硬编码进 newInstance(),再加一层 try/catch fallback。其他配置都是锦上添花,先让 writeStartDocument() 不崩再说。










