初始情况
使用JDK 13的当前1.5.0.Beta2 MapStruct版本。
域模型
class Wrapper {
private Fruit fruit;
}
abstract class Fruit {
private int weight;
/* ... */
}
class Apple extends Fruit {
/* ... */
}
class Banana extends Fruit {
/* ... */
}
(省略了相应的1:1 DTO(
映射器
Wrapper类的映射器
@Mapper(uses = {FruitMapper.class})
public interface WrapperMapper {
WrapperDto map(Wrapper wrapper)
}
水果类映射器
抽象Fruit
类的MapStructMapper
,带有方法签名和注释:
@Mapper(subclassExhaustiveStrategy = SubclassExhaustiveStrategy.RUNTIME_EXCEPTION /*...*/)
public interface FruitMapper {
@SubclassMapping(source = Apple.class, target = AppleDto.class)
@SubclassMapping(source = Banana.class, target = BananaDto.class)
FruitDto map(Fruit fruit);
}
问题
在引用的抽象类(例如Fruit
的weight
(上的字段需要被忽略之前,上述操作一直很好。将此注释放到WrapperMapper
map
方法中。。。
@Mapping(target = "fruit.weight", ignore = true)
WrapperDto map(Wrapper wrapper)
导致The return type FruitDto is an abstract class or interface. Provide a non abstract / non interface result type or a factory method.
编译错误。
问题
有没有一种方法可以跳过MapStruct映射中的字段,而不会出现编译错误?
原因
结果是,因为您在WrapperMapper上指定了它,所以它不会直接使用FruitMapper。相反,WrapperMapper实现将生成一个新的映射方法来映射水果。MapStruct在这次尝试中失败,并给出编译错误。
解决方案
如果您将忽略添加到FruitMapper,它将继承它到两个子类映射:
@SubclassMapping( source = Apple.class, target = AppleDto.class )
@SubclassMapping( source = Banana.class, target = BananaDto.class )
@Mapping( target = "weight", ignore = true )
FruitDto map( Fruit fruit );
如果你想有一个有权重的映射和一个没有权重的映射,你可以将@org.mapstruct.Named
注释添加到没有权重的贴图中,然后在WrappedMapper中使用它。
像这样:
@Mapper(subclassExhaustiveStrategy = SubclassExhaustiveStrategy.RUNTIME_EXCEPTION /*...*/)
public interface FruitMapper {
@SubclassMapping( source = Apple.class, target = AppleDto.class )
@SubclassMapping( source = Banana.class, target = BananaDto.class )
FruitDto map( Fruit fruit );
@SubclassMapping( source = Apple.class, target = AppleDto.class )
@SubclassMapping( source = Banana.class, target = BananaDto.class )
@Mapping( target = "weight", ignore = true )
@Named( "NoWeights" )
FruitDto map( Fruit fruit );
}
@Mapper(uses = {FruitMapper.class})
public interface WrapperMapper {
@Mapping( target = "fruit", qualifiedByName = "NoWeights" )
WrapperDto map(Wrapper wrapper)
}