相信不少兄弟在使用JAXB将bean转xml时候都遇到一个问题就是当bean的某个属性没有设置值或者为null的时候,转换成xml后将不生成对应的xml节点,看到网上大部分的解决办法都是设置一个默认值空的字符串"",当然这也不失为一个解决办法,就是有点麻烦,今天我给大家介绍一个通用的解决办法在根源上处理问题不用设置默认值这么麻烦啦。
1、最初的代码是这样的
public static String parseObjectXmlData(Object obj) {
String backXml = null;
ByteArrayOutputStream baos = null;
try {
baos = new ByteArrayOutputStream();
JAXBContext jax = getContextInstance(obj.getClass());
Marshaller mar = jax.createMarshaller();
mar.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
mar.setProperty(Marshaller.JAXB_FRAGMENT, true);
mar.marshal(obj, baos);
backXml = baos.toString();
backXml = new String(baos.toByteArray(), xmlCoding);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (baos != null) {
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return backXml;
}
这段代码做一个简单的测试如下:
@Data
@XmlRootElement(name = "student")
@XmlAccessorType(XmlAccessType.NONE)
public class Student {
@XmlElement(name = "name")
private String name;
@XmlElement(name = "age")
private String age;
public static void main(String[] args) {
Student student = new Student();
student.setName("kevin");
//这边的parseObjectXmlData代码就是上面那段转换xml的方法
String s = parseObjectXmlData(student);
System.out.println(s);
}
}
果不其然出现了预期的结果:
接下来使用优化后的代码:
private static final Marshaller.Listener marListener = new Marshaller.Listener() {
@Override
public void beforeMarshal(Object source) {
Field[] fields = source.getClass().getDeclaredFields();
for (Field f : fields) {
f.setAccessible(true);
try {
//对象为空且类型为String时候设置空值
if (f.getType() == String.class && f.get(source) == null) {
f.set(source, "");
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
};
public static String parseObjectXmlData(Object obj) {
String backXml = null;
ByteArrayOutputStream baos = null;
try {
baos = new ByteArrayOutputStream();
JAXBContext jax = getContextInstance(obj.getClass());
Marshaller mar = jax.createMarshaller();
mar.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
mar.setProperty(Marshaller.JAXB_FRAGMENT, true);
//这边要单独提取出来创建一个公共的对象,不然每次解析都会创建会造成内存泄漏
mar.setListener(marListener);
mar.marshal(obj, baos);
backXml = baos.toString();
backXml = new String(baos.toByteArray(), xmlCoding);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (baos != null) {
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return backXml;
}
再次运行结果如下:
可见代码是有效的。这边呢就是对这个Marshaller对象设置了个监听内部类,然后在这个监听类实现中用反射取到每个类型为String的字段然后对其进行赋值,其实跟我们原来的赋值解决问题的办法是一样的,只是把赋值这个操作放在了监听里面不用手动为每个属性进行赋值而已。