推土机深度属性映射与自定义转换器

时间:2011-06-16 02:57:51

标签: mapping dozer

我的应用程序中有深度属性映射(从域对象到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方法。可能它不是最快乐的解决方案,但它适用于我的问题场景。

3 个答案:

答案 0 :(得分:1)

如果ID为0,您可以使用CustomConverter(根据其他答案),或使用DozerEventListener将员工对象设置为映射完成后返回null。

答案 1 :(得分:0)

您希望CustomConverter映射父对象,例如:

class PersonA {
    ...
    int employeeId;
    ...
}

DTO

class PersonB {
    ...
    Employee employee;
    ...
}

class Employee {
    ...
    int id;
    ...
}

您希望使用PersonA映射两个类PersonBCustomConverter,这样您就可以按照自己想要的方式构建它们。

答案 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网站以获取更多文档和示例:

http://modelmapper.org