我在Springboot应用程序上工作,暴露了一些不返回原始实体但返回其DTO的终结点。要使用“ org.modelmapper”版本:0.7.4和lombok项目映射我正在工作的所有实体,以避免实现实现获取,设置和其他实用程序。
一切正常,直到我不得不在实体上映射子类列表。源实体是这样的(我删除了一些属性和休眠注释,因为在示例中它们是不必要的):
package com.pfi.repository.entity.sport;
import com.pfi.repository.entity.address.Address;
import lombok.*;
import java.util.List;
@Getter
@Setter
@EqualsAndHashCode
@AllArgsConstructor
@NoArgsConstructor
public class SportPlace {
private Long id;
private List<AbstractSportField> sportFields;
}
目标DTO是:
package dto.sport;
import lombok.*;
import java.util.List;
@Getter
@NoArgsConstructor
@Setter
public class SportPlaceDTO {
private Long id;
private List<AbstractSportFieldDTO> sportFields;
}
AbstractSportFieldDTO和AbstractSportField都是具有两个可能的子类的抽象类:
package dto.sport;
import dto.reserve.AbstractReserveDTO;
import java.util.List;
public abstract class AbstractSportFieldDTO {
protected Long id;
protected List<AbstractReserveDTO> reserves;
public AbstractSportFieldDTO() {
}
public AbstractSportFieldDTO(Long id, List<AbstractReserveDTO> reserves) {
this.id = id;
this.reserves = reserves;
}
public Long getId() {
return id;
}
public AbstractSportFieldDTO setId(Long id) {
this.id = id;
return this;
}
public List<AbstractReserveDTO> getReserves() {
return reserves;
}
public AbstractSportFieldDTO setReserves(List<AbstractReserveDTO> reserves) {
this.reserves = reserves;
return this;
}
}
第一个DTO子类是:
package dto.sport;
import dto.reserve.AbstractReserveDTO;
import java.util.List;
public class ComboSportFieldDTO extends AbstractSportFieldDTO {
private List<SportFieldDTO> sportFields;
public ComboSportFieldDTO(List<SportFieldDTO> sportFields) {
this.sportFields = sportFields;
}
public ComboSportFieldDTO(Long id, List<AbstractReserveDTO> reserves, List<SportFieldDTO> sportFields) {
super(id, reserves);
this.sportFields = sportFields;
}
public ComboSportFieldDTO() {
super();
}
public List<SportFieldDTO> getSportFields() {
return sportFields;
}
public void setSportFields(List<SportFieldDTO> sportFields) {
this.sportFields = sportFields;
}
}
第二个DTO子类是:
package dto.sport;
import dto.reserve.AbstractReserveDTO;
import java.util.List;
public class SportFieldDTO extends AbstractSportFieldDTO {
private Boolean joineable;
public SportFieldDTO(Long id, List<AbstractReserveDTO> reserves, Boolean joineable) {
super(id, reserves);
this.joineable = joineable;
}
public SportFieldDTO() {
super();
}
public Boolean getJoineable() {
return joineable;
}
public void setJoineable(Boolean joineable) {
this.joineable = joineable;
}
}
那么实体是:
package com.pfi.repository.entity.sport;
import com.pfi.repository.entity.reserve.AbstractReserve;
import java.util.List;
public abstract class AbstractSportField {
protected Long id;
protected List<AbstractReserve> reserves;
public AbstractSportField(Long id, List<AbstractReserve> reserves) {
this.id = id;
this.reserves = reserves;
}
public AbstractSportField() {
}
public Long getId() {
return id;
}
public AbstractSportField setId(Long id) {
this.id = id;
return this;
}
public List<AbstractReserve> getReserves() {
return reserves;
}
public AbstractSportField setReserves(List<AbstractReserve> reserves) {
this.reserves = reserves;
return this;
}
}
第一个子类是:
package com.pfi.repository.entity.sport;
import com.pfi.repository.entity.reserve.AbstractReserve;
import java.util.List;
public class ComboSportField extends AbstractSportField {
private List<SportField> sportFields;
public ComboSportField(Long id, List<AbstractReserve> reserves, List<SportField> sportFields) {
super(id, reserves);
this.sportFields = sportFields;
}
public ComboSportField(){
super();
}
public List<SportField> getSportFields() {
return sportFields;
}
public ComboSportField setSportFields(List<SportField> sportFields) {
this.sportFields = sportFields;
return this;
}
}
最后一个子类是:
package com.pfi.repository.entity.sport;
import com.pfi.repository.entity.reserve.AbstractReserve;
import javax.persistence.Entity;
import java.util.List;
public class SportField extends AbstractSportField {
private Boolean joineable;
public SportField(Long id, List<AbstractReserve> reserves, Boolean joineable) {
super(id, reserves);
this.joineable = joineable;
}
public SportField(){
super();
}
public Boolean getJoineable() {
return joineable;
}
public SportField setJoineable(Boolean joineable) {
this.joineable = joineable;
return this;
}
}
当我尝试将SportPlace的实例映射到SportPlaceDTO时,如下所示:
modelMapper.map(sportPlace, SportPlaceDTO.class)
sportPlace包含给定的6个Sportfield,它们是子类的实例。模型映射器将抛出(在列表的6个元素上):
无法实例化目标dto.sport.AbstractSportFieldDTO的实例。确保dto.sport.AbstractSportFieldDTO具有非私有的无参数构造函数。
在阅读有关如何在Modelmapper上映射子类的信息时,我发现设置了TypeMap,它可以在这样的类上设置特定的映射:
modelMapper.createTypeMap(ComboSportField.class,ComboSportFieldDTO.class);
因此,我创建了一个构建器来配置像这样的模型映射器
package com.pfi.repository.builder;
import com.pfi.repository.entity.*;;
import dto.reserve.*;
import dto.sport.*;
import org.modelmapper.ModelMapper;
import org.modelmapper.convention.MatchingStrategies;
import org.springframework.stereotype.Service;
@Service
public class MapperBuilder {
public ModelMapper buildModelMapper() {
ModelMapper modelMapper = new ModelMapper();
modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
mapEntitiesToDTO(modelMapper);
mapDTOToEntities(modelMapper);
return modelMapper;
}
private void mapEntitiesToDTO(final ModelMapper modelMapper){
modelMapper.createTypeMap(ComboSportField.class, ComboSportFieldDTO.class);
modelMapper.createTypeMap(SportField.class, SportFieldDTO.class);
modelMapper.createTypeMap(Reserve.class, ReserveDTO.class);
modelMapper.createTypeMap(AppReserve.class, AppReserveDTO.class);
}
private void mapDTOToEntities(final ModelMapper modelMapper){
modelMapper.createTypeMap(ComboSportFieldDTO.class, ComboSportField.class);
modelMapper.createTypeMap(SportFieldDTO.class, SportField.class);
modelMapper.createTypeMap(ReserveDTO.class, Reserve.class);
modelMapper.createTypeMap(AppReserveDTO.class, AppReserve.class);
}
}
当我这样创建控制器时,我会使用构建器:
@Autowired
protected MapperBuilder mapperBuilder;
BaseController(){
this.getLogger();
}
@PostConstruct
public void buildMapper(){
modelMapper = mapperBuilder.buildModelMapper();
}
我不知道还能做些什么来映射子类。
有人知道如何解决这个问题吗?
谢谢!
答案 0 :(得分:0)
我终于在一些朋友的帮助下解决了这个问题,并在此站点上提出了另一个问题。
我的解决方案
另一位开发人员发布了与我的Here类似的问题。
本文推荐使用typeMap
(但不是我所使用的)和“转换器”声明。当子类尝试映射到AbstractClassDTO
时,必须实例化subclassDTO
。
赞:
public ModelMapper buildModelMapper() {
ModelMapper modelMapper = new ModelMapper();
modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
mapEntitiesToDTO(modelMapper);
mapDTOToEntities(modelMapper);
return modelMapper;
}
private void mapEntitiesToDTO(final ModelMapper modelMapper) {
modelMapper.createTypeMap(ComboSportField.class, AbstractSportFieldDTO.class)
.setConverter(converterWithDestinationSupplier(ComboSportFieldDTO::new));
modelMapper.createTypeMap(SportField.class, AbstractSportFieldDTO.class)
.setConverter(converterWithDestinationSupplier(SportFieldDTO::new));
}
private void mapDTOToEntities(final ModelMapper modelMapper) {
modelMapper.createTypeMap(ComboSportFieldDTO.class, AbstractSportField.class)
.setConverter(converterWithDestinationSupplier(ComboSportField::new));
modelMapper.createTypeMap(SportFieldDTO.class, AbstractSportField.class)
.setConverter(converterWithDestinationSupplier(SportField::new));
}
private < S, D > Converter < S, D > converterWithDestinationSupplier(Supplier << ? extends D > supplier) {
return ctx - > ctx.getMappingEngine().map(ctx.create(ctx.getSource(), supplier.get()));
}
当我测试此配置时,它仍然不起作用。然后,我发现发布最后一个问题的同一开发人员在modelmapper
GitHub存储库here上发布了一个问题。最后的评论报告typeMap
具有继承性已在ModelMapper 1.0.0 上发布,我发现我正在使用版本 0.7.4 。>
因此我将版本更新为当前的(2.3.5),此版本开始起作用。 Link to maven repo.
我希望我的描述可以对遇到同样问题的人有所帮助。谢谢!