侧边栏壁纸
  • 累计撰写 94 篇文章
  • 累计创建 100 个标签
  • 累计收到 10 条评论

目 录CONTENT

文章目录

Jackson反序列化嵌套的对象

汤圆学Java
2022-02-25 / 0 评论 / 0 点赞 / 420 阅读 / 4,030 字
温馨提示:
本文最后更新于 2022-02-25,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

前言

如果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类

目录

  1. 解析为Map对象
  2. 解析为JsonNode
  3. 配置反序列化类

正文

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);

运行输出如下:

image-20220222182504768

可以看到,成功将嵌套的对象解析到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);

输出如下:

image-20220223154251168

可以看到,成功读取;

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);

输出如下:

image-20220223155116938

可以看到,正常输出

总结

解析嵌套对象时,如果Java实体类也有对应的嵌套对象属性,那么直接解析即可;

但是如果Java实体类没有嵌套对象属性,只有展开的属性,那么就需要用到上面介绍的三种解析方法:

  1. 解析为Map对象:通过@JsonProperty(value = "animal")获取到嵌套对象,然后提取对应的属性;
  2. 解析为JsonNode对象:可以通过JsonNode获取嵌套对象的属性,然后再存储到实体类中;
  3. 配置反序列化类:第2种的升级版,将JsonNode对应的解析代码封装到单独的类中,然后通过@JsonDeserialize进行解析;
0

评论区