gson将一个字段反序列化为null
gson deserializing a field as null
首先,我想说这是一个大学项目。
我有 3 个 class。 Order
抽象 class 和 Delivery
和 DineIn
class 继承自 Order.
我正在使用 Gson serialize/deserialize 子 classes 但我 运行 有点问题。订单 class 有一个字段 orderType
,gson 使用该字段来确定其订单类型,堂食或送货。
序列化工作正常。问题是,每当我尝试反序列化时,类型字段值都不会被读取并且总是设置为空,即使它存在于 JSON 文件中。
当 Order 中有很多字段时会发生这种情况,因为当我尝试使用只有 2 个字段(orderType 和 orderNo)的 Order class 以较小的规模测试该程序时,一切正常。我不知道我做错了什么。我试过在这个网站上搜索,几乎总是遇到制作自定义类型适配器和序列化器的建议,但我们在大学里没有研究过它们,我不想使用它们(讲师会因为使用他没有的任何东西而扣分没教过,我上次从他那里学的一门课我差点挂了,因为我用了他没有教过的东西。不过他似乎对第三方库没有问题。
代码:
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;
}
}
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"
}
]
在您的代码中,您有一个层次结构,其中 DineIn
和 Delivery
从 Order
扩展而来。 orderType
字段的设置方式是通过 super()
构造函数中的显式字符串参数。
但是,Gson不使用构造函数来实例化对象。它使用特殊的无参数构造函数并通过反射填充值:
在这种特定情况下,问题来自 RuntimeTypeAdapterFactory
,它从它读取的 JSON 中删除了 orderType
字段。这里的源代码确认:https://github.com/google/gson/blob/86d88c32cf6a6b7a6e0bbc855d76e4ccf6f120bb/extras/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java#L202
正如@fluffy 建议的,较新版本的库包含 maintain
标志,这应该允许保留该字段:https://github.com/google/gson/blob/c1e7e2d2808b042cbe47ca31869ee6ccc62c5417/extras/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java#L214
首先,我想说这是一个大学项目。
我有 3 个 class。 Order
抽象 class 和 Delivery
和 DineIn
class 继承自 Order.
我正在使用 Gson serialize/deserialize 子 classes 但我 运行 有点问题。订单 class 有一个字段 orderType
,gson 使用该字段来确定其订单类型,堂食或送货。
序列化工作正常。问题是,每当我尝试反序列化时,类型字段值都不会被读取并且总是设置为空,即使它存在于 JSON 文件中。 当 Order 中有很多字段时会发生这种情况,因为当我尝试使用只有 2 个字段(orderType 和 orderNo)的 Order class 以较小的规模测试该程序时,一切正常。我不知道我做错了什么。我试过在这个网站上搜索,几乎总是遇到制作自定义类型适配器和序列化器的建议,但我们在大学里没有研究过它们,我不想使用它们(讲师会因为使用他没有的任何东西而扣分没教过,我上次从他那里学的一门课我差点挂了,因为我用了他没有教过的东西。不过他似乎对第三方库没有问题。
代码:
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;
}
}
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"
}
]
在您的代码中,您有一个层次结构,其中 DineIn
和 Delivery
从 Order
扩展而来。 orderType
字段的设置方式是通过 super()
构造函数中的显式字符串参数。
但是,Gson不使用构造函数来实例化对象。它使用特殊的无参数构造函数并通过反射填充值:
在这种特定情况下,问题来自 RuntimeTypeAdapterFactory
,它从它读取的 JSON 中删除了 orderType
字段。这里的源代码确认:https://github.com/google/gson/blob/86d88c32cf6a6b7a6e0bbc855d76e4ccf6f120bb/extras/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java#L202
正如@fluffy 建议的,较新版本的库包含 maintain
标志,这应该允许保留该字段:https://github.com/google/gson/blob/c1e7e2d2808b042cbe47ca31869ee6ccc62c5417/extras/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java#L214