我有以下代码将类User的对象转换为类型为GetUserDto的DTO:

public GetUserDto convertToDto(User user) {
    Converter<User, GetUserDto> converter = context -> {
        User source = context.getSource();
        GetUserDto target = new GetUserDto();
        target.setDescription(source.getDescription());
        target.setId(source.getId());
        target.setName(source.getName());
        target.setImageId(source.getImageId());
        return target;
    };
    modelMapper.createTypeMap(User.class, GetUserDto.class).setConverter(converter);
    return modelMapper.map(user, GetUserDto.class);
}


第一次运行正常,但随后对convertToDto的调用引发:

java.lang.IllegalStateException: A TypeMap already exists for class com.boot.cut_costs.model.User and class com.boot.cut_costs.dto.user.ExtendedGetUserDto

我发现了其他与此相关的帖子,其中有人建议对TypeMap进行空检查以检查modelMapper,如果不是null,则不要再次创建它。这不是一个好的解决方案,因为您有成千上万次调用此方法,因此会增加不必要的开销。

有什么好的解决方案吗?

最佳答案

我发现了其他与此相关的帖子,其中一项建议取消检查
  用于ModelMapper的TypeMap,如果不为null,则不要再次创建它。
  这不是一个好的解决方案,就好像您有成千上万的呼叫
  方法会增加不必要的开销。


如果您查看org.modelmapper.ModelMapper.getTypeMap()的代码
org.modelmapper.ModelMapper.createTypeMap(),您将看到
创建一个开销更大的TypeMap,就像调用方法来检索TypeMap一样。

从地图返回对象(如果存在)是直接的:

  public <S, D> TypeMap<S, D> getTypeMap(Class<S> sourceType, Class<D> destinationType) {
    Assert.notNull(sourceType, "sourceType");
    Assert.notNull(destinationType, "destinationType");
    return config.typeMapStore.<S, D>get(sourceType, destinationType, null);
  }


虽然添加执行更多的事情。
它创建代理类型,执行同步任务,并在创建TypeMap实例之前进行一些检查,最后将其放入地图中:

  private <S, D> TypeMap<S, D> createTypeMapInternal(S source, Class<S> sourceType,
      Class<D> destinationType, String typeMapName, Configuration configuration) {
    if (source != null)
      sourceType = Types.<S>deProxy(source.getClass());
    Assert.state(config.typeMapStore.get(sourceType, destinationType, typeMapName) == null,
        String.format("A TypeMap already exists for %s and %s", sourceType, destinationType));
    return config.typeMapStore.create(source, sourceType, destinationType, typeMapName,
        (InheritingConfiguration) configuration, engine);
  }


还会调用:

  public <S, D> TypeMap<S, D> create(S source, Class<S> sourceType, Class<D> destinationType,
      String typeMapName, InheritingConfiguration configuration, MappingEngineImpl engine) {
    synchronized (lock) {
      TypeMapImpl<S, D> typeMap = new TypeMapImpl<S, D>(sourceType, destinationType, typeMapName,
          configuration, engine);
      if (configuration.isImplicitMappingEnabled()
          && ImplicitMappingBuilder.isMatchable(typeMap.getSourceType())
          && ImplicitMappingBuilder.isMatchable(typeMap.getDestinationType()))
        new ImplicitMappingBuilder<S, D>(source, typeMap, config.typeMapStore,
            config.converterStore).build();
      typeMaps.put(TypePair.of(sourceType, destinationType, typeMapName), typeMap);
      return typeMap;
    }
  }


因此,检查是否有更有效的解决方案:

if (modelMapper.getTypeMap(User.class,GetUserDto.class) == null){
    modelMapper.createTypeMap(User.class, GetUserDto.class).setConverter(converter);
}
return modelMapper.map(user, GetUserDto.class);


现在,如果您确实希望避免不必要的处理,则可以创建TypeMap并将所有与之关联的转换器设置为在特定类中一次。

public void initTypeMaps(){
        modelMapper.createTypeMap(User.class, GetUserDto.class).setConverter(converterUserAndUserDto);
        modelMapper.createTypeMap(Other.class, GetOtherDto.class).setConverter(converterOtherAndOtherDto);
 ...
}


最后,如果您在短时间内对该方法有数千次调用,并且想要最大程度地减少开销,请不要使用ModelMapper和转换器,而要在两个类之间进行映射。

07-24 18:31