【问题标题】:How to setup ModelMapper for nested to different nested?如何设置 ModelMapper 嵌套到不同的嵌套?
【发布时间】:2019-11-28 05:01:26
【问题描述】:

Flight 对象具有如下属性:

@JsonProperty("OriginLocation")
private Location originLocation;

位置对象如下所示:

@JsonProperty("lat")
private double latitude;
@JsonProperty("lon")
private double longitude;

我正在映射到 FlightDto,其中的属性看起来像这样(注意:FlightDto 将 5 个左右的属性从 Flight 移动到 LocationDto ——这些都自动映射,除了纬度/经度):

private LocationDto origin;

LocationDto 如下所示:

private CoordinatesDto coordinates;

CoordinatesDto 如下所示:

private double latitude;
private double longitude;

所以...除了纬度/经度之外,所有属性都正确映射。映射应该是:

FlightDto.getOrigin().setCoordinates(new CoordinatesDto(Flight.getOriginLocation().getLatitude(),
                             Flight.getOriginLocation().getLongitude());

FlightDto.getOrigin() 中的其他字段以某种方式自动正确映射。

我试过了:

    modelMapper.addMappings(new PropertyMap<Flight, FlightDto>() {
        @Override
        protected void configure() {
            map().getOrigin().setCoordinates(new CoordinatesDto(source.getOriginLocation().getLatitude(),
                                                                    source.getOriginLocation().getLongitude()));
//              map().getDestination().setCoordinates(new CoordinatesDto(source.getDestinationLocation().getLatitude(),
//                                                                       source.getDestinationLocation().getLongitude()));

    }
});

但这实际上在启动时崩溃:

原因:java.lang.NullPointerException: null 在 org.xxx.yyy.flights.models.Location$ByteBuddy$NcO8GjcN.getLongitude(Unknown Source) ~[classes/:na] 在 org.xxx.yyy.config.ModelMapperConfig$2.configure(ModelMapperConfig.java:42) ~[classes/:na] 在 org.modelmapper.PropertyMap.configure(PropertyMap.java:389) ~[modelmapper-2.3.5.jar:na]

我不明白为什么 getLatitude() 有效,但 getLongitude() 不是为了一件事...但是可以说我注释掉了 getLongitude() 和硬编码 1... 看起来像二传手只在启动时调用一次,而不是为每条记录调用一次。

我还看到了一些使用 TypeMap 的示例,但我看不到如何从 1 个嵌套级别映射到 2 个嵌套级别,因为 LocationDto 已正确创建和填充,但 LocationDto.Coordinates 不是。

【问题讨论】:

    标签: java spring modelmapper


    【解决方案1】:

    我认为您在这里有两个问题,请参见下面的代码和 cmets:

    // When you have different field names you should tell it to ModelMapper like this
    mm.createTypeMap(Flight.class, FlightDto.class).addMapping(Flight::getOriginLocation,
        FlightDto::setOrigin);
    
    // And when you do not have 'clear' association or mapping is not in the `same 
    // level` mapping can not be guessed so you need to tell it explicitly like 
    // (this is something near to what you tried already)
    mm.addMappings(new PropertyMap<Location, LocationDto>() {
        @Override
        protected void configure() {
            map().getCoordinates().setLatitude(source.getLatitude());
            map().getCoordinates().setLongitude(source.getLongitude());
        }
    });
    

    在告诉这个(这两个)之后——假设我正确理解了你的模型/dto 结构——ModelMapper 能够进行映射。

    【讨论】:

      【解决方案2】:

      我在使用 modelmapper 时遇到了类似的问题。我有 pojo,它具有一组相同类型的属性,例如:

      private Registrar createdBy;
      private Registrar updatedBy;
      private Registrar ownedBy;
      

      ModelMapper 仅保存一个 Registrar 实例(遇到的第一个实例,即使它为空)。

      我的解决方案是使用Converters 并使用原始类型来映射原始值。

      然后映射看起来像:

      addMappings(new PropertyMap<DomainDTO, Domain>() {
          @Override
          protected void configure() {
              using(RegistrarFromId).map(source.getRegistrarId()).setRegistrar(null);
              using(RegistrarFromId).map(source.getUpdaterId()).setUpdater(null);
              using(RegistrarFromId).map(source.getCreatorId()).setCreator(null);
          }
      });
      

      使用此转换器:

      private final Converter<Long, Registrar> RegistrarFromId = context -> {
          MappingContext<?, ?> parent = context.getParent();
      
          if (parent.getDestinationType() == Registrar.class
                  && parent.getDestination() != null) {
              Registrar registrar = (Registrar) parent.getDestination();
              return registrar;
          }
      
          Long id = context.getSource();
          Registrar registrar = registrarDaoService.findById(id);
          if (registrar == null) {
              throw new MappingException(String.format("Registrar %s not found", id));
          }
          return registrar;
      };
      

      我希望这可以激发您找到解决方案。

      【讨论】:

      • 从我的角度来看,ModelMapper 仅适用于大多数简单的情况。一旦你的模型变得更复杂,ModelMapper 就太复杂了,无法使用。代码也很糟糕。就我而言,我仍在使用它,但我自己实现映射所花费的时间不到使用 ModelMapper 的一半。而且我的映射中仍然存在未解决的边缘情况;所以它在路线图上编写自己的实现。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-06
      • 2016-06-21
      • 2018-06-03
      • 1970-01-01
      • 2018-07-19
      相关资源
      最近更新 更多