SnakeYAML实例化ArrayList而不是HashMap [英] SnakeYAML is instantiating ArrayList instead of HashMap

查看:139
本文介绍了SnakeYAML实例化ArrayList而不是HashMap的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要解析以下YAML文件.

I need to parse the following YAML file.

arguments:
  - Database
  - Fold
  - MetaFeature
  - Algorithm
  - Config
processes:
  - id: MetaFeatureCalculator
    command: "python metaFeatCalc.py {Database} folds/{Fold} de/{MetaFeature}/{Algorithm}.csv"
    in: [Database, Fold]
    out: [MetaFeature, Algorithm]
    log: "mf/{Fold}/{MetaFeature}.out"
  - id: Tunner
    command: "java -jar tunner.jar {MetaFeature} alg/{Algorithm} {config}"
    in: [Metafeature, Algorithm]
    out: [Config]
    log: "mf/{Metafeature}/{Algorithm}.out"
recipeDefaults:
  - Database: ["D1"]
recipes:
  - id: Ex1
    uses:
      - Database: ["D1", "D2"]
      - MetaFeature: ["M1", "M2"]
      - Algorithm: ["A1", "A2"]
      - Config: ["C1", "C4"]
  - id: Ex2
    uses:
      - Folds: ["F1", "F2", "F5"]
      - MetaFeature: ["M1", "M2"]
      - Algorithm: ["A1", "A2"]
      - Config: ["C1", "C4"]

然后我创建了以下POJO来接收此数据.

And I created the following POJOs to receive this data.

回购: https://github.com/Pacheco95/ExperimentLoader

@Data
public class Experiment {
  private HashSet<String> arguments;
  private HashSet<Process> processes;
  private HashSet<HashMap<String, HashSet<String>>> recipeDefaults;
  private HashSet<Recipe> recipes;
}

@Data
public class Process {
  private String id;
  private String command;
  private HashSet<String> in;
  private HashSet<String> out;
  private String log;
}

@Data
public class Recipe {
  private String id;
  private HashSet<HashMap<String, HashSet>> uses;
}

然后使用此类来测试解析器:

And this class to test the parser:

public class ExperimentLoader {
  public static void main(String[] args) throws IOException {
    InputStream is = args.length == 0 ? System.in : Files.newInputStream(Paths.get(args[0]));
    Yaml yaml = new Yaml();
    Experiment experiment = yaml.loadAs(is, Experiment.class);
    Gson gson = new GsonBuilder().setPrettyPrinting().serializeNulls().create();
    System.out.println(gson.toJson(experiment));
  }
}

解析器似乎运行良好,但是在调试模式下运行此代码时,某些字段已使用正确的类型(HashSet)实例化,而其他字段则没有.它们被实例化为ArrayLists(我不知道这里发生了什么魔术).

The parser seems to work well, but running this code in debugging mode some fields was instantiated with the correct type (HashSet) while others dont. They was instantiated as ArrayLists (I have no idea what kind of magic happened here).

这是脱胶窗口的快照:

我的测试课的输出:

{
  "arguments": [
    "Fold",
    "MetaFeature",
    "Config",
    "Database",
    "Algorithm"
  ],
  "processes": [
    {
      "id": "MetaFeatureCalculator",
      "command": "python metaFeatCalc.py {Database} folds/{Fold} de/{MetaFeature}/{Algorithm}.csv",
      "in": [
        "Fold",
        "Database"
      ],
      "out": [
        "MetaFeature",
        "Algorithm"
      ],
      "log": "mf/{Fold}/{MetaFeature}.out"
    },
    {
      "id": "Tunner",
      "command": "java -jar tunner.jar {MetaFeature} alg/{Algorithm} {config}",
      "in": [
        "Metafeature",
        "Algorithm"
      ],
      "out": [
        "Config"
      ],
      "log": "mf/{Metafeature}/{Algorithm}.out"
    }
  ],
  "recipeDefaults": [
    {
      "Database": [
        "D1"
      ]
    }
  ],
  "recipes": [
    {
      "id": "Ex2",
      "uses": [
        {
          "MetaFeature": [
            "M1",
            "M2"
          ]
        },
        {
          "Folds": [
            "F1",
            "F2",
            "F5"
          ]
        },
        {
          "Config": [
            "C1",
            "C4"
          ]
        },
        {
          "Algorithm": [
            "A1",
            "A2"
          ]
        }
      ]
    },
    {
      "id": "Ex1",
      "uses": [
        {
          "MetaFeature": [
            "M1",
            "M2"
          ]
        },
        {
          "Config": [
            "C1",
            "C4"
          ]
        },
        {
          "Database": [
            "D1",
            "D2"
          ]
        },
        {
          "Algorithm": [
            "A1",
            "A2"
          ]
        }
      ]
    }
  ]
}

我的依赖项:

<dependencies>
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
    <scope>test</scope>
  </dependency>
  <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.8</version>
    <scope>provided</scope>
  </dependency>
  <dependency>
    <groupId>org.yaml</groupId>
    <artifactId>snakeyaml</artifactId>
    <version>1.24</version>
  </dependency>
  <dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.5</version>
  </dependency>
</dependencies>

有人遇到过这个问题吗?我找不到解决方法.

Has anyone had this problem? I cant find a solution.

推荐答案

您的问题可能是类型删除:

当类型安全(通用)集合是JavaBean属性时,SnakeYAML动态检测所需的类. […]

When type-safe (generic) collections are JavaBean properties SnakeYAML dynamically detects the required class. […]

如果泛型类型是抽象类(接口),则该方法不起作用.您必须在YAML中放置一个显式标签或提供显式TypeDescription. TypeDescription的目标是收集更多信息并在加载/转储时使用它.

It does not work if generic type is abstract class (interface). You have to put an explicit tag in the YAML or provide the explicit TypeDescription. TypeDescription serves the goal to collect more information and use it while loading/dumping.

虽然您不使用抽象类或接口,但我认为SnakeYaml在发现HashSet<HashMap<String, HashSet>>的嵌套泛型类型方面存在问题.该文档建议添加TypeDescription.但是,这不能解决您的问题,因为设计了接口,因此您只能在外部HashSet内部指定类型,而不能在内部HashMap内部指定类型.接口不期望嵌套容器这一事实也暗示了这是您的问题.

While you do not use abstract classes or interfaces, I assume that SnakeYaml has a problem with discovering the nested generic types of HashSet<HashMap<String, HashSet>>. The documentation suggests adding a TypeDescription; however that does not solve your problem because the interface is designed so that you can only specify the type inside the outer HashSet, but not inside the inner HashMap. The fact that the interface does not expect nested containers also hints that this is your problem.

一种解决方法是将YAML内部的显式标记添加到无法正确加载的集合:

A workaround would be to add explicit tags inside your YAML to the sets that fail to load properly:

- Database: !!set ["D1"]
- MetaFeature: !!set ["M1", "M2"]

如果您不想这样做,则基本上有两个选择:将此功能修补到SnakeYAML中,或使用低级API并从解析器事件中手动生成类型.

If you don't want to do that, you basically have two other options: Patch this feature into SnakeYAML, or use the low-level API and generate your types manually from the parser events.

这篇关于SnakeYAML实例化ArrayList而不是HashMap的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆