我正在尝试读取YAML文件并将结果存储在POJO列表中。
我无法修改YAML文件。我使用Jackson 2.10.0,但可以使用任何其他版本。我正在尝试用Jackson解析以下脚本:
基本上,车辆是具有一些共同属性且对于车辆类型而言是唯一的对象的列表。
---
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系列属性可以起作用,但是我正在慢慢失去它;-)。
答案 0 :(得分:1)
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
来读取类型。我从JsonSubTypes
类中删除了JsonTypeInfo
和Vehicle
批注,并用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'}]}