XStream を使うかどうかは、NULL value をどう扱うかが問題

XStream は、アノテーションによるXMLに対するJava Object のマッピング、コンバータの指定ができていいのだけど、
stackoverflow.com

ここで書かれたように NULL を 中身空のタグでXMLを書く場合に指定方法が文字列、String型でしか逃げ道がない。
stackoverflow に投稿されたように、ReflectionConverter を書き直して 配布されてる XStream ライブラリに手を加える
なんてやってられない。

日付や時刻のとき、困るだろう。

これとは論点が違う話で。。。

皆(特に日本だけ?)、なぜか、年月日の表現を、yyyy-MM-dd のハイフン区切りの書式を嫌がり、yyyy/MM/dd になってる
ことが多い。

XStream でこの書式を解決するのは、com.thoughtworks.xstream.converters.Converter 実装を用意するか
com.thoughtworks.xstream.converters.time.LocalDateConverter を継承して書式を任意に指定させるかである。


Converter 実装の例

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;

public class CustomLocalDateConverter implements Converter{
   private String format;
   public CustomLocalDateConverter(String format){
      this.format = format;
   }
   @Override
   public boolean canConvert(Class type){
      return type.equals(LocalDate.class);
   }
   @Override
   public void marshal(Object value, HierarchicalStreamWriter writer, MarshallingContext context){
      LocalDate date = (LocalDate)value;
      writer.setValue(date.format(DateTimeFormatter.ofPattern(format)));
   }
   @Override
   public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context){
      try{
         return LocalDate.parse(reader.getValue(), DateTimeFormatter.ofPattern(format));
      }catch(Exception e){
         return null;
      }
   }
}


LocalDateConverter を継承の例

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import com.thoughtworks.xstream.converters.ConversionException;
import com.thoughtworks.xstream.converters.time.LocalDateConverter;

public class CustomLocalDateConverter extends LocalDateConverter{
   private String format;
   public CustomLocalDateConverter(String format){
      this.format = format;
   }
   @Override
   public Object fromString(final String str){
      try{
         return LocalDate.parse(str, DateTimeFormatter.ofPattern(format));
      }catch(Exception e){
         final ConversionException exception = new ConversionException("Cannot parse value as local date", e);
         exception.add("value", str);
         throw exception;
      }
   }
   @Override
   public String toString(final Object obj){
      if (obj==null){
         return "";
      }
      return DateTimeFormatter.ofPattern(format).format((LocalDate)obj);
   }
}

任意のフィールドを日付のタグ、 <date> に割り当てる場合

   @XStreamAlias("date")
   @XStreamConverter(value=CustomLocalDateConverter.class, strings={"yyyy/MM/dd"})
   public LocalDate birthday;


ここで、どうしても、 この LocalDate bithday が、null の時、このままでは、<date></date> と書かれるXML
生成できないので、、、

強引なトリックを使うなら、この bithday 宣言の前に、NULL の時に XML出力時専用のフィールドを文字列で用意することだ。

   @XStreamAlias("date")
   @XStreamConverter(value=CustomLocalDateConverter.class, strings={"yyyy/MM/dd"})
   public LocalDate birthday;

   @XStreamAlias("date")
   public String writeOnlyDate = "";


@XStreamAlias を2回やってしまうのである。これがなぜかエラーにならない。
上の例では、birthday が、NULL の時、writeOnlyDate = "" が有効になって、 <date></date> が出力される。



そもそも、XML離れが進んでる傾向が強いので、久々にこれらXML系を調べたけど、
相変わらず、これ1本で。。。というフレームワーク、ツール、ライブラリが見当たらない。。。

>>>つづき、、、
oboe2uran.hatenablog.com