【问题标题】:Extend Existing Mapstruct Interface To Add Additional Mapping Methods扩展现有 Mapstruct 接口以添加其他映射方法
【发布时间】:2020-07-10 05:20:09
【问题描述】:

我有一个 Mapstruct 映射器,它已经在我的应用程序当前使用的公共库中定义。我有一个新的映射器方法我想添加到这个映射器中,它特定于我的应用程序,所以我不想修改原始映射器来添加这个功能。

我曾尝试扩展界面,但一直遇到问题。目前使用下面的代码,它会编译,但它会抛出运行时异常,因为 Mapstruct 没有生成 MyMapperExtendedImpl 类。

原因:java.lang.RuntimeException:java.lang.ClassNotFoundException:找不到 com.whatever.package.name.MyMapperExtended 的实现

我确实收到了来自 Sonar 的警告,当我尝试通过调用 Mappers.getMapper(MyMapperExtended.class) 访问映射器时,它没有 @Mapper 注释。然后,我通过删除 @MapperConfig 注释并将其替换为父映射器中的相同 @Mapper(imports = { SomeUtilityClass.class }) 来更改 MyMapperExtended.class。代码不再编译,我有一系列错误说无法找到某些变量。这些变量似乎是函数参数,因为名称完全匹配。

如何正确扩展现有的 MyMapper 接口,以便向其添加其他映射方法?

@MapperConfig(uses = MyMapper.class)
public interface MyMapperExtended extends MyMapper {

    default List<ChildClass> someObjectListToChildClassList(List<SomeObject> someList) {
        //Some special logic here and looping which makes it so cannot use the @Mapping annotations
        
        //Call the mapper for the parent so that the base properties are mapped 
        ParentClass mappedParentClass = this.someObjectListToParentClassList(someList);
        
        //Uses a copy constructor to copy over the mapped base properties
        ChildClass myChildClass = new ChildClass(mappedParentClass);
        myChildClass.setExtraProperty("whatever value");

        return myChildClass;
    }
}

来自共享公共库的映射器

@Mapper(imports = { SomeUtilityClass.class })
public interface MyMapper {
    @Mapping(target = "id", source = "someId")
    @Mapping(target = "name", source = "name")
    @Mapping(target = "someFieldWeIgnoreWhileMapping", ignore = true)
    ParentClass someObjectListToParentClass(SomeObject someObject)

    List<ParentClass> someObjectListToParentClassList(List<SomeObject> someList)
}

类 ParentClass 和 ChildClass 也被映射(简化,因此不显示成员变量的 getter/setter)

public class ParentClass {
    UUID id; 
    String name;
    String someFieldWeIgnoreWhileMapping;

    public ParentClass() {}
}

public class ChildClass {
    String extraProperty; 

    public ChildClass(ParentClass parent) {
        super();
        this.setId(parent.getId());
        this.setName(parent.getName());
    }
}

SomeObject 类被用作映射的源对象

public class SomeObject {
    UUID someId; 
    String name; 
    String someFieldWeIgnore; 

    public SomeObject () {}
}

【问题讨论】:

    标签: java inheritance mapstruct


    【解决方案1】:

    在解决了几个不同的问题之后。我终于让它在生成代码的地方“工作”了,但它不适用于我的用例。我从上面发布的代码中排除了“表达式”的使用,因为当时我认为它不相关,但它导致了最终问题。

    @Mapping(target = "id", source = "someId")
    @Mapping(target = "name", source = "name")
    @Mapping(target = "someFieldWeIgnoreWhileMapping", ignore = true)
    @Mapping(expression = "java(SomeUtilityClass.doSomethingHelpful(someObject.getSpecialField()))", target = "specialField")
    ParentClass someObjectListToParentClass(SomeObject someObject);
    

    从 Mapstruct 生成的代码看起来像这样。

    public ParentClass someObjectListToParentClass(SomeObject arg0) {
        if (arg0 == null) {
            return null;
        } else { 
            ParentClass parentClass = new ParentClass();
            parentClass.setId(arg0.getId()); 
            parentClass.setName(arg0.getName());
    
            //The problem. 
            //It puts the variable name as "someObject" because that's what the expression is hardcoded as in the Interface, but the varible is actually arg0 here 
            parentClass.setSpecialField(SomeUtilityClass.doSomethingHelpful(someObject.getSpecialField()));
        }
    }
    

    对于没有像我这样的场景的任何人,看起来只是添加 @Mapper 应该可以工作(包括所有导入,如果你有的话)。我决定只制作一个单独的映射器,而不是从原始映射器继承。

    【讨论】:

      猜你喜欢
      • 2021-08-03
      • 2023-03-18
      • 1970-01-01
      • 1970-01-01
      • 2021-10-09
      • 2016-09-17
      • 2021-12-25
      • 2021-11-19
      • 1970-01-01
      相关资源
      最近更新 更多