简体   繁体   中英

gson deserializing a field as null

First of all, I'd like to say this is for a university project.

I have 3 classes. Order abstract class and Delivery and DineIn classes which inherits from Order.

I am using Gson to serialize/deserialize the child classes but I have run into a bit of a problem. The Order class has a field orderType which gson uses to determine type of order it is, DineIn or Delivery.

Serialization is working just fine. The problem is that whenever I try to deserialize, the type field value is not read and is always set as null even though it is present in the JSON file. This happens when there are a lot of fields in Order because when I tried testing this program on a smaller scale with the Order class just having 2 fields (orderType and orderNo) everything worked just fine. I don't what I am doing wrong. I have tried searching on this site and am almost always coming across suggestions to make custom type adapters and serializers but we haven't studied about them in university and I don't want to use them (the instructor deducts marks for using anything he hasn't taught, I almost failed a course I took from him last time because I used things he hadn't taught. He doesn't seem to have a problem with third-party libraries though).

The code:

public class Main {
    public static final List<Order> ordersList = read();
    public static void main(String[] args) {
        System.out.println(ordersList.get(0).getOrderType());
        System.out.println(ordersList.get(0) instanceof DineIn ? "DineIn": "Delivery");
    }

    private static List<Order> read(){
        List<Order> ordersList = new ArrayList<>();
        Type type = new TypeToken<ArrayList<Order>>() {
        }.getType();


        RuntimeTypeAdapterFactory<Order> adapter = RuntimeTypeAdapterFactory.of(Order.class, "orderType")
                .registerSubtype(DineIn.class)
                .registerSubtype(Delivery.class);

        Gson gson = new GsonBuilder().registerTypeAdapterFactory(adapter).create();
        JsonReader ordersJsonReader;
        try {
            ordersJsonReader = new JsonReader(new FileReader("orders.json"));
            List<Order> tempOrdersList = gson.fromJson(ordersJsonReader, type);
            if (tempOrdersList != null) ordersList = tempOrdersList;
            ordersJsonReader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ordersList;
    }
}

abstract class Order {
    private final int orderNumber;
    private final String date, customerName;
    private final int discountRate;
    private final String paymentMethod;
    private String orderStatus;
    private int grossTotal = 0;
    private double netTotal = 0;
    private int totalItems = 0;
    protected final String orderType;

    public abstract String getOrderType();
    public abstract double getExtraCharges();

    public Order(int orderNumber, String date, String customerName, int discountRate, String paymentMethod, String orderStatus, int grossTotal, double netTotal, int totalItems, String orderType) {
        this.orderNumber = orderNumber;
        this.date = date;
        this.customerName = customerName;
        this.discountRate = discountRate;
        this.paymentMethod = paymentMethod;
        this.orderStatus = orderStatus;
        this.grossTotal = grossTotal;
        this.netTotal = netTotal;
        this.totalItems = totalItems;
        this.orderType = orderType;
    }
}

class DineIn extends Order {
    private double serviceCharges = 150;

    public DineIn(int orderNumber, String date, String customerName, int discountRate, String paymentMethod, String orderStatus, int grossTotal, double netTotal, int totalItems) {
        super(orderNumber, date, customerName, discountRate, paymentMethod, orderStatus, grossTotal, netTotal, totalItems, "DineIn");
    }

    @Override
    public String getOrderType() {
        return orderType;
    }

    @Override
    public double getExtraCharges() {
        return serviceCharges;
    }
}

class Delivery extends Order {
    private double deliveryCharges = 100;

    public Delivery(int orderNumber, String date, String customerName, int discountRate, String paymentMethod, String orderStatus, int grossTotal, double netTotal, int totalItems) {
        super(orderNumber, date, customerName, discountRate, paymentMethod, orderStatus, grossTotal, netTotal, totalItems, "Delivery");
    }

    @Override
    public String getOrderType() {
        return orderType;
    }

    @Override
    public double getExtraCharges() {
        return deliveryCharges;
    }
}

The JSON:

[
  {
    "serviceCharges": 150.0,
    "orderNumber": 1,
    "date": "12/12/2021",
    "customerName": "Ali",
    "discountRate": 15,
    "paymentMethod": "Card",
    "orderStatus": "Preparing",
    "grossTotal": 5000,
    "netTotal": 4500.0,
    "totalItems": 14,
    "orderType": "DineIn"
  }
]

In your code you have a hierarchy where DineIn and Delivery extend from Order . The way the orderType field is set is through an explicit String argument in the super() constructor.

However, Gson does not use the constructor to instantiate the objects. It uses a special no-argument constructor and populates the values via reflection: https://stackoverflow.com/a/40442037/9698467

In this specific case the problem comes from the RuntimeTypeAdapterFactory , which removes the orderType field from the JSON that it reads. The source code here confirms that: https://github.com/google/gson/blob/86d88c32cf6a6b7a6e0bbc855d76e4ccf6f120bb/extras/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java#L202

As @fluffy suggested newer versions of the library include the maintain flag, which should allow for the field to be preserved: https://github.com/google/gson/blob/c1e7e2d2808b042cbe47ca31869ee6ccc62c5417/extras/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java#L214

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM