Dónal
Dónal

Reputation: 187379

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:

Is there a better way?

Upvotes: 1

Views: 7048

Answers (3)

fl0w
fl0w

Reputation: 3897

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).

Upvotes: 0

Corneil du Plessis
Corneil du Plessis

Reputation: 1043

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

Upvotes: 1

mark-cs
mark-cs

Reputation: 4707

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

Upvotes: 1

Related Questions