LoginSignup
1
3

More than 5 years have passed since last update.

ハッシュのハッシュになっているyamlをsnakeyamlで読み込む時のサンプルソース

Last updated at Posted at 2016-10-26

やりたいこと

  • こういうYAMLをsnakeyamlで読み込みたい。ハッシュのハッシュのかたち。
personData.yaml
yamada:
  id: 100
  address: 東京
  age: 20
tanaka:
  id: 101
  address: さいたま
  age: 22

実現の条件

  • キャストはしたくない。
  • @SuppressWarnings("unchecked") なんてやりたくない。
  • なるべくソースを書きたくない。
  • Yaml.loadAs()とかをうまく使ってなるべく楽したい。

適用の検討

ハッシュなのでjava.util.MapYaml.loadAs()したとする。これだと型パラメータを指定できないのでキャストとか面倒事が増える。

Yaml y = new Yaml();
Map<?, ?> personMap = y.loadAs(PersonDataYamlTest.class.getResourceAsStream("/personMap.yaml"), Map.class);

こんなpersonMapは使いたくない。しかし、型パラメータを直接指定するようなAPIはなさそうなので、別のやり方をとる。

妥協案的に、yamlを以下の形式に変える。

personData2.yaml
personData :
  yamada:
    id: 100
    address: 東京
    age: 20
  tanaka:
    id: 101
    address: さいたま
    age: 22

読み込むコード

PersonDataYaml.java
package testsnakeyaml;

import org.yaml.snakeyaml.TypeDescription;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;

import java.util.Map;

public class PersonDataYaml {
  public Map<String, Person> personData;

  static PersonDataYaml loadSetting(String file) {
    Constructor constructor = new Constructor(PersonDataYaml.class);
    TypeDescription desc = new TypeDescription(PersonDataYaml.class);
    desc.putMapPropertyType("personData", String.class, Person.class);
    constructor.addTypeDescription(desc);
    Yaml y = new Yaml(constructor);
    return y.loadAs(PersonDataYaml.class.getResourceAsStream(file), PersonDataYaml.class);
  }

  static class Person {
    public int id;
    public String address;
    public int age;
  }
}

テストコード

PersonDataYamlTest.java
package testsnakeyaml;

import org.junit.jupiter.api.Test;
import org.yaml.snakeyaml.Yaml;

import java.util.Map;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class PersonDataYamlTest {
  @Test
  void testRawMap() {
    Yaml y = new Yaml();
    Map<?, ?> personMap = y.loadAs(PersonDataYamlTest.class.getResourceAsStream("/personData.yaml"), Map.class);

    assertTrue(personMap.values().iterator().next() instanceof Map);
  }

  @Test
  void testBean() {
    PersonDataYaml yaml = PersonDataYaml.loadSetting("/personData2.yaml");
    assertEquals(100, yaml.personData.get("yamada").id);
    assertEquals("東京", yaml.personData.get("yamada").address);
    assertEquals("さいたま", yaml.personData.get("tanaka").address);
  }
}

考えたこと

  • 読み込むYAML全体を、PersonDataYaml.javaとし、personDataなるフィールドに型がつけられたMapを保持させる。
    • 階層が1個増えたが妥協なので我慢。
  • ハッシュのキーは、JavaBeansの仕様に合わせる必要があるようなので、ここでは簡単にpublicフィールドとする。
    • 要件次第でsetter,getterを付ける。
  • staticなファクトリメソッドで読み込み処理をやらせる。必要なデータと操作を全て押し込める事ができたようなのでこれで良しとする。
  • もっと簡素に書けるなら、そのように修正したい。

利用したバージョン

  • SnakeYAML 1.17

ネタ元

(このwiki記事と内容一緒なんですが、ベストプラクティス的になってないのでわたしなりのを書いてみた次第。)

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3