使用mapstruct中的构建器(使用不可变注释处理器)将对象映射到不可变对象

2024-01-10

我们正在使用不可变框架 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 中,仍然不支持构建器。但是关于这个主题有很多讨论,因此如果有人遇到同样的问题,关注这个问题可能会很有趣。


您可以配置 Immutables 以在构建器中生成 setter:

@Value.Immutable
@Value.Style(init = "set*")
public interface MammalEntity {
    public Long getNumberOfLegs();
    public Long getNumberOfStomachs();
}

并且不需要ObjectBuilder,可以直接使用生成的Immutable类

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

    ImmutableMammalEntity.Builder toTarget(MammalDto source);
}

您甚至可以在自己的注释中定义这些设置

@Value.Style(init = "set*")
public @interface SharedData {}

并用它代替

@SharedData
@Value.Immutable
public interface MammalEntity {
    public Long getNumberOfLegs();
    public Long getNumberOfStomachs();
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用mapstruct中的构建器(使用不可变注释处理器)将对象映射到不可变对象 的相关文章

  • java中监视目录变化

    我正在使用 WatchService 来监视目录中的更改 特别是目录中新文件的创建 下面是我的代码 package watcher import java nio file import static java nio file Stand
  • Java Logger 未记录到 Netbeans 中的输出

    我正在 Netbeans 中使用 Maven 启动一个 Java 项目 我编写了一些代码来使用 Logger 类进行日志记录 但是 日志记录似乎不起作用 在程序开始时 我运行 Logger getLogger ProjectMainClas
  • java.lang.ClassNotFoundException:javax.mail.MessagingException

    我想使用 eclipse 将电子邮件从我的 gmail 帐户发送到另一个邮件帐户 我使用 apache tomcat 7 0 34 作为我的 Web 服务器 并使用端口 8080 作为 apache 服务器 HTTP 1 1 并使用 JRE
  • 如何在java中将数组值排序为循环格式?

    我的数组值如下 String value 1 2 3 4 5 6 7 8 9 10 假设如果我将值 5 传递给 tat 数组 它应该按如下顺序排序 5 6 7 8 9 10 1 2 3 4 怎么办 有人帮忙吗 感谢你 你需要的就是所谓的轮换
  • Java 的支持向量机?

    我想用Java编写一个 智能监视器 它可以随时发出警报detects即将到来的性能问题 我的 Java 应用程序正在以结构化格式将数据写入日志文件
  • Android:文本淡入和淡出

    我已阅读此 stackoverflow 问题和答案 并尝试实现文本淡入和淡出 Android中如何让文字淡入淡出 https stackoverflow com questions 8627211 how to make text fade
  • Thymeleaf 3 Spring 5 映射加载字符串而不是 HTML

    我正在尝试将 Spring 5 和 Thymeleaf 3 一起配置 我正在 Eclipse 上工作 我使用 全新安装 构建并使用 springboot run 运行应用程序 我已经设置了一个控制器和几个模板 但 Thymeleaf 似乎找
  • 什么是抽象类? [复制]

    这个问题在这里已经有答案了 当我了解抽象类时 我说 WT H 问题 创建一个无法实例化的类有什么意义呢 为什么有人想要这样的课程 什么情况下需要抽象类 如果你明白我的意思 最常见的是用作基类或接口 某些语言有单独的interface构建 有
  • java inputstream 打印控制台内容

    sock new Socket www google com 80 out new BufferedOutputStream sock getOutputStream in new BufferedInputStream sock getI
  • Java 中如何将 char 转换为 int? [复制]

    这个问题在这里已经有答案了 我是Java编程新手 我有例如 char x 9 我需要得到撇号中的数字 即数字 9 本身 我尝试执行以下操作 char x 9 int y int x 但没有成功 那么我应该怎么做才能得到撇号中的数字呢 ASC
  • 如何仅从 Firestore 获取最新更新的数据?

    在 Firestore 上发现任何更改时始终获取整个文档 如何只获取最近更新的数据 这是我的数据 我需要在第一次加载时在聊天中按对象顺序 例如 2018 09 17 30 40 msg和sendby 并且如果数据更新则仅获取新的msg和se
  • 如何在JPanel中设置背景图片

    你好 我使用 JPanel 作为我的框架的容器 然后我真的想在我的面板中使用背景图片 我真的需要帮助 这是我到目前为止的代码 这是更新 请检查这里是我的代码 import java awt import javax swing import
  • 使用 Elastic Beanstalk 进行 Logback

    我在使用 Elastic Beanstalk 记录应用程序日志时遇到问题 我正在 AWS Elastic Beanstalk 上的 Tomcat 8 5 with Corretto 11 running on 64bit Amazon Li
  • 在 Java 中获取并存储子进程的输出

    我正在做一些需要我开始子处理 命令提示符 并在其上执行一些命令的事情 我需要从子进程获取输出并将其存储在文件或字符串中 这是我到目前为止所做的 但它不起作用 public static void main String args try R
  • 如何区分从 Saxon XPathSelector 返回的属性节点和元素节点

    给定 XML
  • let/var 如何解决可变性? [复制]

    这个问题在这里已经有答案了 我没有任何问题 我只是想对有关可变性的问题进行一些澄清 在 Objective C 中我们会使用例如NSMutableArray得到一个可变数组和NSArray得到一个不可变的 我对两者的内部运作了解不多 但据我
  • 将 JavaFX FXML 对象分组在一起

    非常具有描述性和信息性的答案将从我这里获得价值 50 声望的赏金 我正在 JavaFX 中开发一个应用程序 对于视图 我使用 FXML
  • 子类构造函数(JAVA)中的重写函数[重复]

    这个问题在这里已经有答案了 为什么在派生类构造函数中调用超类构造函数时 id 0 当创建子对象时 什么时候在堆中为该对象分配内存 在基类构造函数运行之后还是之前 class Parent int id 10 Parent meth void
  • 由 Servlet 容器提供服务的 WebSocket

    上周我研究了 WebSockets 并对如何使用 Java Servlet API 实现服务器端进行了一些思考 我没有花费太多时间 但在使用 Tomcat 进行一些测试时遇到了以下问题 如果不修补容器或至少对 HttpServletResp
  • java'assert'和'if(){}else exit;'之间的区别

    java和java有什么区别assert and if else exit 我可以用吗if else exit代替assert 也许有点谷歌 您应该记住的主要事情是 if else 语句应该用于程序流程控制 而assert 关键字应该仅用于

随机推荐