XStream null value を出力させるケース、修正

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アノテーションで書いたコンバータが使用される。