我们正在使用不可变框架 http://immutables.github.io/生成所有 DTO。现在我们想将这些对象映射到另一个映射结构 http://mapstruct.org。但生成的 DTO 是不可变的,没有 setter 和构造函数,这与构建器模式相对应。它们仅通过静态访问的相应构建器来填充builder()
-method.
相反,我们尝试将 DTO1 映射到 DTO2.Builder,如果 mapstruct 能够识别 Builder 中的 setter,则该方法可以工作,但它们没有 void 返回类型,而是返回 Builder 本身以实现流畅的串联。
这是示例的代码。
我们有两个接口
@Value.Immutable
public interface MammalDto {
public Integer getNumberOfLegs();
public Long getNumberOfStomachs();
}
and
@Value.Immutable
public interface MammalEntity {
public Long getNumberOfLegs();
public Long getNumberOfStomachs();
}
然后我们就有了mapstruct的Mapper接口:
@Mapper(uses = ObjectFactory.class)
public interface SourceTargetMapper {
SourceTargetMapper MAPPER = Mappers.getMapper( SourceTargetMapper.class );
ImmutableMammalEntity.Builder toTarget(MammalDto source);
}
为了让mapstruct找到Builder,我们需要一个Factory:
public class ObjectFactory {
public ImmutableMammalDto.Builder createMammalDto() {
return ImmutableMammalDto.builder();
}
public ImmutableMammalEntity.Builder createMammalEntity() {
return ImmutableMammalEntity.builder();
}
}
为了生成代码,编译器插件被指示使用两个注释处理器:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<annotationProcessorPaths>
<path>
<groupId>org.immutables</groupId>
<artifactId>value</artifactId>
<version>2.2.8</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.2.0.Beta3</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
注意:这会起作用only映射结构版本 > 1.2.x。旧版本在干净构建中存在问题(mvn clean compile
)他们找不到不可变刚刚构建的源。在第二个构建(没有清理)中,他们会找到不可变实现,因为它们在运行注释处理器之前位于类路径上。此错误现已修复。
这就像一个魅力。首先,生成接口的不可变实现,然后 mapstruct 使用它们来生成构建器。
但测试显示没有设置任何属性:
@Test
public void test() {
MammalDto s = ImmutableMammalDto.builder().numberOfLegs(4).numberOfStomachs(3l).build();
MammalEntity t = SourceTargetMapper.MAPPER.toTarget(s).build();
assertThat(t.getNumberOfLegs()).isEqualTo(4);
assertThat(t.getNumberOfStomachs()).isEqualTo(3);
}
断言失败。一看mapstruct生成的mapper就发现它显然没有找到任何setter:
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
//...
)
public class SourceTargetMapperImpl implements SourceTargetMapper {
private final ObjectFactory objectFactory = new ObjectFactory();
@Override
public Builder toTarget(MammalDto source) {
if ( source == null ) {
return null;
}
Builder builder = objectFactory.createMammalEntity();
return builder;
}
}
返回空的构建器。我认为原因是生成的构建器的 setter 实现,因为它返回自身以创建流畅的 API:
public final Builder numberOfLegs(Long numberOfLegs) {
this.numberOfLegs = Objects.requireNonNull(numberOfLegs, "numberOfLegs");
return this;
}
有没有办法让mapstruct找到这些setter?或者甚至是使用构建器处理此类不可变对象的更好方法?
编辑:正如我在评论中所说,我遇到了问题#782 https://github.com/mapstruct/mapstruct/issues/782。在版本 1.2.0.Beta3 中,仍然不支持构建器。但是关于这个主题有很多讨论,因此如果有人遇到同样的问题,关注这个问题可能会很有趣。