我正在尝试读取 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
Car
和 Truck
POJO 非常明显:
汽车
package net.jgp.labs.jackson.yaml.lab411_pojos;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class Car extends Vehicle {
private int seatingCapacity;
private double topSpeed;
@JsonCreator
public Car(
@JsonProperty("make") String make,
@JsonProperty("model") String model,
@JsonProperty("seating") int seatingCapacity,
@JsonProperty("topSpeed") double topSpeed) {
super(make, model);
this.seatingCapacity = seatingCapacity;
this.topSpeed = topSpeed;
}
public int getSeatingCapacity() {
return seatingCapacity;
}
public void setSeatingCapacity(int seatingCapacity) {
this.seatingCapacity = seatingCapacity;
}
public double getTopSpeed() {
return topSpeed;
}
public void setTopSpeed(double topSpeed) {
this.topSpeed = topSpeed;
}
public String getType() {
return "car";
}
}
卡车
package net.jgp.labs.jackson.yaml.lab411_pojos;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class Truck extends Vehicle {
private double payloadCapacity;
@JsonCreator
public Truck(
@JsonProperty("make") String make,
@JsonProperty("model") String model,
@JsonProperty("payload") double payloadCapacity) {
super(make, model);
this.payloadCapacity = payloadCapacity;
}
public double getPayloadCapacity() {
return payloadCapacity;
}
public void setPayloadCapacity(double payloadCapacity) {
this.payloadCapacity = payloadCapacity;
}
@Override
public String getType() {
return "truck";
}
}
舰队
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;
}
}
车辆
Vehicle
有点棘手,因为我正在尝试使用 @JsonTypeInfo
和 @JsonSubTypes
。你可以看到注释的代码,它慢慢让我发疯:
package net.jgp.labs.jackson.yaml.lab411_pojos;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
@JsonTypeInfo(
use = JsonTypeInfo.Id.CLASS,
include = JsonTypeInfo.As.EXTERNAL_PROPERTY
// ,
// property = "className"
)
@JsonSubTypes({
@Type(value = Car.class, name = "car"),
@Type(value = Truck.class, name = "truck")
})
//@JsonSubTypes({
// @Type(value = Car.class, name = "car"),
// @Type(value = Truck.class, name = "truck")
//})
public abstract class Vehicle {
private String make;
private String model;
@JsonProperty("type")
abstract public String getType();
public void setType(String type) {};
protected Vehicle(String make, String model) {
this.make = make;
this.model = model;
}
public String getMake() {
return make;
}
public void setMake(String make) {
this.make = make;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
}
应用程序
最后是应用程序代码,这也非常明显。
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
文件无法修改,我们可以使用Streaming API
读取类型属性并反序列化Vehicle
。在伪代码中它可能看起来像:
while token != EOF
while token != FIELD_NAME
nextToken()
fieldName = nextFieldName();
clazz = convertToClass(fieldName);
vehicles.add(read(clazz));
幸运的是,定义类型的字段名称是第一个字段名称,我们可以手动读取它,然后使用 Jackson
读取类型。我从 Vehicle
类中删除了 JsonSubTypes
和 JsonTypeInfo
注释,并使用 Streaming API
它可能如下所示:
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'}]}
关于java - 使用不同类型的数组解析 YAML,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58665457/