扩展现有的 Mapstruct 接口以添加其他映射方法
Extend Existing Mapstruct Interface To Add Additional Mapping Methods
我有一个 Mapstruct 映射器,它已经在我的应用程序当前使用的公共库中定义。我有一个新的映射器方法,我想添加到这个映射器,它是我的应用程序特有的,所以我不想修改原始映射器来添加这个功能。
我曾尝试扩展界面,但我一直 运行 遇到问题。目前使用下面的代码,它会编译,但它会抛出运行时异常,因为 Mapstruct 没有生成 MyMapperExtendedImpl class.
Caused by: java.lang.RuntimeException: java.lang.ClassNotFoundException: Cannot find implementation for 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 也被映射(简化因此不显示成员变量 getters/setters)
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 class 用作映射的源对象
public class SomeObject {
UUID someId;
String name;
String someFieldWeIgnore;
public SomeObject () {}
}
在解决了几个不同的问题之后。我终于让它在生成代码的地方“工作”了,但它不适用于我的用例。我在上面发布的代码中排除了“表达式”的使用,因为当时我认为它不相关,但它导致了最后一个问题。
@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 就可以了(包括所有导入,如果有的话)。我决定只制作一个单独的映射器,而不是完全继承原始映射器。
我有一个 Mapstruct 映射器,它已经在我的应用程序当前使用的公共库中定义。我有一个新的映射器方法,我想添加到这个映射器,它是我的应用程序特有的,所以我不想修改原始映射器来添加这个功能。
我曾尝试扩展界面,但我一直 运行 遇到问题。目前使用下面的代码,它会编译,但它会抛出运行时异常,因为 Mapstruct 没有生成 MyMapperExtendedImpl class.
Caused by: java.lang.RuntimeException: java.lang.ClassNotFoundException: Cannot find implementation for 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 也被映射(简化因此不显示成员变量 getters/setters)
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 class 用作映射的源对象
public class SomeObject {
UUID someId;
String name;
String someFieldWeIgnore;
public SomeObject () {}
}
在解决了几个不同的问题之后。我终于让它在生成代码的地方“工作”了,但它不适用于我的用例。我在上面发布的代码中排除了“表达式”的使用,因为当时我认为它不相关,但它导致了最后一个问题。
@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 就可以了(包括所有导入,如果有的话)。我决定只制作一个单独的映射器,而不是完全继承原始映射器。