java ModelMapper:匹配多个源属性层次结构

p8h8hvxi  于 12个月前  发布在  Java
关注(0)|答案(6)|浏览(166)

我无法解决modelMapper错误。你知道问题出在哪里吗?
注意:鉴于java.sql.Time没有非参数构造函数,我没有找到比编写转换器更好的方法

org.modelmapper.ConfigurationException: ModelMapper configuration errors:

1) The destination property 
biz.models.CarWash.setSecondShift()/java.util.Date.setTime() matches 
multiple source property hierarchies:

biz.dto.CarWashDTO.getFirstShift()/java.time.LocalTime.getSecond()
biz.dto.CarWashDTO.getSecondShift()/java.time.LocalTime.getSecond()

字符串
错误是由这段代码造成的

@SpringBootTest
@RunWith(SpringRunner.class)
public class CarWashDTO2CarWash {

@Autowired
protected ModelMapper modelMapper;

@Test
public void testCarWashDTO2CarWash_allFiledShouldBeConverted(){
    CarWashDTO dto = CarWashDTO.builder()
            .name("SomeName")
            .address("SomeAddress")
            .boxCount(2)
            .firstShift(LocalTime.of(9, 0))
            .secondShift(LocalTime.of(20, 0))
            .phoneNumber("5700876")
            .build();

    modelMapper.addConverter((Converter<CarWashDTO, CarWash>) mappingContext -> {
        CarWashDTO source = mappingContext.getSource();
        CarWash destination = mappingContext.getDestination();
        destination.setId(source.getId());
        destination.setFirstShift(source.getFirstShift() == null ? null : Time.valueOf(source.getFirstShift()));
        destination.setSecondShift(source.getSecondShift() == null ? null : Time.valueOf(source.getSecondShift()));
        destination.setEnable(true);
        destination.setAddress(source.getAddress());
        destination.setBoxCount(source.getBoxCount());
        destination.setName(source.getName());
        destination.setDateOfCreation(source.getDateOfCreation());
        return destination;
    });

    final CarWash entity = modelMapper.map(dto, CarWash.class);
    assertNotNull(entity);
    assertEquals(2, entity.getBoxCount().intValue());
    assertEquals("SomeAddress", entity.getAddress());
    assertEquals("SomeName", entity.getName());
}


}
模型Map器bean由下一个配置构建

@Bean
public ModelMapper modelMapper(){
    return new ModelMapper();
}


Dto:

public class CarWashDTO {
private Long id;
private String name;
private String address;
private String phoneNumber;
private Integer boxCount;
private LocalTime firstShift;
private LocalTime secondShift;
private LocalDateTime dateOfCreation;
}


实体(firstShift和secondShift的类型为java.sql.Time):

public class CarWash {
private Long id;
private String name;
private String address;
private String phoneNumber;
private Integer boxCount;
private Time firstShift;
private Time secondShift;
private LocalDateTime dateOfCreation;
private Boolean enable;
private Owner owner;
}

ubof19bj

ubof19bj1#

尝试modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT)

vxqlmq5t

vxqlmq5t2#

这解决了我的问题:modelMapper.getConfiguration().setAmbiguityIgnored(true);

dddzy1tm

dddzy1tm3#

您需要在Bean初始化期间借助PropertyMap自定义ModelMapper配置:http://modelmapper.org/user-manual/property-mapping/

@Bean
public ModelMapper modelMapper(){
    ModelMapper mm = new ModelMapper();

    PropertyMap<CarWashDTO, CarWash> propertyMap = new PropertyMap<CarWashDTO, CarWash> (){
        protected void configure() {
            map(source.getId()).setId(null);
        }
    }

    mm.addMappings(propertyMap);
    return mm;
}

字符串

jdgnovmf

jdgnovmf4#

我不知道当问题被问到的时候,ModelMapper是怎么样的,但是使用转换器应该很简单。而不是为整个类实现转换器,而是将其实现为实际需要转换的类型。比如:

public static Converter<LocalTime, Time> timeConverter = new AbstractConverter<>() {
    @Override
    protected Time convert(LocalTime source) {
        return null == source ? null : Time.valueOf(source);
    }
};

字符串
那么它只是为了:

mm.addConverter(timeConverter);


猜猜你是否知道如何使用Spring或EJB将其添加到配置中。

ef1yzkbh

ef1yzkbh5#

这解决了我的问题:

modelMapper.getConfiguration().setAmbiguityIgnored(true);

字符串

zlwx9yxi

zlwx9yxi6#

如果使用MatchingStrategies.STRICTsetAmbiguityIgnored(true)的建议解决方案不是一个选项(例如,当只有一个ModelMapper示例时,它已经执行了许多不同的Map,因此潜在的副作用可能是一个问题),那么还有另一个解决方案。
而不是使用createTypeMap创建TypeMap(或者typeMap,它的工作原理非常微妙,但基本上是相同的),使用emptyTypeMap。这完全禁用了所有隐式Map的构造,这是在类似命名属性的情况下导致那些二义性问题的原因。在此基础上,然后你可以(也必须)显式地应用所有Map。我猜这可以比作只为这个特定的TypeMap启用STRICT匹配。
所以对于洗车的例子,使用fluent界面,它会是这样的:

modelMapper.emptyTypeMap(CarWashDTO.class, CarWash.class)
           .addMapping(CarWashDTO::getFirstShift, CarWash::setFirstShift) 
           .addMapping(CarWashDTO::getSecondShift, CarWash::setSecondShift) 
           [...]

字符串
我自己还没有尝试过,但是甚至可以 * 只 * 为冲突的属性显式指定Map,而对其余的属性再次使用隐式Map。这将通过使用implicitMappings()终止链来实现。

相关问题