非Spring、非SpringBoot 環境で、YAMLを読む - Oboe吹きプログラマの黙示録
を書いたので、今度はJava オブジェクトから、YAML テキストを snakeyaml で出力します。
Yaml yaml = new Yaml();
基本、Yamlインスタンス作って、dumpメソッドで出力するのですが、
String res = yaml.dump(sample);
どうも、これだと、結果テキストの先頭に、"!!"の2文字に続けて、sample のクラス名の1行が先頭に
出力される。
さらに、YAML形式といっても、リストは1行で収まる書式にされている。
ダンプ例)
!!org.aaa.dto.Sample address: clist: [21, 22, 23] group: {info1: A, info2: B} ate: {date: 2020/09/21, datetime: '2020/09/22 11:09:22'}
snakeyaml では、Java オブジェクトから YAML 生成を目的にはしていないんじゃないかと思われる。
YAML書式になるようにダンプするなら、dumpAs メソッドでオプション指定で出力する。
dumpAs( object, org.yaml.snakeyaml.nodes.Tag , DumperOptions.FlowStyle )
ということらしい。
2番目の引数を、Tag.YAML として実行すると、
先頭の行が、"!!yaml" として出力される。
String res = yaml.dumpAs(sample, Tag.YAML, DumperOptions.FlowStyle.BLOCK);
Tag.YAML の代わりに、null を指定すれば、"!!"の2文字に続けて、sample のクラス名になる。
FlowStyle.BLOCK を指定すれば、見慣れたYAML書式が出力される。
!!yaml address: clist: - 21 - 22 - 23 group: info1: A info2: B ate: date: 2020/09/21 datetime: 2020/09/22 11:09:22
どうも、この 先頭行 "!!" 出力させない方法がわからない!
日付、時刻を出力でも java.time.* では、書く必要があり、
非Spring、非SpringBoot 環境で、YAMLを読む - Oboe吹きプログラマの黙示録
と同様、出力用の変換クラスが必要である。
Yaml のコンストラクタ
public Yaml(BaseConstructor constructor, Representer representer)
を使用すれば、YAML読込みも、出力も使用できる Yamlインスタンスになる。
この Representer representer として、java.time の LocalDate と LocalDateTime 変換用を用意すれば良い。
import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import org.yaml.snakeyaml.nodes.Node; import org.yaml.snakeyaml.nodes.Tag; import org.yaml.snakeyaml.representer.Representer; public class LocalDateRepresenter extends Representer{ private DateTimeFormatter dateformatter; private DateTimeFormatter datetimeformatter; private Tag dateTag; private Tag datetimeTag; public LocalDateRepresenter(){ dateTag = Tag.TIMESTAMP; datetimeTag = Tag.TIMESTAMP; dateformatter = DateTimeFormatter.ISO_LOCAL_DATE; datetimeformatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME; multiRepresenters.put(LocalDate.class, new RepresentLocalDate()); multiRepresenters.put(LocalDateTime.class, new RepresentLocalDateTime()); } public LocalDateRepresenter addLocalDateTimeFormat(String format) { this.datetimeformatter = DateTimeFormatter.ofPattern(format); this.datetimeTag = Tag.STR; return this; } public LocalDateRepresenter addLocalDateFormat(String format) { this.dateformatter = DateTimeFormatter.ofPattern(format); this.dateTag = Tag.STR; return this; } private class RepresentLocalDate extends RepresentDate { @Override public Node representData(Object obj){ LocalDate localDateTime = (LocalDate)obj; String date = localDateTime.format(dateformatter); return representScalar(getTag(obj.getClass(), dateTag), date); } } private class RepresentLocalDateTime extends RepresentDate { @Override public Node representData(Object obj){ LocalDateTime localDateTime = (LocalDateTime)obj; String date = localDateTime.format(datetimeformatter); return representScalar(getTag(obj.getClass(), datetimeTag), date); } } }
ここで注目すべきは、multiRepresenters に、class と、private 定義した RepresentDate 継承クラスを
追加していくことであり、1つの Representer で、複数の型についての
変換仕様を登録できることである。
public interface Represent インターフェースで、
org.yaml.snakeyaml.nodes.Node を返すことを約束したものを定義していく。