繁体   English   中英

使用自定义转换器在推土机中进行映射的一种方式

[英]One way mapping in Dozer using custom converter

请注意:虽然我会接受基于 XML 的解决方案,如果这确实是完成我正在寻找的唯一方法,但我更喜欢使用 Dozer 的 Java API 的解决方案。


我是Dozer的新手,正在尝试弄清楚如何使用它的 API。 它似乎默认为字段级映射(如果字段名称匹配)并允许自定义映射器和转换器,以防字段级映射(基于字段名称)对于您的应用程序需求是不可能或不合逻辑的。

我的应用程序将采用 DTO,例如ReportedIssue (用户报告并通过 HTTP 发送到我的应用程序的问题)和Issue实体(将持久保存到 MySQL 数据库的数据实体)。

这是我的两个对象:

@Data
public class ReportedIssue {

    private String typeRefId;
    private String reporterRefId;
    private String info;

}

@Entity
@Table(name = "issues")
@Data
public class Issue {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "issue_ref_id")
    private String refId;

    @Column(name = "issue_tracking_number")
    private String trackingNumber;

    @OneToOne(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    @JoinColumn(name = "issue_type_id", referencedColumnName = "issue_type_id")
    private IssueType type;

    @Column(name = "issue_reported_on")
    private Date reportedOn;

    @OneToOne(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    @JoinColumn(name = "issue_reporter_id", referencedColumnName = "account_id")
    private Account reporter;

    @Column(name = "issue_info")
    private String info;

}

因此,在应用程序前端,用户可以报告问题。 前端将ReportedIssue的 JSON 版本发送到后端,其中 JSON 被反序列化为ReportedIssue DTO bean。 然后我需要 Dozer 将我的ReportedIssue转换为Issue实体,然后我可以轻松地将其保存到我的 MySQL 数据库中。

这是我最好的尝试:

public class ReportedIssueConverter extends DozerConverter<ReportedIssue, Issue> {

    private AuthService authService;

    public ReportedIssueConverter(AuthService authService, Class<ReportedIssue> prototypeA, Class<Issue> prototypeB) {
      super(prototypeA, prototypeB);
      this.authService = authService;
    }

    public ReportedIssueConverter(Class<ReportedIssue> prototypeA, Class<Issue> prototypeB) {
        super(prototypeA, prototypeB);
    }

    @Override
    public Issue convertTo(ReportedIssue source, Issue destination) {

        Issue issue = new Issue();
        issue.setRefId(UUID.randomUUID().toString());
        issue.setType(IssueUtils.determineType(source));
        issue.setReportedOn(DateTimeUtils.nowInUTC());
        issue.setReporter(authService.currentUser());
        issue.setInfo(destination.getInfo());

        return issue;

    }

    @Override
    public ReportedIssue convertFrom(Issue source, ReportedIssue destination) {
        throw new UnsupportedOperationException("we currently don't map from issues to reported issues");
    }

}

这里有几个问题。 一方面,这样的定制转换器是否必要? 或者是否有“更好”(符合更多标准或使用普遍接受的推土机实践)的方式来使用推土机 API 执行此转换? 但主要是,这个DozerConverter似乎适用于双向映射用例。 然而,在我的应用程序中,我永远不会Issue实例,需要将其 map 回传给ReportedIssue DTO 实例。 所以我只需要来自ReportedIssue --> Issue的单向映射。 我是通过抛出UnsupportedOperationException正确使用推土机,还是有另一个接口或 API 技巧可以用来仅利用我需要的单向映射?

它实际上可以在没有自定义转换器的情况下使用您的 dto class 中对应于Issue中的字段的自定义 getter 方法来完成。 Dozer 的工作原理是通过尝试调用源 class 中相应名称的 getter 方法来映射目标 class 中的每个字段。

public class ReportedIssue {
    // fields.......

    public String getRefId() {
        UUID.randomUUID().toString()
    }

    public IssueType getType() {
        IssueUtils.determineType(this);
    }

    // similarly create getters for other required fields.

}

但是对于Issue中的reporter字段,您需要一个AuthService object。 我建议编写如下 static 方法:

public static Issue getIssue(AuthService auth, ReportedIssue dto) {
    Issue issue = //map using dozer
    issue.setReporter(authService.currentUser());
    return issue;
}

冈瑟姆的回答会奏效。 另外的选择:

实现一个 com.github.dozermapper.core.BeanFactory 你的自定义 BeanFactory 可以处理

Issue issue = new Issue();
issue.setRefId(UUID.randomUUID().toString());
issue.setReportedOn(DateTimeUtils.nowInUTC());
issue.setReporter(authService.currentUser());

然后根据你的喜好,这个也可以 go 进豆厂

issue.setType(IssueUtils.determineType(source));

或者您可以在映射中单独处理。 有些东西需要知道如何调用 IssueUtils,因此要么是 1) 客户转换器,要么是 2) 更改 DTO 或实体以通过 getter 或 setter 获得功能。

最后,这条线将在 Dozer Java API 映射中处理

issue.setInfo(destination.getInfo());

Personally, I like Dozer's com.github.dozermapper.core.loader.api.BeanMappingBuilder where you can explicitly tell it how to map 2 beans, specify the bean factory to use and the custom converter for a specific field.

mapping(ReportedIssue.class, Issue.class, oneWay(), wildcard(true), beanFactory(IssueBeanFactory.class.getName()).fields("this", "type", customConverter(IssueTypeConverter.class)

oneWay()、wildcard(boolean) 和 beanFactory(String) 在 Dozer 的 TypeMappingOptions 中找到,customConverter(Class.class) 在 Dozer 的 FieldMappingOptions 中找到。

  • oneWay() 使映射仅在 BeanMappingBuilder 中指定的方向上工作。
  • wildcard(true) 告诉 Dozer 自动 map 匹配字段(这是默认行为)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM