通过Jackson序列化反序列化解决对象拷贝问题

问题背景

最近在项目中遇到一个对象拷贝的问题,无法直接使用BeanUtils.copyProperties(a, b);且使用get set比较麻烦。拷贝涉及到的两个类信息如下:

// 省略get set方法
public class A {

    private int id;

    private String name;

    private List<A> list;

    private Date birthday;

    private LocalDateTime localDateTime;

}
// 省略get set方法
public class B {

    private int bId;

    private String bName;

    private List<B> bList;

    private Date myBirthday;

    private LocalDateTime localDateTime;

}

业务场景

  1. 这是一个SpringBoot工程,A是通过feign调用其他服务获取到的,B是本工程的一个Controller接口的返回值
  2. A和B里面的字段其实是一模一样的,B的字段和值来源均为A
    1. 没有直接使用A的原因是:Controller接口的出入参和feign接口的出入参不共用一套,两者解耦开,避免feign接口出入参有修改,controller接口未做调整,前端或其他调controller接口的服务使用出错
    2. 故而B里面的字段可以命名为id(和A保持一致),或者命名为bId(和A 不一致,但值就是A中id的值)
  3. 由于A里面有个List类型的A,即便把B里面的字段完全命名成和A中的字段一样,直接BeanUtils.copyProperties(a, b)也未能成功:B里面的List类型的B值为空
  4. 经分析:可以将A序列化为json,再将json串反序列化为B。
    1. 但是id怎么转换成bId呢,jackson已经提供了此类功能,通过@JsonProperty注解给属性起另一个想要的名称进行转换。
    2. 另外也支持时间类型的字段的转换:通过@JsonFormat注解配置日期格式,可以格式化日期属性。
  5. 进而调整B的代码如下:
// 省略get set方法
public class B {

    // @JsonProperty 在序列号和反序列化时使用,作用于属性上,作用是把该属性的名称序列化成另一个自己想要的名称。
    @JsonProperty("id")
    private int bId;

    @JsonProperty("name")
    private String bName;

    @JsonProperty("list")
    private List<B> bList;

    // @JsonFormat 格式化日期属性
    @JsonProperty("birthday")
    @JsonFormat(pattern = "yyyy年MM月dd日")
    private Date myBirthday;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime localDateTime;

}

这样就可以通过json序列化、反序列化实现了对象的拷贝List<A>转换成List<B>同理,也可以这样转换。

 @Test
    public void t1() {
        A a = A.builder().id(1).name("name1").list(
                        Arrays.asList(
                                A.builder().id(10).name("name10").list(
                                                Arrays.asList(
                                                        A.builder().id(100).name("name100").list(new ArrayList<>()).build(),
                                                        A.builder().id(101).name("name101").list(new ArrayList<>()).build()
                                                ))
                                        .build(),
                                A.builder().id(11).name("name11").list(new ArrayList<>()).build())
                )
                .birthday(new Date())
                .localDateTime(LocalDateTime.now())
                .build();
        String str = JacksonUtils.writeAsString(a);

        B b = JacksonUtils.readValue(str, B.class);
        System.out.println(JacksonUtils.writeAsString(b));
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Java 中的序列机制是指将一个对象转换为字节流的过程,也可以将字节流转换为对象。这个过程可以用于数据的传输和存储,也可以用于对象的深度复制。 Java 中的序列机制需要实现 java.io.Serializable 接口,这个接口没有任何方法,只是一个标记接口,用来标记一个类可以被序列。一个类只有实现了 Serializable 接口,才能被序列成字节流或者序列对象。 Java 中序列的实现方式有两种:Java 序列和 JSON 序列。下面分别介绍这两种序列方式。 #### Java 序列 Java 序列是将一个对象转换为字节流的过程,可以使用 ObjectOutputStream 来实现。下面是一个将对象序列为字节流的示例: ```java public class MyClass implements Serializable { private int id; private String name; public MyClass(int id, String name) { this.id = id; this.name = name; } public int getId() { return id; } public String getName() { return name; } } public class Main { public static void main(String[] args) throws IOException { MyClass obj = new MyClass(1, "My Object"); // 将对象序列为字节流 ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); ObjectOutputStream objOut = new ObjectOutputStream(byteOut); objOut.writeObject(obj); byte[] bytes = byteOut.toByteArray(); // 打印字节流 System.out.println(Arrays.toString(bytes)); } } ``` 上面的例子中,MyClass 类实现了 Serializable 接口,这样就可以将 MyClass 对象序列为字节流了。在 Main 类中,将 MyClass 对象序列为字节流,然后打印字节数组。 #### JSON 序列 JSON 序列是将一个对象转换为 JSON 字符串的过程,可以使用 JSON 序列库来实现。常用的 JSON 序列库有 Jackson 和 Gson。下面是一个使用 Gson 序列对象的示例: ```java public class MyClass { private int id; private String name; public MyClass(int id, String name) { this.id = id; this.name = name; } public int getId() { return id; } public String getName() { return name; } } public class Main { public static void main(String[] args) { MyClass obj = new MyClass(1, "My Object"); // 将对象序列为 JSON 字符串 Gson gson = new Gson(); String json = gson.toJson(obj); // 打印 JSON 字符串 System.out.println(json); } } ``` 上面的例子中,MyClass 类没有实现 Serializable 接口,因此不能使用 Java 序列。在 Main 类中,使用 Gson 序列 MyClass 对象为 JSON 字符串,然后打印该字符串。 总的来说,Java 中的序列机制非常灵活和强大,可以用于网络传输、数据存储、对象复制等多个场景,但是需要注意序列序列过程中可能会出现的问题,如版本兼容性、安全性等。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值