使用自定义反序列化器 Jackson 将 .json 文件转换为 Java 对象
Converting a .json file into a Java object with a custom deserializer Jackson
在我的项目中,我有一个名为 Closet 的 class,它包含一个名为 clothes 的服装列表。我已经实现了将 Closet 对象的信息保存到 .json 文件中的代码,结果如下所示:
{
"clothes" : [ {
"name" : "mypants",
"type" : "pants",
"color" : "red",
"size" : 32.0,
"needsWashing" : false
}, {
"name" : "myshirt",
"type" : "shirt",
"color" : "blue",
"size" : 2.0,
"needsWashing" : false
} ],
"numberOfClothing" : 2
}
但是,当我尝试检索 Json 文件并将其转换回壁橱时,抛出了 JsonProcessingException。
Closet closet = getDefaultObjectMapper().readValue(Paths.get("./data/Closet.json")
.toFile(), Closet.class);
我是初学者 java 程序员,我不确定如何解决这个问题。我已经通过创建自定义反序列化器进行了一些搜索,但是,我不确定如何使用我的嵌套对象(Clothing 嵌套在 Closet 中)以及 Closet 对象中可能有任意数量的 Clothing 来实现反序列化器。
我对另一个名为 StyleBoard 的 class 有同样的问题,它是一个 Outfit 列表(另一个 class),而一个 Outfit 是一个 Clothing 列表。样式板的 json 文件写入 .json 文件的示例是
contains 2 outfits "shirt and pants" and "pants and socks" each with 2 Clothing objects
{
"styleBoard" : [ {
"clothes" : [ {
"name" : "mypants",
"type" : "pants",
"color" : "blue",
"size" : 32.0,
"needsWashing" : false
}, {
"name" : "myshirt",
"type" : "shirt",
"color" : "blue",
"size" : 0.0,
"needsWashing" : false
} ],
"favorite" : false,
"name" : "shirt and pants",
"numberOfClothing" : 2
}, {
"clothes" : [ {
"name" : "mypants",
"type" : "pants",
"color" : "blue",
"size" : 32.0,
"needsWashing" : false
}, {
"name" : "mysocks",
"type" : "socks",
"color" : "white",
"size" : 3.0,
"needsWashing" : false
} ],
"favorite" : false,
"name" : "pants and socks",
"numberOfClothing" : 2
} ],
"numberOfOutfits" : 2
}
这是我收到的错误消息:
Exception in thread "main" java.lang.RuntimeException: Cannot construct instance of `model.Clothing` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (String)"{
"clothes" : [ {
"name" : "myshirt",
"type" : "shirt",
"color" : "black",
"size" : 2.09,
"needsWashing" : false
}, {
"name" : "mypants",
"type" : "pants",
"color" : "red",
"size" : 32.0,
"needsWashing" : false
} ],
"collectionSize" : 2
}"; line: 3, column: 5] (through reference chain: model.Closet["clothes"]->java.util.ArrayList[0])
at persistence.Json.fromJson(Json.java:43)
at persistence.Json.parseUserCloset(Json.java:104)
at ui.ClosetApp.loadUser(ClosetApp.java:195)
at ui.ClosetApp.runClosetApp(ClosetApp.java:173)
at ui.ClosetApp.doLogin(ClosetApp.java:103)
at ui.ClosetApp.processLoginCommand(ClosetApp.java:68)
at ui.ClosetApp.runLogin(ClosetApp.java:49)
at ui.ClosetApp.<init>(ClosetApp.java:26)
at ui.Main.main(Main.java:5)
我注意到的一个可能导致此问题的问题是,当我将壁橱对象写入 .json 文件时,它添加了一个额外的字段 "numberOfClothing" 如你所见。这不是我的 Closet 构造函数的一部分,但是我确实有一个名为 getNumberOfClothing 的 getter。当我将此 getter 的名称更改为 getCollectionSize 时,添加到我的 json 的这个额外字段变为 "collectionSize"。
为什么要创建这个额外的字段?我怎样才能防止它? 我认为这个额外的字段导致从 json.
重建对象时出现问题
首先,您需要根据您的 json 创建 classes。
您需要创建一个壁橱 class.
仅供参考,我使用 Lombok 是为了简洁,即不需要 getter、setter 和 toString 方法。如果您不使用 Lombok,则必须创建 getter 和 setter,因为 Jackson 库将使用此 getter 和 setter。
@Getter
@Setter
@ToString
@FieldDefaults(level= AccessLevel.PRIVATE)
public class Closet {
// you need to create getter and setter method.
// i use lombok so I don't need to create one
List<Cloth> clothes = new ArrayList<>();
Integer numberOfClothing;
}
然后是布料class:
@Getter
@Setter
@ToString
@FieldDefaults(level= AccessLevel.PRIVATE)
public class Cloth {
String name;
String type;
String color;
Float size;
Boolean needsWashing;
}
如果您需要命名您的 class 成员而不是 json 字段,您可以使用 @JsonProperty("json 字段名称") 进行注释,例如
@JsonProperty("name")
String clothName;
那么实际的转换代码:
Closet closet = JsonUtil.fromJson(jsonStr, Closet.class);
其中 JsonUtil class 包含此静态方法(使用 jackson):
public static <T> T fromJson(String jsonStr, Class<T> clazz){
try {
return new ObjectMapper().readValue(jsonStr, clazz);
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}
您可以通过下面的 maven 依赖获取 jackson 库:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.0</version>
</dependency>
jackson教程,可以google。下面只是其中一个例子:
https://www.baeldung.com/jackson-object-mapper-tutorial
我把样式板留给你,因为步骤与壁橱完全相同 class。
问题出在我的 Clothing class 没有带空参数的构造函数。我只是添加了另一个构造函数。
额外的无法识别的字段“numberOfclothing”的问题是由于我的 Closet 和 StyleBoard 类 都对不属于字段的值但对使用列表类型。我只需要更改这些方法的名称,使其名称中不包含“get”即可。
在我的项目中,我有一个名为 Closet 的 class,它包含一个名为 clothes 的服装列表。我已经实现了将 Closet 对象的信息保存到 .json 文件中的代码,结果如下所示:
{
"clothes" : [ {
"name" : "mypants",
"type" : "pants",
"color" : "red",
"size" : 32.0,
"needsWashing" : false
}, {
"name" : "myshirt",
"type" : "shirt",
"color" : "blue",
"size" : 2.0,
"needsWashing" : false
} ],
"numberOfClothing" : 2
}
但是,当我尝试检索 Json 文件并将其转换回壁橱时,抛出了 JsonProcessingException。
Closet closet = getDefaultObjectMapper().readValue(Paths.get("./data/Closet.json")
.toFile(), Closet.class);
我是初学者 java 程序员,我不确定如何解决这个问题。我已经通过创建自定义反序列化器进行了一些搜索,但是,我不确定如何使用我的嵌套对象(Clothing 嵌套在 Closet 中)以及 Closet 对象中可能有任意数量的 Clothing 来实现反序列化器。
我对另一个名为 StyleBoard 的 class 有同样的问题,它是一个 Outfit 列表(另一个 class),而一个 Outfit 是一个 Clothing 列表。样式板的 json 文件写入 .json 文件的示例是
contains 2 outfits "shirt and pants" and "pants and socks" each with 2 Clothing objects
{
"styleBoard" : [ {
"clothes" : [ {
"name" : "mypants",
"type" : "pants",
"color" : "blue",
"size" : 32.0,
"needsWashing" : false
}, {
"name" : "myshirt",
"type" : "shirt",
"color" : "blue",
"size" : 0.0,
"needsWashing" : false
} ],
"favorite" : false,
"name" : "shirt and pants",
"numberOfClothing" : 2
}, {
"clothes" : [ {
"name" : "mypants",
"type" : "pants",
"color" : "blue",
"size" : 32.0,
"needsWashing" : false
}, {
"name" : "mysocks",
"type" : "socks",
"color" : "white",
"size" : 3.0,
"needsWashing" : false
} ],
"favorite" : false,
"name" : "pants and socks",
"numberOfClothing" : 2
} ],
"numberOfOutfits" : 2
}
这是我收到的错误消息:
Exception in thread "main" java.lang.RuntimeException: Cannot construct instance of `model.Clothing` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (String)"{
"clothes" : [ {
"name" : "myshirt",
"type" : "shirt",
"color" : "black",
"size" : 2.09,
"needsWashing" : false
}, {
"name" : "mypants",
"type" : "pants",
"color" : "red",
"size" : 32.0,
"needsWashing" : false
} ],
"collectionSize" : 2
}"; line: 3, column: 5] (through reference chain: model.Closet["clothes"]->java.util.ArrayList[0])
at persistence.Json.fromJson(Json.java:43)
at persistence.Json.parseUserCloset(Json.java:104)
at ui.ClosetApp.loadUser(ClosetApp.java:195)
at ui.ClosetApp.runClosetApp(ClosetApp.java:173)
at ui.ClosetApp.doLogin(ClosetApp.java:103)
at ui.ClosetApp.processLoginCommand(ClosetApp.java:68)
at ui.ClosetApp.runLogin(ClosetApp.java:49)
at ui.ClosetApp.<init>(ClosetApp.java:26)
at ui.Main.main(Main.java:5)
我注意到的一个可能导致此问题的问题是,当我将壁橱对象写入 .json 文件时,它添加了一个额外的字段 "numberOfClothing" 如你所见。这不是我的 Closet 构造函数的一部分,但是我确实有一个名为 getNumberOfClothing 的 getter。当我将此 getter 的名称更改为 getCollectionSize 时,添加到我的 json 的这个额外字段变为 "collectionSize"。 为什么要创建这个额外的字段?我怎样才能防止它? 我认为这个额外的字段导致从 json.
重建对象时出现问题首先,您需要根据您的 json 创建 classes。 您需要创建一个壁橱 class.
仅供参考,我使用 Lombok 是为了简洁,即不需要 getter、setter 和 toString 方法。如果您不使用 Lombok,则必须创建 getter 和 setter,因为 Jackson 库将使用此 getter 和 setter。
@Getter
@Setter
@ToString
@FieldDefaults(level= AccessLevel.PRIVATE)
public class Closet {
// you need to create getter and setter method.
// i use lombok so I don't need to create one
List<Cloth> clothes = new ArrayList<>();
Integer numberOfClothing;
}
然后是布料class:
@Getter
@Setter
@ToString
@FieldDefaults(level= AccessLevel.PRIVATE)
public class Cloth {
String name;
String type;
String color;
Float size;
Boolean needsWashing;
}
如果您需要命名您的 class 成员而不是 json 字段,您可以使用 @JsonProperty("json 字段名称") 进行注释,例如
@JsonProperty("name")
String clothName;
那么实际的转换代码:
Closet closet = JsonUtil.fromJson(jsonStr, Closet.class);
其中 JsonUtil class 包含此静态方法(使用 jackson):
public static <T> T fromJson(String jsonStr, Class<T> clazz){
try {
return new ObjectMapper().readValue(jsonStr, clazz);
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}
您可以通过下面的 maven 依赖获取 jackson 库:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.0</version>
</dependency>
jackson教程,可以google。下面只是其中一个例子: https://www.baeldung.com/jackson-object-mapper-tutorial
我把样式板留给你,因为步骤与壁橱完全相同 class。
问题出在我的 Clothing class 没有带空参数的构造函数。我只是添加了另一个构造函数。
额外的无法识别的字段“numberOfclothing”的问题是由于我的 Closet 和 StyleBoard 类 都对不属于字段的值但对使用列表类型。我只需要更改这些方法的名称,使其名称中不包含“get”即可。