开发者

custom dozer mapping

I'm trying to use Dozer to convert an instance of

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

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

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

to an instance of:

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

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

In Java code I would preform the converstion like this

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

Dozer doesn't perform this conversion by default because Target doesn't have a foos property (开发者_开发知识库just a getter).

In reality, I have lots of properties like this that I need to map. One option is to tell Dozer to map the private fields directly, but this is not entirely satisfactory because:

  • I will need to specify each field to be mapped in this way by name in the Dozer XML config
  • accessing private fields is bad

Is there a better way?


There is no easy way to get around this other than the is-accessible flag. But you could define a custom converter that uses the getter to do:

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

This would be very heavy handed and alot of work. You would need to define a custom converter (see http://dozer.sourceforge.net/documentation/customconverter.html) between Source and Target that used the getter instead of the setter:

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

I think, good luck


You could add a method to 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>

Maybe suggest a feature to allow use of EL in a setter or getter expression


If for example you do not have a setter for a list value (like I had for whatever reason...) you can use the field mapping in combination with "this", to identify the attribute you can use "key":

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

You can then proceed to implement the converter. You will be given the Object containing the field "variablename" as source. you are now able to manipulate the source object the way you need to (in this case use the getter, get the list, addAll() and you're good).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜