前言
如果Json字符串中嵌套的对象,在Java类中的属性也是以嵌套对象的形式存在,那么直接反序列化即可;
比如下面的例子:此时可以解析成功;
// User中嵌套有Animal对象
public class User {
private String username;
private Animal animal;
}
class Animal{
private String animalName;
}
// Json字符串中嵌套了animal对象
String s = "{\"username\": \"jalon\", \"animal\":{\"animalName\": \"tutu\"}}";
但是如果Java类中没有嵌套对象,而是将嵌套对象的属性展开来存储,那么就需要做一些处理,才可以反序列化;
比如下面的User类:没有嵌套Animal类,而是将它的animalName属性包含进来
public class User {
private String username;
private String animalName;
}
下面分别介绍几种解析的办法,思路就是将嵌套的对象解析为不同的类型,然后再提取对应的属性;
用到的实体类就是上面这个User类
目录
- 解析为Map对象
- 解析为JsonNode
- 配置反序列化类
正文
1. 解析为Map对象
这里可以通过前面介绍的@JsonProperty属性来实现;
@JsonProperty注解是用来将Json字符串中的属性名和Java类中的属性名对应起来;
这里我们将@JsonProperty注解加在一个public setter方法上,这样反序列化时,就可以获取到嵌套的对象,然后对其进行解析操作;
这里涉及到前面介绍过的一个知识点:Jackson反序列化是通过对应的public setter方法进行解析的;
加了注解后的User类如下:
@AllArgsConstructor
@NoArgsConstructor
@Data
public class User {
private String username;
private String animalName;
@JsonProperty(value = "animal")
public void setName(Map<String, Object> animal){
this.animalName = (String) animal.getOrDefault("animalName", "");
}
}
执行测试代码,如下:
String s = "{\"username\": \"jalon\", \"animal\":{\"animalName\": \"tutu\"}}";
ObjectMapper objectMapper = new ObjectMapper();
User user = objectMapper.readValue(s, User.class);
System.out.println(user);
运行输出如下:
可以看到,成功将嵌套的对象解析到User对象中;
2. 解析为JsonNode
前面的Jackson比较两个Json对象 - 掘金 (juejin.cn)介绍过JsonNode对象,我们可以简单理解为 加强版的Map映射集合;
不知道具体的解析对象,可以将其解析为JsonNode对象,然后通过asText()等方法取出对应的值;
这里正好可以用到,我们可以通过JsonNode取出嵌套的对象,然后获取对应的属性;
代码如下:
String s = "{\"username\": \"jalon\", \"animal\":{\"animalName\": \"tutu\"}}";
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(s);
String username = jsonNode.get("username").asText();
String animalName = jsonNode.get("animal").get("animalName").asText();
User user = new User(username, animalName);
System.out.println(user);
输出如下:
可以看到,成功读取;
3. 配置反序列化类
这种方式是第二种的封装版,就是把第二种JsonNode那种获取方式,封装到一个自定义的类中,然后需要时通过@JsonDeserialize进行注入即可;
下面是将JsonNode相关操作封装到自定义的类中的例子:
public class UserDeserialize extends StdDeserializer<User> {
public UserDeserialize() {
this(null);
}
public UserDeserialize(Class<?> vc) {
super(vc);
}
@Override
public User deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
JsonNode jsonNode = jp.getCodec().readTree(jp);
User user = new User();
user.setUsername(jsonNode.get("username").asText());
user.setAnimalName(jsonNode.get("animal").get("animalName").asText());
return user;
}
}
然后在User实体类上加@JsonDeserialize注解:
@AllArgsConstructor
@NoArgsConstructor
@Data
@JsonDeserialize(using = UserDeserialize.class)
public class User {
private String username;
private String animalName;
}
最后运行代码进行测试:
String s = "{\"username\": \"jalon\", \"animal\":{\"animalName\": \"tutu\"}}";
ObjectMapper objectMapper = new ObjectMapper();
User user = objectMapper.readValue(s, User.class);
System.out.println(user);
输出如下:
可以看到,正常输出
总结
解析嵌套对象时,如果Java实体类也有对应的嵌套对象属性,那么直接解析即可;
但是如果Java实体类没有嵌套对象属性,只有展开的属性,那么就需要用到上面介绍的三种解析方法:
- 解析为Map对象:通过@JsonProperty(value = "animal")获取到嵌套对象,然后提取对应的属性;
- 解析为JsonNode对象:可以通过JsonNode获取嵌套对象的属性,然后再存储到实体类中;
- 配置反序列化类:第2种的升级版,将JsonNode对应的解析代码封装到单独的类中,然后通过@JsonDeserialize进行解析;
评论区