मैं एक वाईएएमएल फ़ाइल पढ़ने और परिणाम को पीओजेओ की सूची में संग्रहीत करने की कोशिश कर रहा हूं।

मैं YAML फ़ाइल को संशोधित नहीं कर सकता। मैं जैक्सन 2.10.0 का उपयोग करता हूं लेकिन मैं किसी अन्य संस्करण के लिए खुला हूं। मैं जैक्सन के साथ निम्नलिखित स्क्रिप्ट को पार्स करने की कोशिश कर रहा हूं:

वाहन-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 परिवार के साथ खेलने के लिए कुछ है, लेकिन मैं इसे धीरे-धीरे खो रहा हूं ;-)।

2
jgp 1 नवम्बर 2019, 23:23

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'}]}
1
Michał Ziober 2 नवम्बर 2019, 11:53