自定义推土机映射

时间:2011-04-21 13:58:00

标签: java dozer

我正在尝试使用Dozer来转换

的实例
class Source {
  private List<Foo> foos = new ArrayList<Foo>();

  public List<Foo> getFoos() {
    return foos;
  }

  public void setFoos(List<Foo> foos) {
    this.foos = foos;
  }
}

到一个实例:

class Target {
  private List<Foo> foos = new ArrayList<Foo>();

  public List<Foo> getFoos() {
    return foos;
  }
}

在Java代码中,我会像这样预先形成转换

Source s = new Source();
Target t = new Target();
t.getFoos().addAll(s.getFoos());

默认情况下,Dozer不会执行此转换,因为Target没有foos属性(只是一个getter)。

实际上,我有很多这样的属性需要映射。一种选择是告诉Dozer map the private fields directly,但这并不完全令人满意,因为:

  • 我需要在Dozer XML config
  • 中按名称指定要以这种方式映射的每个字段
  • 访问私有字段不好

有更好的方法吗?

4 个答案:

答案 0 :(得分:1)

is-accessible标志外,没有其他方法可以解决这个问题。 但您可以定义一个使用getter执行的自定义转换器:

t.getFoos().addAll(s.getFoos());

这将是非常沉重的工作和很多工作。您需要在使用getter而不是setter的SourceTarget之间定义自定义转换器(请参阅http://dozer.sourceforge.net/documentation/customconverter.html):

public class TestCustomConverter implements CustomConverter {

  public Object convert(Object destination, Object source, Class destClass, Class sourceClass) {
    if (source == null) {
      return null;
    }
    if (source instanceof Source) {
      Target dest = null;
      // check to see if the object already exists
      if (destination == null) {
        dest = new Target();
      } else {
        dest = (Target) destination;
      }
      dest.getFoos().addAll(((Source)source).getFoos());
      return dest;
    } else if (source instanceof Target) {
      Source dest = null;
      // check to see if the object already exists
      if (destination == null) {
        dest = new Source();
      } else {
        dest = (Source) destination;
      }
      dest.setFoos(((Target)source).getFoos());
      return dest;
    } else {
      throw new MappingException("Converter TestCustomConverter used incorrectly. Arguments passed in were:"
          + destination + " and " + source);
    }
  } 

我认为,祝你好运

答案 1 :(得分:1)

您可以向Target添加方法:

public void addFoo(Foo item) {
    foos.add(item);
}

<mapping>
  <class-a>Source</class-a>
  <class-b>Target</class-b>
  <field>
    <a>foos</a>
    <b set-method="addFoo" type="iterate">foos</b>
  </field>
</mapping>

可能建议允许在setter或getter表达式中使用EL的功能

答案 2 :(得分:1)

您可以查看ModelMapper作为Dozer的替代方案。处理这种情况是微不足道的:

ModelMapper modelMapper = new ModelMapper();
modelMapper.getConfiguration()
  .enableFieldMatching(true)
  .setFieldAccessLevel(AccessLevel.PRIVATE);

这为所有私有字段启用了字段匹配。要执行映射:

Target target = modelMapper.map(source, Target.class);

查看ModelMapper网站了解更多信息:

http://modelmapper.org

答案 3 :(得分:0)

例如,如果您没有列表值的setter(就像我出于某种原因......),您可以将字段映射与“this”结合使用,以识别您可以使用“key”的属性:

<field custom-converter="de.xyz.custom.MyConverter">
    <a key="variablename">this</a>
    <b>targetvariablename</b>
</field>

然后,您可以继续实施转换器。您将获得包含字段“variablename”作为源的Object。你现在能够以你需要的方式操作源对象(在这种情况下使用getter,获取列表,addAll()并且你很好)。