我的应用程序中有深度属性映射(从域对象到DTO,反之亦然),类似于下一个示例:
...
<field>
<a>employee.id</a>
<b>employeeId</a>
</field>
...
当Dozer将域转换为DTO时,它会将employee.id
映射到employeeId
,这没关系。
当Dozer将DTO转换为域时,它会将employeeId
映射到id = employeeId的新Employee实例。
我想为这个深度属性映射创建一些逻辑,但我无法弄清楚解决方案。我尝试实现CustomConverter
(或扩展DozerConverter
),但是Dozer将Integer类型作为源类和目标类传递给我(并期望Integer作为结果)。
修改:
更确切地说,我需要的是,如果DTO中的employee
为0,则将null
在域中映射到employeeId
。
这可能吗?
有什么建议吗?
根据答案编辑: 我解决了现场级自定义转换器的问题。而不是之前,上面提到的映射,现在我有这样的东西......
...
<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
只是Domain对象中id-field的名称。使用该名称,我只需在转换器中调用setter或getter方法。可能它不是最快乐的解决方案,但它适用于我的问题场景。
答案 0 :(得分:1)
如果ID为0,您可以使用CustomConverter
(根据其他答案),或使用DozerEventListener
将员工对象设置为映射完成后返回null。
答案 1 :(得分:0)
您希望CustomConverter
映射父对象,例如:
域
class PersonA {
...
int employeeId;
...
}
DTO
class PersonB {
...
Employee employee;
...
}
class Employee {
...
int id;
...
}
您希望使用PersonA
映射两个类PersonB
和CustomConverter
,这样您就可以按照自己想要的方式构建它们。
答案 2 :(得分:0)
您可以查看ModelMapper(此处作者)。它将智能地映射您描述的场景,而无需任何配置或自定义转换器。考虑到模型:
class Person {
Employee employee;
}
class Employee {
int id;
}
class PersonDTO {
int employeeId;
}
映射很简单:
ModelMapper modelMapper = new ModelMapper();
PersonDTO personDTO = modelMapper.map(person, PersonDTO.class);
要在Person.employee
不为零时有条件地映射PersonDTO.employeeId
,我们只需创建一个条件并为Person.employee添加一个属性映射,条件为:
Condition<?, ?> empIdIsNotZero = new Condition<PersonDTO, Employee>() {
public boolean applies(MappingContext<PersonDTO, Employee> context) {
return context.getSource().getEmployeeId() != 0;
}
};
modelMapper.addMappings(new PropertyMap<PersonDTO, Person>() {
protected void configure() {
when(empIdIsNotZero).map(source).setEmployee(null);
}
});
当empIdIsNotZero
条件适用时,映射将正常进行。否则将跳过映射并将Person.employee
设置为null。
查看ModelMapper网站以获取更多文档和示例: