[英]One way mapping in Dozer using custom converter
Please note: while I would accept an XML-based solution if that's truly the only way to accomplish what I'm looking for, I would greatly prefer a solution using Dozer's Java API.请注意:虽然我会接受基于 XML 的解决方案,如果这确实是完成我正在寻找的唯一方法,但我更喜欢使用 Dozer 的 Java API 的解决方案。
I am new to Dozer and am trying to figure out how to use its API.我是Dozer的新手,正在尝试弄清楚如何使用它的 API。 It seems to default to field-level mappings (if the field names match) and to allow for custom mappers and converters in the event that field-level mapping (based on field name) is either not possible or not logical for your application needs.它似乎默认为字段级映射(如果字段名称匹配)并允许自定义映射器和转换器,以防字段级映射(基于字段名称)对于您的应用程序需求是不可能或不合逻辑的。
I have a situation where my app will take a DTO, say, ReportedIssue
(an issue reported by a user and sent to my application over HTTP), and an Issue
entity (a data entity that will be persisted to a MySQL DB).我的应用程序将采用 DTO,例如ReportedIssue
(用户报告并通过 HTTP 发送到我的应用程序的问题)和Issue
实体(将持久保存到 MySQL 数据库的数据实体)。
Here are my two objects:这是我的两个对象:
@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;
}
So in the application frontend, a user can report an issue.因此,在应用程序前端,用户可以报告问题。 The frontend sends a JSON version of a ReportedIssue
to the backend, where that JSON is deserialized into a ReportedIssue
DTO bean.前端将ReportedIssue
的 JSON 版本发送到后端,其中 JSON 被反序列化为ReportedIssue
DTO bean。 Then I need Dozer to convert my ReportedIssue
into an Issue
entity that I can then easily save to my MySQL DB.然后我需要 Dozer 将我的ReportedIssue
转换为Issue
实体,然后我可以轻松地将其保存到我的 MySQL 数据库中。
Here is my best attempt:这是我最好的尝试:
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");
}
}
Several concerns here.这里有几个问题。 For one, is such a custom converter even necessary?一方面,这样的定制转换器是否必要? Or is there a "better" (more standards compliant or using generally-accepted Dozer practices) way to use the Dozer API to perform this conversion?或者是否有“更好”(符合更多标准或使用普遍接受的推土机实践)的方式来使用推土机 API 执行此转换? But mainly, this DozerConverter
seems to be intended for bi-directional mapping use cases.但主要是,这个DozerConverter
似乎适用于双向映射用例。 Whereas, in my application, I will never have an Issue
instance and need to map it back to a ReportedIssue
DTO instance.然而,在我的应用程序中,我永远不会有Issue
实例,需要将其 map 回传给ReportedIssue
DTO 实例。 So I only need one-way mapping from ReportedIssue --> Issue
.所以我只需要来自ReportedIssue --> Issue
的单向映射。 Am I using Dozer correctly by throwing an UnsupportedOperationException
or is there another interface or API trick I can use to only leverage the one-way mapping I need?我是通过抛出UnsupportedOperationException
正确使用推土机,还是有另一个接口或 API 技巧可以用来仅利用我需要的单向映射?
It could actually be done without a custom converter using custom getter methods in your dto class corresponding to fields in Issue
.它实际上可以在没有自定义转换器的情况下使用您的 dto class 中对应于Issue
中的字段的自定义 getter 方法来完成。 Dozer works by mapping each field in destination class by trying to invoke the getter method of the corresponding name in the source class. 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.
}
But for reporter
field in Issue
, you need an AuthService
object.但是对于Issue
中的reporter
字段,您需要一个AuthService
object。 I would suggest writing a static method as below:我建议编写如下 static 方法:
public static Issue getIssue(AuthService auth, ReportedIssue dto) {
Issue issue = //map using dozer
issue.setReporter(authService.currentUser());
return issue;
}
Gauntham answer will work.冈瑟姆的回答会奏效。 Another option:另外的选择:
Implement a com.github.dozermapper.core.BeanFactory Your custom BeanFactory can handle实现一个 com.github.dozermapper.core.BeanFactory 你的自定义 BeanFactory 可以处理
Issue issue = new Issue();
issue.setRefId(UUID.randomUUID().toString());
issue.setReportedOn(DateTimeUtils.nowInUTC());
issue.setReporter(authService.currentUser());
Then depending on your preferences, this could also go into the bean factory然后根据你的喜好,这个也可以 go 进豆厂
issue.setType(IssueUtils.determineType(source));
Or you could handle that separately in the mapping.或者您可以在映射中单独处理。 Something would need to know how to call IssueUtils, so that is either 1) a customer converter or 2) a change to the DTO or entity to have the functionality through a getter or setter.有些东西需要知道如何调用 IssueUtils,因此要么是 1) 客户转换器,要么是 2) 更改 DTO 或实体以通过 getter 或 setter 获得功能。
Finally, this line would be handled in the Dozer Java API mapping最后,这条线将在 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. 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), and beanFactory(String) are found in Dozer's TypeMappingOptions and customConverter(Class.class) is found in Dozer's FieldMappingOptions. oneWay()、wildcard(boolean) 和 beanFactory(String) 在 Dozer 的 TypeMappingOptions 中找到,customConverter(Class.class) 在 Dozer 的 FieldMappingOptions 中找到。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.