XStream null value を出力させるケース、先日の
XStream を使うかどうかは、NULL value をどう扱うかが問題 - Oboe吹きプログラマの黙示録
の方法は、やはり良くない!!
書込み専用になってしまうからである。やはり、ReflectionConverterを継承して doMarshal を null 対応したものを
XStream の registerConverter メソッドで登録するしかない。
そこで、以下の CustomReflectionConverter を用意する。
import java.util.function.BiConsumer; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.reflection.ReflectionConverter; import com.thoughtworks.xstream.converters.reflection.ReflectionProvider; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.mapper.Mapper; /** * CustomReflectionConverter */ public class CustomReflectionConverter extends ReflectionConverter{ private BiConsumer<Object, HierarchicalStreamWriter> consumer; public CustomReflectionConverter(Mapper mapper, ReflectionProvider reflectionProvider , BiConsumer<Object, HierarchicalStreamWriter> onMarchall){ super(mapper, reflectionProvider); consumer = onMarchall; } protected void doMarshal(final Object source, final HierarchicalStreamWriter writer , final MarshallingContext context) { super.doMarshal(source, writer, context); consumer.accept(source, writer); } }
XStream を使うかどうかは、NULL value をどう扱うかが問題 - Oboe吹きプログラマの黙示録 で書いたように、
XML出力時専用のフィールドを文字列で用意なんてしない!!
public class Root{ @XStreamAlias("date") @XStreamConverter(value=CustomLocalDateConverter.class, strings={"yyyy/MM/dd"}) public LocalDate birthday; : :
このCustomReflectionConverter を registerConverterで指定する。
XStream stream = new XStream(new DomDriver("UTF-8")); CustomReflectionConverter reflectionConverter = new CustomReflectionConverter(stream.getMapper(), new SunUnsafeReflectionProvider(), (o, w)->{ if (o instanceof Root){ if (((Root)o).date==null){ w.startNode("date"); w.setValue(""); w.endNode(); } } }); stream.registerConverter(reflectionConverter, XStream.PRIORITY_VERY_LOW); stream.processAnnotations(Root.class); try(OutputStream out = new FileOutputStream(new File("out.xml"))){ out.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n".getBytes()); stream.toXML(root, out); }catch(Exception e){ e.printStackTrace(); }finally{ System.out.println("finish!"); }
Root の date が null の場合、Rootタグの最後になってしまうが、、
<?xml version="1.0" encoding="UTF-8"?> <root> : <date></date> </root>
が作れる。null でない場合は、@XStreamConverterアノテーションで書いたコンバータが使用される。