Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/redis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用不同类型的数组解析YAML_Java_Jackson_Yaml - Fatal编程技术网

Java 使用不同类型的数组解析YAML

Java 使用不同类型的数组解析YAML,java,jackson,yaml,Java,Jackson,Yaml,我试图读取YAML文件并将结果存储在POJO列表中 我无法修改YAML文件。我使用Jackson 2.10.0,但我对任何其他版本都持开放态度。我正试图用Jackson解析以下脚本: 车辆-notype.yaml 车辆基本上是一个对象列表,具有一些通用属性和一些车辆类型特有的属性 --- vehicles: - car: make: "Mercedes-Benz" model: "S500" topSpeed: 250.0 seatingCapacity: 5 - truck:

我试图读取YAML文件并将结果存储在POJO列表中

我无法修改YAML文件。我使用Jackson 2.10.0,但我对任何其他版本都持开放态度。我正试图用Jackson解析以下脚本:

车辆-notype.yaml 车辆基本上是一个对象列表,具有一些通用属性和一些车辆类型特有的属性

---
vehicles:
- car:
  make: "Mercedes-Benz"
  model: "S500"
  topSpeed: 250.0
  seatingCapacity: 5
- truck:
  make: "Isuzu"
  model: "NQR"
  payloadCapacity: 7500.0
期望输出 阅读完文件后,我想,如果我反思一下列表,我想得到:

... App.java:48): -> start()
... App.java:56): class net.jgp.labs.jackson.yaml.lab411_pojos.Car
... App.java:56): class net.jgp.labs.jackson.yaml.lab411_pojos.Truck
汽车
卡车
POJO非常明显:

汽车 卡车 舰队
Fleet
POJO也很明显

package net.jgp.labs.jackson.yaml.lab411_pojos;

import java.util.List;

public class Fleet {

  private List<Vehicle> vehicles;

  public void setVehicles(List<Vehicle> vehicles) {
    this.vehicles= vehicles;
  }

  public List<Vehicle> getVehicles() {
    return vehicles;
  }

}
应用程序 最后是应用程序代码,这也是显而易见的

package net.jgp.labs.jackson.yaml.lab411_read_diff_objects;

import java.io.File;
import java.io.IOException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;

import net.jgp.labs.jackson.yaml.lab411_pojos.Fleet;
import net.jgp.labs.jackson.yaml.lab411_pojos.Vehicle;

/**
 * What does it do?
 * 
 * @author jgp
 */
public class ReadListVehicleNoTypeApp {
  private static final Logger log =
      LoggerFactory.getLogger(ReadListVehicleNoTypeApp.class);

  /**
   * main() is your entry point to the application.
   * 
   * @param args
   */
  public static void main(String[] args) {
    ReadListVehicleNoTypeApp app = new ReadListVehicleNoTypeApp();
    try {
      app.start();
    } catch (JsonProcessingException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }

  /**
   * The processing code.
   * 
   * @throws IOException
   */
  protected boolean start() throws IOException {
    log.debug("-> start()");

    ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
    Fleet fleet = mapper.readValue(new File("data/vehicles-notype.yaml"),
        Fleet.class);
    for (Vehicle v : fleet.getVehicles()) {
      log.debug("{}", v.getClass());
    }

    return true;
  }
}

我非常确定@Json属性家族有什么值得玩味的地方,但我正在慢慢失去它;-)

car
truck
是字段名、属性。我不知道允许从不同字段设置类型的
Jackson
注释

如果无法修改
Yaml
文件,我们可以使用
流式API
读取类型属性并反序列化
车辆
。在伪代码中,它可能看起来像:

while token != EOF
    while token != FIELD_NAME
        nextToken()

    fieldName = nextFieldName();
    clazz = convertToClass(fieldName);
    vehicles.add(read(clazz));
幸运的是,定义类型的字段名是第一个字段名,我们可以手动读取它,然后使用
Jackson
读取类型。我从
Vehicle
类中删除了
JsonSubTypes
JsonTypeInfo
注释,并使用
streamingapi
将其如下所示:

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLParser;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

public class YamlApp {

    public static void main(String[] args) throws Exception {
        File yamlFile = new File("./resource/test.yaml").getAbsoluteFile();

        FleetDeserializer deserializer = new FleetDeserializer();
        Fleet fleet = deserializer.readValue(yamlFile);

        System.out.println(fleet);
    }
}

class FleetDeserializer {
    private YAMLFactory factory = new YAMLFactory();
    private ObjectMapper mapper = new ObjectMapper(factory);

    public Fleet readValue(File yamlFile) throws IOException {
        Fleet fleet = new Fleet();
        fleet.setVehicles(new ArrayList<>());

        YAMLParser parser = factory.createParser(yamlFile);
        while (parser.nextToken() != null) {
            if (parser.getCurrentToken() != JsonToken.START_OBJECT) {
                continue;
            }
            // skip everything until a field name
            while (parser.nextToken() != JsonToken.FIELD_NAME) ;

            Class<? extends Vehicle> type = getType(parser.getCurrentName());
            if (type == null) {
                continue;
            }

            // skip field name
            parser.nextToken();
            parser.nextToken();

            // read next vehicle
            fleet.getVehicles().add(mapper.readValue(parser, type));
        }

        return fleet;
    }

    private Class<? extends Vehicle> getType(String fieldName) {
        Objects.requireNonNull(fieldName);
        switch (fieldName) {
            case "car":
                return Car.class;
            case "truck":
                return Truck.class;
            default:
                return null;
        }
    }
}

这是伟大的米莎。。。但是,当我这样做时:ObjectMapper mapper=newobjectmapper(newyamlfactory());String jsonDataString=mapper.writeValueAsString(fleet);然后它会丢失类型。你认为我需要一个自定义序列化程序吗?@jgp,因为我们删除了所有与类型信息相关的注释,我们需要编写自定义序列化程序,或者在每个类中提供额外字段/getter:
getCar(){return”“;}
Car
类和
getruck(){return”“;}
Truck
类中。如果需要,可以使用
@JsonPropertyOrder
对类进行注释,以确保该类型将是第一个字段。。。我仍然得到这样的东西:-汽车:“制造:”梅赛德斯-奔驰“有没有可能我可以摆脱双重报价?我尝试了include/null值,但没有成功…@jgp这不是一件容易的事情,因为幕后使用了
SnakeYAML
,您应该以某种方式将其配置为不为空字符串写引号。此外,这不是一个bug,而是一个功能:。请参阅文档中的和。@jgp,我发现了一个肮脏的黑客程序,但我不确定它是否适用于您,因为我们禁用了所有
String
值的引号。您需要启用
YAMLGenerator.Feature.MINIMIZE\u QUOTES
功能。例如:
factory.enable(YAMLGenerator.Feature.MINIMIZE_引号)
而不是返回空字符串:
公共字符串getCar(){return“\u00A0”;}
公共字符getTruck(){return 0X00A0;}
。现在,这个字符在输出中不可见,应该删除引号。缺点:引号到处都被删除了。
package net.jgp.labs.jackson.yaml.lab411_read_diff_objects;

import java.io.File;
import java.io.IOException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;

import net.jgp.labs.jackson.yaml.lab411_pojos.Fleet;
import net.jgp.labs.jackson.yaml.lab411_pojos.Vehicle;

/**
 * What does it do?
 * 
 * @author jgp
 */
public class ReadListVehicleNoTypeApp {
  private static final Logger log =
      LoggerFactory.getLogger(ReadListVehicleNoTypeApp.class);

  /**
   * main() is your entry point to the application.
   * 
   * @param args
   */
  public static void main(String[] args) {
    ReadListVehicleNoTypeApp app = new ReadListVehicleNoTypeApp();
    try {
      app.start();
    } catch (JsonProcessingException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }

  /**
   * The processing code.
   * 
   * @throws IOException
   */
  protected boolean start() throws IOException {
    log.debug("-> start()");

    ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
    Fleet fleet = mapper.readValue(new File("data/vehicles-notype.yaml"),
        Fleet.class);
    for (Vehicle v : fleet.getVehicles()) {
      log.debug("{}", v.getClass());
    }

    return true;
  }
}
while token != EOF
    while token != FIELD_NAME
        nextToken()

    fieldName = nextFieldName();
    clazz = convertToClass(fieldName);
    vehicles.add(read(clazz));
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLParser;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

public class YamlApp {

    public static void main(String[] args) throws Exception {
        File yamlFile = new File("./resource/test.yaml").getAbsoluteFile();

        FleetDeserializer deserializer = new FleetDeserializer();
        Fleet fleet = deserializer.readValue(yamlFile);

        System.out.println(fleet);
    }
}

class FleetDeserializer {
    private YAMLFactory factory = new YAMLFactory();
    private ObjectMapper mapper = new ObjectMapper(factory);

    public Fleet readValue(File yamlFile) throws IOException {
        Fleet fleet = new Fleet();
        fleet.setVehicles(new ArrayList<>());

        YAMLParser parser = factory.createParser(yamlFile);
        while (parser.nextToken() != null) {
            if (parser.getCurrentToken() != JsonToken.START_OBJECT) {
                continue;
            }
            // skip everything until a field name
            while (parser.nextToken() != JsonToken.FIELD_NAME) ;

            Class<? extends Vehicle> type = getType(parser.getCurrentName());
            if (type == null) {
                continue;
            }

            // skip field name
            parser.nextToken();
            parser.nextToken();

            // read next vehicle
            fleet.getVehicles().add(mapper.readValue(parser, type));
        }

        return fleet;
    }

    private Class<? extends Vehicle> getType(String fieldName) {
        Objects.requireNonNull(fieldName);
        switch (fieldName) {
            case "car":
                return Car.class;
            case "truck":
                return Truck.class;
            default:
                return null;
        }
    }
}
Fleet{vehicles=[Car{seatingCapacity=5, topSpeed=250.0, make='Mercedes-Benz', model='S500'}, Truck{payloadCapacity=7500.0, make='Isuzu', model='NQR'}]}