- 在使用jaxb从bean转换为xml过程中,默认会将bean中属性为null的属性过滤掉,如下:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "person")
public class Person {
private String name;
private String address;
//getter, setter
}
执行如下代码:
Person person = new Person();
person.setName("Tom");
JAXBContext context = JAXBContext.newInstance(Person.getClass());
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
StringWriter result = new StringWriter();
marshaller.marshal(person, result);
此时result内容为:
<person>
<name>Tom</name>
</person>
因address为null,jaxb在处理生成xml过程中将<address>元素过滤掉,但此时如果业务需求需要生成一个空的<address></address>则可以通过变通为marshaller对象在marshal前添加监听器,在监听器中通过反射的方式对bean中属性为null的字段赋默认值的方式解决该问题,如字段类型为String的可以对该字段赋空字符串:
marshaller.setListener(new MarshallerListener());
StringWriter result = new StringWriter();
marshaller.marshal(person, result);
MarshallerListener中代码如下:
import com.xinyuan.haze.common.utils.HazeStringUtils;
import com.xinyuan.tender.entity.XmlChoiceFilter;
import javax.xml.bind.Marshaller;
import java.lang.reflect.Field;
/**
* 该监听器主要用来解决jaxb无法渲染字段为null的属性.
* <p>
* 在将Java类转换为xml片段时,默认jaxb会过滤属性值为null的属性,通过该监听器的{@link #beforeMarshal(Object)}方法,在渲染前
* 通过将属性赋值为空字符串来达到在生成的xml片段中包含该属性的功能.
* </p>
* <p>
* <strong>注意:</strong>默认处理{@link String}类型的字段.
* </p>
*/
public class MarshallerListener extends Marshaller.Listener {
public static final String BLANK_CHAR = "";
@Override
public void beforeMarshal(Object source) {
super.beforeMarshal(source);
Field[] fields = source.getClass().getDeclaredFields();
for (Field f : fields) {
f.setAccessible(true);
//获取字段上注解<pre name="code" class="java">
try {
if (f.getType() == String.class && f.get(source) == null) {
f.set(source, BLANK_CHAR);
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
添加上述代码后生成过的result如下:
<person>
<name>Tom</name>
<address></address>
</person>
注意:该解决方案使用反射,动态改变了对象运行时属性状态如:
f.setAccessible(true);
故该解决方案不是最佳,因暂未找到其它好的方案所以采用该途径处理.