在使用Jackson的XmlMapper处理XML序列化任务时,默认的序列化配置不会自动添加XML标准声明头,这会导致生成的XML内容不符合规范,部分严格的XML解析器可能无法正常识别内容。要解决这个问题,需要对XmlMapper进行针对性的高级配置,开启声明头输出选项。

XmlMapper默认序列化行为分析
XmlMapper是Jackson库中专门用于XML序列化和反序列化的核心类,默认情况下,它序列化对象生成的XML内容只包含根元素和对应的子元素,不会包含<?xml version="1.0" encoding="UTF-8"?>这类标准声明头。我们可以先看一个默认的序列化示例:
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import java.io.IOException;
public class DefaultXmlTest {
static class User {
private String name;
private Integer age;
// 构造方法、getter、setter省略
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Integer getAge() { return age; }
public void setAge(Integer age) { this.age = age; }
}
public static void main(String[] args) throws IOException {
XmlMapper xmlMapper = new XmlMapper();
User user = new User("张三", 25);
String xmlResult = xmlMapper.writeValueAsString(user);
System.out.println(xmlResult);
}
}
运行上述代码后,输出的XML内容为<User><name>张三</name><age>25</age></User>,可以看到并没有标准声明头。
开启XML声明头的核心配置
要让XmlMapper输出包含标准声明头的XML,需要使用XmlMapper关联的XmlMapper.Builder或者配置SerializationFeature以及XML模块的相关特性。核心是需要开启WRITE_XML_DECLARATION特性,这个特性是控制是否输出XML声明头的关键开关。
配置方式一:通过Builder构建XmlMapper
在创建XmlMapper实例时,通过XmlMapper.builder()方法构建,并启用WRITE_XML_DECLARATION特性,示例代码如下:
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import java.io.IOException;
public class ConfigXmlTest {
static class User {
private String name;
private Integer age;
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Integer getAge() { return age; }
public void setAge(Integer age) { this.age = age; }
}
public static void main(String[] args) throws IOException {
// 构建XmlMapper时开启WRITE_XML_DECLARATION特性
XmlMapper xmlMapper = XmlMapper.builder()
.enable(SerializationFeature.WRITE_XML_DECLARATION)
.build();
User user = new User("李四", 30);
String xmlResult = xmlMapper.writeValueAsString(user);
System.out.println(xmlResult);
}
}
运行上述代码后,输出的XML内容会变为<?xml version="1.0" encoding="UTF-8"?><User><name>李四</name><age>30</age></User>,已经包含了标准声明头。
配置方式二:对已有XmlMapper实例配置
如果已经有一个XmlMapper实例,也可以通过enable方法直接开启对应的特性,示例代码如下:
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import java.io.IOException;
public class ExistMapperTest {
static class Product {
private String productName;
private Double price;
public Product(String productName, Double price) {
this.productName = productName;
this.price = price;
}
public String getProductName() { return productName; }
public void setProductName(String productName) { this.productName = productName; }
public Double getPrice() { return price; }
public void setPrice(Double price) { this.price = price; }
}
public static void main(String[] args) throws IOException {
XmlMapper xmlMapper = new XmlMapper();
// 对已有实例开启声明头输出特性
xmlMapper.enable(SerializationFeature.WRITE_XML_DECLARATION);
Product product = new Product("笔记本电脑", 5999.99);
String xmlResult = xmlMapper.writeValueAsString(product);
System.out.println(xmlResult);
}
}
自定义声明头参数
默认开启WRITE_XML_DECLARATION后,生成的声明头是<?xml version="1.0" encoding="UTF-8"?>,如果需要自定义编码或者其他参数,可以通过配置XmlMapper的XmlFactory来实现。比如需要设置编码为GBK,示例代码如下:
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.XmlFactory;
import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator;
import com.fasterxml.jackson.databind.SerializationFeature;
import javax.xml.stream.XMLOutputFactory;
import java.io.IOException;
public class CustomDeclTest {
static class Order {
private String orderId;
private String orderTime;
public Order(String orderId, String orderTime) {
this.orderId = orderId;
this.orderTime = orderTime;
}
public String getOrderId() { return orderId; }
public void setOrderId(String orderId) { this.orderId = orderId; }
public String getOrderTime() { return orderTime; }
public void setOrderTime(String orderTime) { this.orderTime = orderTime; }
}
public static void main(String[] args) throws IOException {
// 自定义XML输出工厂,设置编码
XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
XmlFactory xmlFactory = new XmlFactory(outputFactory, null);
XmlMapper xmlMapper = new XmlMapper(xmlFactory);
xmlMapper.enable(SerializationFeature.WRITE_XML_DECLARATION);
// 设置默认编码为GBK
xmlMapper.configure(ToXmlGenerator.Feature.WRITE_XML_DECLARATION, true);
Order order = new Order("20240501001", "2024-05-01 10:00:00");
String xmlResult = xmlMapper.writeValueAsString(order);
System.out.println(xmlResult);
}
}
常见问题排查
- 配置后仍然没有声明头:检查是否同时开启了
SerializationFeature.WRITE_XML_DECLARATION,部分旧版本的Jackson XML模块需要同时确认ToXmlGenerator的相关特性是否开启。 - 声明头编码和实际内容编码不一致:如果自定义了编码,需要确保整个序列化过程的编码统一,避免出现乱码问题。
- 依赖版本问题:确保使用的
jackson-dataformat-xml版本不低于2.9,低版本可能存在特性支持不全的问题。
总结
要让Jackson XmlMapper输出包含标准声明头的XML,核心就是开启SerializationFeature.WRITE_XML_DECLARATION特性,开发者可以根据是新建XmlMapper实例还是使用已有实例选择不同的配置方式,同时可以根据需要自定义声明头的参数。按照上述配置方式操作,就能稳定生成符合规范的XML内容,满足各类解析场景的需求。