使用自定义转换器进行推土机深度属性映射
我的应用程序中有深度属性映射(从域对象到 DTO,反之亦然),类似于下一个示例:
...
<field>
<a>employee.id</a>
<b>employeeId</a>
</field>
...
当 Dozer 将 Domain 转换为 DTO 时,它将 employee.id
映射到 employeeId< /code>,这样就可以了。
当 Dozer 将 DTO 转换为 Domain 时,它将 employeeId
映射到 id=employeeId 的新 Employee 实例。
我想为这个深层属性映射创建一些逻辑,但我只是想不出解决方案。我尝试实现 CustomConverter(或扩展 DozerConverter),但 Dozer 将 Integer 类型作为源类和目标类传递给我(并期望 Integer 作为结果)。
编辑: 更准确地说,如果 DTO 中的 employeeId
为 0,我需要将 Domain 中的 employee
映射到 null
。
这可能吗?
有什么建议吗?
根据答案进行编辑: 我使用字段级自定义转换器解决了问题。而不是前面提到的映射,现在我有这样的东西...
...
<field custom-converter="ManyToOneIdMapper" custom-converter-param="id">
<a>employee</a>
<b>employeeId</b>
</field>
...
在 ManyToOneIdMapper 中我有...
public class ManyToOneIdMapper implements ConfigurableCustomConverter{
//...
//parameter field declaration, setParameter and getParameter implementations etc.
//...
public Object convert(Object existingDestinationFieldValue, Object sourceFieldValue,
Class<?> destinationClass, Class<?> sourceClass) {
try {
if(sourceClass.equals(Integer.class)){
Integer src=(Integer)sourceFieldValue;
if(src==null || src==0)
return null;
String setterName=formatMethodName("set", getParameter());
Method setterMethod=destinationClass.getMethod(setterName, Integer.class);
Object instance=destinationClass.newInstance();
setterMethod.invoke(instance, src);
return instance;
}else{
if(sourceFieldValue==null)
return 0;
String getterName=formatMethodName("get", getParameter());
Method getterMethod=sourceClass.getMethod(getterName);
Object instance=getterMethod.invoke(sourceFieldValue);
return instance;
}
} catch (Exception e){}
return null;
}
/**
* @return - method name (most often setter or getter) according to fieldName.
* For example formatMethodName("get", "id") returns "getId"
*/
protected String formatMethodName(String methodPrefix, String fieldName){
String trimmedFieldName=fieldName.trim();
String firstLetter=String.valueOf(trimmedFieldName.charAt(0));
String capitalizedFirstLetter=firstLetter.toUpperCase();
String methodName=methodPrefix+""+capitalizedFirstLetter+""+fieldName.substring(1);
return methodName;
}
custom-converter-param
只是域对象中 id 字段的名称。使用这个名称,我只需在转换器中调用 setter 或 getter 方法。也许,这不是最快乐的解决方案,但它适用于我的问题场景。
I have deep property mapping in my application (from domain objects to DTO, and the reverse), similar to next example:
...
<field>
<a>employee.id</a>
<b>employeeId</a>
</field>
...
When Dozer converts Domain to DTO, it maps employee.id
to employeeId
, and that is ok.
When Dozer converts DTO to Domain, it maps employeeId
to a new Employee instance with id=employeeId.
I want to create some logic for this deep property mapping, but i just can't figure out solution. I tried to implement CustomConverter
(or extend DozerConverter
) but Dozer passes me Integer type as source and destination class(and expect Integer as result).
EDIT:
More precisely, what i need is to map employee
in Domain to null
if employeeId
in DTO is 0.
Is this possible?
Any advice?
EDIT ACCORDING TO ANSWERS:
I solve problem with field-level custom converter. Instead of earlier, above mentioned, mapping, now i have something like this...
...
<field custom-converter="ManyToOneIdMapper" custom-converter-param="id">
<a>employee</a>
<b>employeeId</b>
</field>
...
In ManyToOneIdMapper i have...
public class ManyToOneIdMapper implements ConfigurableCustomConverter{
//...
//parameter field declaration, setParameter and getParameter implementations etc.
//...
public Object convert(Object existingDestinationFieldValue, Object sourceFieldValue,
Class<?> destinationClass, Class<?> sourceClass) {
try {
if(sourceClass.equals(Integer.class)){
Integer src=(Integer)sourceFieldValue;
if(src==null || src==0)
return null;
String setterName=formatMethodName("set", getParameter());
Method setterMethod=destinationClass.getMethod(setterName, Integer.class);
Object instance=destinationClass.newInstance();
setterMethod.invoke(instance, src);
return instance;
}else{
if(sourceFieldValue==null)
return 0;
String getterName=formatMethodName("get", getParameter());
Method getterMethod=sourceClass.getMethod(getterName);
Object instance=getterMethod.invoke(sourceFieldValue);
return instance;
}
} catch (Exception e){}
return null;
}
/**
* @return - method name (most often setter or getter) according to fieldName.
* For example formatMethodName("get", "id") returns "getId"
*/
protected String formatMethodName(String methodPrefix, String fieldName){
String trimmedFieldName=fieldName.trim();
String firstLetter=String.valueOf(trimmedFieldName.charAt(0));
String capitalizedFirstLetter=firstLetter.toUpperCase();
String methodName=methodPrefix+""+capitalizedFirstLetter+""+fieldName.substring(1);
return methodName;
}
custom-converter-param
is just name of id-field in Domain object. With that name, i just call setter or getter method in my converter. Probably, it is not the happiest solution, but it works for my problem scenario.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您可以使用
CustomConverter
(根据其他答案),或者使用DozerEventListener
在映射完成后将员工对象设置回 null(如果 ID 为 0) 。You can either use a
CustomConverter
(per the other answer), or use aDozerEventListener
to set the employee object back to null after the mapping has finished, if the ID is 0.您希望使用
CustomConverter
来映射父对象,例如:Domain
DTO
您希望使用
PersonA
和PersonB
来映射两个类>CustomConverter,这将让您可以按照您想要的方式构建它们。You want a
CustomConverter
to map the parent object, for example:Domain
DTO
You want to map the two classes
PersonA
andPersonB
using aCustomConverter
, this will let you construct them what ever way you want.您可以查看ModelMapper(作者在这里)。它将智能地映射您描述的场景,无需任何配置或自定义转换器。考虑模型:
映射很简单:
要在
PersonDTO.employeeId
不为零时有条件地映射Person.employee
,我们只需创建一个条件并为 Person.employee 添加属性映射条件:当
empIdIsNotZero
条件适用时,映射将正常发生。否则映射将被跳过,并且Person.employee
将被设置为 null。查看 ModelMapper 网站以获取更多文档和示例:
http://modelmapper.org
You might check out ModelMapper (author here). It will intelligently map the scenario you describe without requiring any configuration or custom converters. Considering the model:
Mapping is simple:
To conditionally map
Person.employee
whenPersonDTO.employeeId
is not zero, we simply create a condition and add a property mapping for Person.employee with the condition:When the
empIdIsNotZero
condition applies, mapping will occur as normal. Otherwise mapping will be skipped andPerson.employee
will be set to null.Check out the ModelMapper site for more docs and examples:
http://modelmapper.org