java实体类转换有没有更优雅的方式?

常规的转换方式:

a.setId(b.getId());
a.setUserName(b.getName());

当类中的成员变量非常多,几十个,这种方式就会变得非常糟糕,且易出错,不易排查,
有没有更好的方式来解决这个问题呢?

阅读 18.5k
7 个回答

BeanUtils:
public static void copyProperties(java.lang.Object dest, java.lang.Object orig) throws java.lang.IllegalAccessException, java.lang.reflect.InvocationTargetException;

其中 dest是目标,orig是最初的
Spring的工具类

属性少的话,直接set即可。

如果属性多的话,可以考虑使用Apache中的Bean工具包,主要使用 BeanUtils.copyProperties(Object dest,Object orig) 和 PropertyUtils.copyProperties(Object dest,Object orig),原理无非是反射读取到属性列表,然后循环赋值,主要注意的只拷贝dest和orig的相同的名称的字段,比如orig有一个userName属性,dest有一个userName属性,则orig的userName会赋值到dest的userName上。

我看你的给你的例子name赋值到userName这种情况,上面的工具就不适用了,我们简单做一个转化,上面的工具类可以适用。请看例子:

public class Original{
    private Integer id;
    
    private String name;
    
    private String desc;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    @Override
    public String toString() {
        return "Original [id=" + id + ", name=" + name + ", desc=" + desc + "]";
    }
}


public class Dest{
    
    private Integer id;
    
    private String userName;
    
    private String desc;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }
    @Override
    public String toString() {
        return "Dest [id=" + id + ", userName=" + userName + ", desc=" + desc
                + "]";
    }
}

import org.apache.commons.beanutils.PropertyUtils;
public class Test {
    
    public static void main(String[] args) throws Exception {
        Original o = new Original();
        o.setId(7);
        o.setName("七夕快乐");
        o.setDesc("老婆给我最好的七夕礼物是给我独处的一天");
        Dest d = new Dest();
        PropertyUtils.copyProperties(d, o);
        System.out.println(d);//Dest [id=7, userName=null, desc=老婆给我最好的七夕礼物是给我独处的一天]
    }
}

由于d中userName属性和original中的name属性名称不一致,工具也知道怎么映射,这个时候我们在dest类中添加一个public void setName(String userName){this.userName = userName;}方法,
然后打印下就正确了。[id=7, userName=七夕快乐, desc=老婆给我最好的七夕礼物是给我独处的一天]

一般bean直接的拷贝,都是有很多属性名称相同的,稍微几个不同,用上面的方法即可,如果有很多的属性名不同,那可以自己写一个工具类,实现映射配置。

a.initFromB(b)?

你可以试试Bean拷贝,但是最传统的方法速度是最快的

这个问题我也想知道、大概最优雅的方式最好是点下鼠标右键,然后点个复制就好了,楼主其实可以自己写个idea的插件来满足这个需求。开发插件也不难,几个小时就可以搞定入门到一个简单功能,以后就可以偷懒了。/偷笑

可以试试lombok项目,利用建造者模式来做,使用方式是添加@Builder
也是谷歌代码规范推荐方式:

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

/**
 * Created by echo on 2018/8/17.
 */
@Builder
@Getter
@Setter
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class User {

  private String name;
  private Integer age;
  private String address;

  public static void main(String[] args) {
    User user = User.builder().name("echo").age(28).address("China").build();
    System.out.println(user);
  }
}
User(name=echo, age=28, address=China)

Process finished with exit code 0

你需要的是 MapStrut 这个组件, 因为没使用反射机制,所以性能比BeanUtil 高很多, 俩个实体之间属性或者类型不一致时也支持转换

简单举例:

1.maven 引入 MapStrut 这个组件

2.实体举例

class Good{
    int a;
    int b;
    int c;
    //..... 此处省略1000000个属性
}
class GoodDto{
   int a;
   int b;
   int c
   //此处省略 同Good 差不多的10000001个属性
}

3.定义一个转换接口(不用你实现,组件为你实现实现类)

@Mapper(componentModel = "spring")
public interface GoodDtoMapper {

     GoodDto from(Good good);
     
}

4.在需要转换的类中

class GoodController{
  
   @Autowired
   GoodDtoMapper dtoMapper;

   public void list(){
         // 此处获得了一个 Good 对象
        Good good = findGoods();
        
        //转换来了  支持 list to list 转换
        GoodDto dto = dtoMapper.from(good)

   }

}

例子1:
https://blog.csdn.net/lu_ckid...

例子2:

https://segmentfault.com/a/11...

例子3:
https://www.jianshu.com/p/a04...

推荐问题
宣传栏