使用mapstruct中的构建器(使用不可变注释处理器)将对象映射到不可变对象 [英] Mapping an object to an immutable object with builder (using immutables annotation processor) in mapstruct

查看:698
本文介绍了使用mapstruct中的构建器(使用不可变注释处理器)将对象映射到不可变对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们正在使用 不可变框架 来生成所有DTO。现在,我们想使用 mapstruct 将这些对象相互映射。但是生成的DTO是不可变的,并且没有对应于构建器模式的setter和构造函数。它们只能通过静态 builder()方法访问的相应构建器进行填充。

We are using the immutables framework to generate all DTOs. Now we would like to map these objects one to another with mapstruct. But the generated DTOs are immutable and have no setters and no constructor, corresponding to the builder pattern. They are only filled through the corresponding builder accessed by a static builder()-method.

我们改为尝试将DTO1映射到DTO2.Builder,如果mapstruct可以识别Builder中的setter,但它们没有void返回类型,但可以将Builder本身进行流畅的串联,则可以工作。

We instead tried to map DTO1 to DTO2.Builder which would work if mapstruct would recognize the setter in the Builder but these do not have void return type but return the Builder itself for fluent concatenation.

因此,这是示例代码。

我们有两个接口

@Value.Immutable
public interface MammalDto {
  public Integer getNumberOfLegs();
  public Long getNumberOfStomachs();
}

@Value.Immutable
public interface MammalEntity {
  public Long getNumberOfLegs();
  public Long getNumberOfStomachs();
}

然后我们有了mapstruct的Mapper界面:

Then we have the Mapper interface for mapstruct:

@Mapper(uses = ObjectFactory.class)
public interface SourceTargetMapper {
  SourceTargetMapper MAPPER = Mappers.getMapper( SourceTargetMapper.class );

  ImmutableMammalEntity.Builder toTarget(MammalDto source);
}

要让mapstruct查找生成器,我们需要一个工厂:

For mapstruct to find the Builder we need a Factory:

public class ObjectFactory {

  public ImmutableMammalDto.Builder createMammalDto() {
    return ImmutableMammalDto.builder();
  }

  public ImmutableMammalEntity.Builder createMammalEntity() {
    return ImmutableMammalEntity.builder();
  }
}

为了生成代码,指示了编译器插件使用两个注释处理器:

In order to generate the code the compiler plugin was instructed to use both annotation processors:

<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>

注意:此选项仅在 且mapstruct版本> 1.2.x时有效。较旧的版本在一个干净的版本( mvn clean编译)中存在问题,即它们找不到刚构建的不可变源。在第二个构建中(无需清理),他们将找到不可变的实现,因为它们在运行注释处理器之前位于类路径上。该错误现已修复。

Note: This will work only with mapstruct version > 1.2.x. Older versions have the problem in a clean build (mvn clean compile) that they do not find the sources that immutables just built. In a second build (without clean) they would find the immutables implementations because they were on the classpath before annotation processors were run. This bug is fixed now.

这就像一个护身符。首先,生成交互的不可变实现,然后mapstruct使用它们来生成生成器。

This works like a charm. First the Immutable implementations of the interfactes are generated and mapstruct uses them to generate the builder.

但是测试显示未设置任何属性:

But the Test shows that no properties are set:

@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生成的映射器,它显然没有找到任何设置器:

The asserts fail. One look at the mapper generated by mapstruct shows that it has obviously not found any setters:

@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:

The empty builder is returned. I think the reason is the setter implementation of the generated builder because it returns itself to create a fluent API:

public final Builder numberOfLegs(Long numberOfLegs) {
  this.numberOfLegs = Objects.requireNonNull(numberOfLegs, "numberOfLegs");
  return this;
}

有没有办法让mapstruct找到这些设置者?甚至还有一个更好的方法来与生成器一起处理这种不可变的对象?

Is there a way to let mapstruct find these setters? Or even a better way to deal with such immutable objects with builders?

编辑:正如我在评论中所述,我遇到了问题#782 。在1.2.0版中,仍不支持Beta3构建器。但是,对此主题进行了多次讨论,因此如果一个人遇到相同的问题,则可能很有趣。

As I stated in the comment I ran into Issue #782. In version 1.2.0.Beta3 builders are still not supported. But there are several discussions on this topic so it might be interesting to follow the issue if one has the same problem.

推荐答案

1.3 MapStruct支持不可变。在此处中查找更多详细信息。

Since 1.3 MapStruct supports Immutables. Look here for more details.

这篇关于使用mapstruct中的构建器(使用不可变注释处理器)将对象映射到不可变对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆