使用推土机可以将多个字段映射到一个字段吗?

时间:2015-12-15 19:30:42

标签: java dozer

我们正在尝试映射一些遗留数据...遗留数据包含月份日的字段...

是否可以转换

MyObject.day
MyObject.year
MyObject.month

MyOtherObject.date

我找不到有关此主题的任何文档。任何人都将不胜感激。

4 个答案:

答案 0 :(得分:2)

我知道这是一篇过时的文章,但是我找不到令人满意的答案,花了很多时间,然后发现了这个(我认为)简单的方法。您可以将ConfigurableCustomConver与mapping.xml中的“ this”引用结合使用。

例如:

public class Formatter implements ConfigurableCustomConverter
{
   private String format;
   private String[] fields;

   @Override
   public Object convert(Object existingDestinationFieldValue, Object           sourceFieldValue, Class<?> destinationClass, Class<?> sourceClass) {
      List valueList = new ArrayList();

      for (String field : fields){
        try {
           valueList.add(sourceClass.getMethod(field).invoke(sourceFieldValue));
        }
        catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
           throw new RuntimeException("Reflection error during mapping", e);
        }
     }
     return MessageFormat.format(format, valueList.toArray());
  }

  @Override
  public void setParameter(String parameter)
  {
     String[] parameters = parameter.split("\\|");
     format = parameters[0];
     fields = Arrays.copyOfRange( parameters, 1, parameters.length);
  }
}

并在您的mapping.xml中:

<mapping type="one-way">
    <class-a>test.model.TestFrom</class-a>
    <class-b>test.model.TestTo</class-b>

    <field custom-converter="nl.nxs.dozer.Formatter" custom-converter-param="{0}{1}|getFirstValue|getSecondValue">
        <a>this</a>
        <b>combinedValue</b>
    </field>
</mapping>

课程:

public class TestFrom
{
   private String firstValue;
   private String secondValue;

   public String getFirstValue()
   {
      return firstValue;
   }

   public void setFirstValue(String firstValue)
   {
      this.firstValue = firstValue;
   }

   public String getSecondValue()
   {
      return secondValue;
   }

   public void setSecondValue(String secondValue)
   {
      this.secondValue = secondValue;
   } 
}
public class TestTo
{
   private String combinedValue;  

   public String getCombinedValue(){
      return combinedValue;
   } 

   public void setCombinedValue(String combinedValue){
      this.combinedValue = combinedValue;
   }
}

答案 1 :(得分:1)

根据Dozer documentation

  

如何将多个字段映射到单个字段?

     

Dozer目前不支持此功能。而且由于周围的复杂性?实现它,此功能目前不在路线图上。一种可能的解决方案是将多个字段包装在自定义复杂类型中,然后定义自定义转换器以在复杂类型和单个字段之间进行映射。这样,您就可以处理将三个字段映射到自定义转换器中的单个字段所需的自定义逻辑。

如果您可以控制旧数据,则可以创建一个类型来包装各个日期字段:

<强> MyWrapperObject.java

public class MyWrapperObject {

    private int day;

    private int month;

    private int year;

}

<强> MyObject.java

public class MyObject {

    private MyWrapperObject myWrapperObject;

}

然后使用自定义转换器将3个字段映射到日期字段:

<强> MyOtherWrapperObject.java

public class MyOtherWrapperObject {

    private Date date;

}

DateCustomConverter .java

public class DateCustomConverter implements CustomConverter {

    @Override
    public Object convert(Object destination, Object source,
            @SuppressWarnings("rawtypes") Class destClass,
            @SuppressWarnings("rawtypes") Class sourceClass) {

        // Source object is null
        if (source == null) {
            return null;
        }

        if (source instanceof MyWrapperObject) {
            MyOtherWrapperObject dest = new MyOtherWrapperObject();
            MyWrapperObject src = (MyWrapperObject) source;

            Calendar c = Calendar.getInstance();
            // Months are 0 based in Java 
            c.set(src.getYear(), src.getMonth() - 1, src.getDay());
            dest.setDate(c.getTime());

            return dest;
        }
        return null;
    }

然后在XML映射文件中引用此转换器:

<强> dozer.xml

<mapping  map-null="false" >
    <class-a>com.xxx.MyObject</class-a>
    <class-b>com.xxx.MyOtherObject</class-b>

    ...

    <field custom-converter="com.xxx.DateCustomConverter">
        <a>myWrapperObject</a>
        <b>myOtherWrapperObject</b>
    </field>
</mapping>

如果您无法控制旧数据,我相信您必须编写自定义映射器才能将MyObject映射到MyOtherObject

答案 2 :(得分:1)

如果你需要将两个字段映射到单个字段,反之亦然,我会推荐一个不同的解决方案。

Dozer可以使用setter / getters作为映射的方式。在您必须这样做的类上(您有两个字段并希望映射到单个字段)使用setters,您可以在其中提供来自不同对象的单个字段,并在setter / getter逻辑上分配这两个字段。

示例映射:

<mapping type="bi-directional">
<class-a>ClassWithTwoFields</class-a>
<class-b>ClassWithSingleField</class-b>
<field>
  <a get-method="getHelperField" set-method="setHelperField" >helperField</a>
  <b>helperField</b>
</field>

getter / setters示例:

 public FieldType getHelperField() {
    if (!isNull(field1) && !isNull(field2)) {
        return field1 + field2;
    }
    return null;
}

public void setHelperField(FieldType singleField) {
    if (!isNull(singleField)) {
        this.field1 = singleField.part1();
        this.field2 = singleField.part2();
    }
}

这是解决问题的快捷方法。

答案 3 :(得分:1)

这可能与问题100%不符,但我来到这里试图找到这个解决方案(可能很多其他人)。这样做:将单个字段值映射到目标类中的两个字段,有条件地在哪个目标上进行处理。想象一下单个“名称”字段,该字段应映射到目标类中的名称和名称缩写字段。 我正在使用Dozer“ConfigurableCustomConverter”。

映射:

<field custom-converter="de.foo.MyConfCustomConverter" custom-converter-param="name">
  <a>person.name</a>
  <b>student.name</b>
</field>
<field custom-converter="de.foo.MyConfCustomConverter" custom-converter-param="abbreviation">
  <a>person.name</a>
  <b>student.shortName</b>
</field>

匹配的自定义转换器:

public class MyConfCustomConverter implements ConfigurableCustomConverter {

private String param;

@SuppressWarnings("rawtypes")
@Override
public Object convert(Object destination, Object source, Class destClass, Class sourceClass) {
    if ("name".equals(this.param)) {
        return (String) source;
    }
    else if ("abbreviation".equals(this.param)) {
        return myAbbrevFunction((String) source);
    }
    return null;
}

@Override
public final void setParameter(String parameter) {
    this.param = parameter;
}

}