使用提供程序和不可变对象进行深度映射

时间:2016-09-09 08:27:26

标签: java spring-mvc dto modelmapper

我有一个这样的模型:

public class PersonDto {

    private CarDto car;

    public CarDto getCar() {
        return car;
    }

    public void setCar(CarDto car) {
        this.car = car;
    }

    public static class CarDto {

        private String model;

        private String color;

        public String getModel() {
            return model;
        }

        public void setModel(String model) {
            this.model = model;
        }

        public String getColor() {
            return color;
        }

        public void setColor(String color) {
            this.color = color;
        }
    }
}

VO是不可改变的:

public class PersonVo {

    private final CarDto car;

    public PersonVo(CarDto car) {
        super();
        this.car = car;
    }

    public CarDto getCar() {
        return car;
    }

    public static class CarDto {

        private final String model;

        private final String color;

        public CarDto(String model, String color) {
            super();
            this.model = model;
            this.color = color;
        }

        public String getModel() {
            return model;
        }

        public String getColor() {
            return color;
        }   
    }
}

使用ModelMapper提供商是否可以轻松地将此方案从Dto转换为Vo?

我无法使用PersonVo的一个提供程序弄明白,因为当我创建新对象时,我不知道如何解析CarDto ...

public class PersonVoProvider implements Provider<PersonVo> {

    public PersonVo get(org.modelmapper.Provider.ProvisionRequest<PersonVo> request) {
        PersonDto source = PersonDto.class.cast(request.getSource());
        return new PersonVo(car); ????????????
    }
}

2 个答案:

答案 0 :(得分:1)

要将一个实例转换为另一个不可更改的实例,请执行以下步骤(总结:1。创建Provider,2。创建Converter,3。将两者都添加到ModelMapper configuration) :

  1. 首先使用Provider类创建一个AbstractProvider以避免实例化目标错误(Failed to instantiate instance of destination com.example.pregunta.PersonVo. Ensure that com.example.pregunta.PersonVo has a non-private no-argument constructor)。您的Provider应该实例化您的不可变类(在您的情况下为PersonVo),甚至属性都是最终的,具有您想要的值,因为此实例化只是为了避免实例化错误。例如:

    Provider<PersonVo> providerVo = new AbstractProvider<PersonVo>() {
    
        @Override
        protected PersonVo get() {
            PersonVo.CarDto carDto = new PersonVo.CarDto("", "");
            PersonVo personVo = new PersonVo(carDto);
    
            return personVo;
        }
    };
    
  2. 然后,您需要创建一个包含来源Converter和目标PersonDto的{​​{1}}。用手将一个实例转换为另一个实例,如下一个示例所示:

    PersonVo
  3. 最后,需要将提供程序和转换器添加到Converter<PersonDto, PersonVo> converterDtoToVo = new Converter<PersonDto, PersonVo>() { @Override public PersonVo convert(MappingContext<PersonDto, PersonVo> context) { PersonDto dto = context.getSource(); String color = dto.getCar().getColor(); String model = dto.getCar().getModel(); PersonVo.CarDto carVo = new PersonVo.CarDto(color, model); PersonVo vo = new PersonVo(carVo); return vo; } }; 实例配置中:

    ModelMapper
  4. 测试

    我已经尝试过这个例子而且效果很好:

    ModelMapper mapper = new ModelMapper();
    mapper.getConfiguration().setProvider(providerVo);
    mapper.addConverter(converterDtoToVo);
    

    输出:

      

    PersonVo [car = CarDto [model = blue,color = Picasso]]

答案 1 :(得分:0)

该示例使用lombok immutable对象解决了该问题,并使用modelMapper

嵌套了immutable

唯一的事情是我们必须将accessLevel设置为private并将构造函数声明为private以保持不变性,lombok为我们注释。 请参阅以下示例:

首先定义modelMapper,将accesLevel设置为private

 ModelMapper modelMapper = new ModelMapper();
    modelMapper.getConfiguration()
            .setFieldMatchingEnabled(true)
            .setFieldAccessLevel(Configuration.AccessLevel.PRIVATE);

和不可变对象:

@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Value
@Builder
public class UserDto {

    private final Long id;

    private final String uid;

    private final String description;

    private final boolean enabled;

    @Singular
    private final Set<GroupUserDto> userGroups;
}

@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Builder
public class GroupUserDto {

    private Long id;

    private String name;

    private String description;

    private String comments;

    private boolean enabled;
}

最后,使用Builder父类调用modelMapper.map可以正常工作。映射的所有字段都包含嵌套的immutable dto

UserDto dto = modelMapper.map(user,UserDto.UserDtoBuilder.class).build();