繁体   English   中英

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

[英]With dozer is it possible to map several fields to one field?

我们有一些我们正在尝试映射的遗留数据......遗留数据具有用于月日年的字段......

是否可以转换

MyObject.day
MyObject.year
MyObject.month

MyOtherObject.date

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

从我的角度来看,如果您需要将两个字段映射到单个字段,反之亦然,我会推荐一个稍微不同的解决方案。

Dozer 可以让用户设置器/获取器作为进行映射的方式。 在您必须执行此操作的类上(您有两个字段并希望映射到单个字段)使用 setter,您可以在其中提供来自不同对象的单个字段,并在 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/setter:

 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();
    }
}

这是处理问题的快速方法。

我知道这是一个旧帖子,但我找不到令人满意的答案,花了很多时间然后发现了这个(我认为)简单的方法。 您可以将 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;
   }
}

根据推土机文档

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

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

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

MyWrapperObject.java

public class MyWrapperObject {

    private int day;

    private int month;

    private int year;

}

我的对象

public class MyObject {

    private MyWrapperObject myWrapperObject;

}

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

MyOtherWrapperObject.java

public class MyOtherWrapperObject {

    private Date date;

}

日期自定义转换器.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 映射文件中引用此转换器:

推土机.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

这可能与问题 100% 不匹配,但我来到这里试图找到这个解决方案(可能还有许多其他解决方案)。 这是做什么的:将单个字段值映射到目标类中的两个字段,有条件地取决于正在寻址的目标。 想象一个单独的“名称”字段,该字段应映射到目标类中的名称和名称缩写字段。 我正在使用推土机“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;
}

}

如果您有其他复杂类型要映射,您还可以实现“MapperAware”以在 CustomConverter 中使用 Dozer Mapper 函数:

public class MyConfCustomConverter implements ConfigurableCustomConverter, MapperAware{

private String param;
private Mapper mapper;

@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)) {
        if(isSourceClassAComplexType()){
            return mapper.map(source, my.target.package.ComplexType.class);
        }
        return myAbbrevFunction((String) source);
    }
    return null;
}

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

}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM