目录
公共实体类
@JacksonXmlRootElement(localName = "stu")
public class Stu {
private String name;
private String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
最简单的序列化
public static void main(String[] args) throws JsonProcessingException {
XmlMapper xmlMapper = new XmlMapper();
Stu stu = new Stu();
stu.setName("学生");
stu.setAge("18");
String xml = xmlMapper.writeValueAsString(stu);
System.out.println(xml);
}
结果为
<stu><name>学生</name><age>18</age></stu>
没有xml声明?
接着往下看
添加Xml声明
public static void main(String[] args) throws JsonProcessingException {
XmlMapper xmlMapper = new XmlMapper();
//只需要这一步,设置WRITE_XML_DECLARATION为true
xmlMapper.configure(ToXmlGenerator.Feature.WRITE_XML_DECLARATION, true);
Stu stu = new Stu();
stu.setName("学生");
stu.setAge("18");
String xml = xmlMapper.writeValueAsString(stu);
System.out.println(xml);
}
结果为
<?xml version='1.0' encoding='UTF-8'?><stu><name>学生</name><age>18</age></stu>
纳尼?<?xml version='1.0' encoding='UTF-8'?>怎么是单引号?
Jackson生成xml声明源码
先看看Jackson源码,怎么生成的xml声明
看com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator
继续跟踪到com.ctc.wstx.sw.BufferingXmlWriter类
mUseDoubleQuotesInXmlDecl 字段为true时才使用双引号
mUseDoubleQuotesInXmlDecl 字段在BufferingXmlWriter的父类 com.ctc.wstx.sw.XmlWriter 中
竟然用 final 修饰?
看来只能在实例化BufferingXmlWriter对象时设置值了
与WriterConfig有关,继续向上跟踪源码到 com.ctc.wstx.stax.WstxOutputFactory 类
mConfig是在 WstxOutputFactory 类的构造器设置的,还是protected修饰
我可以写个子类,用默认构造器先调用父类构造器,再给mConfig设置值
PROP_USE_DOUBLE_QUOTES_IN_XML_DECL 的值是10,可是不是public修饰的,不过没关系。
convertToBoolean 的第一个参数竟然没用到,一会儿我们可以这么调用方法
mConfig.setProperty(null, 10, true);
具体实现后面再说。
但是,怎么让XmlMapper使用我写的类呢?看类名是个序列化工厂
先来看看WstxOutputFactory 类的继承关系
我们再看看XmlMapper类的构造器
发现了吗?可以传入 XMLOutputFactory 对象,也就是说可以传入 WstxOutputFactory 对象
再看 XmlFactory 的构造器
当 XMLInputFactory 参数为 null 时,则使用默认的 XMLInputFactory 对象,当 XMLOutputFactory 参数为 null 时,则使用默认的 XMLOutputFactory 对象。
所以我们可以使用
创建XmlMapper对象
在XML声明中使用双引号 方案一
创建 WstxOutputFactory 的子类
import com.ctc.wstx.stax.WstxOutputFactory;
public class DoubleQuotesOutputFactory extends WstxOutputFactory {
public DoubleQuotesOutputFactory() {
super();
mConfig.setProperty(null, 10, true);
}
}
创建XmlMapper对象
XmlMapper xmlMapper = new XmlMapper(null, new DoubleQuotesOutputFactory());
完整代码
public static void main(String[] args) throws JsonProcessingException {
XmlMapper xmlMapper = new XmlMapper(null, new DoubleQuotesOutputFactory());
//只需要这一步,设置WRITE_XML_DECLARATION为true
xmlMapper.configure(ToXmlGenerator.Feature.WRITE_XML_DECLARATION, true);
Stu stu = new Stu();
stu.setName("学生");
stu.setAge("18");
String xml = xmlMapper.writeValueAsString(stu);
System.out.println(xml);
}
结果为
<?xml version="1.0" encoding="UTF-8"?><stu><name>学生</name><age>18</age></stu>
优化 WstxOutputFactory 的子类
在 WstxOutputFactory 类中有个方法
向下跟踪源码
关键的一步是 findPropertyId(propName)
继续跟踪进 WriterConfig 类
P_USE_DOUBLE_QUOTES_IN_XML_DECL 是 public 修饰的
PROP_USE_DOUBLE_QUOTES_IN_XML_DECL 的值就是10
所以 WstxOutputFactory 的子类可以优化为下面的代码
import com.ctc.wstx.api.WstxOutputProperties;
import com.ctc.wstx.stax.WstxOutputFactory;
public class DoubleQuotesOutputFactory extends WstxOutputFactory {
public DoubleQuotesOutputFactory() {
super();
this.setProperty(WstxOutputProperties.P_USE_DOUBLE_QUOTES_IN_XML_DECL, true);
}
}
运行结果仍然为
<?xml version="1.0" encoding="UTF-8"?><stu><name>学生</name><age>18</age></stu>
在XML声明中使用双引号 方案二
不多说了,上代码
public static void main(String[] args) throws JsonProcessingException {
XmlMapper xmlMapper = new XmlMapper();
XmlFactory factory = xmlMapper.getFactory();
XMLOutputFactory xmlOutputFactory = factory.getXMLOutputFactory();
xmlOutputFactory.setProperty(WstxOutputProperties.P_USE_DOUBLE_QUOTES_IN_XML_DECL, true);
//只需要这一步,设置WRITE_XML_DECLARATION为true
xmlMapper.configure(ToXmlGenerator.Feature.WRITE_XML_DECLARATION, true);
Stu stu = new Stu();
stu.setName("学生");
stu.setAge("18");
String xml = xmlMapper.writeValueAsString(stu);
System.out.println(xml);
}