Search code examples
javamodelmapper

How can I map from to sources to the same object in ModelMapper


How can I express the following in ModelMapper: To fill a field in the target, I want to use property A of the source if it is non-null, otherwise use the property B.

Example (Code below if you don't like technical descriptions): Let's say I want from a source class SourceBigThing to a target class Target using ModelMapper. The SourceBigThing has two properties, one called red and one called green. These two properties are of different types RedSmallThing and GreenSmallThing. Both of these things have a property called name. A SourceBigThing can either have a red or a green, but not both (the other is null). I want to map the names of the Small Things to a property of the target-class.

Example-Code:

class SourceBigThing {
    private final SourceSmallThingGreen green;
    private final SourceSmallThingRed red;
}

class SourceSmallThingGreen {
    private final String name;
}

class SourceSmallThingRed {
    private final String name;
}



class Target {
    private TargetColorThing thing;
}

class TargetColorThing {
    // This property should either be "green.name" or "red.name" depending
    // on if red or green are !=null
    private String name; 
}

I tried to play around with the conditionals, but you cannot have two mappings to the same target because ModelMapper throws an exception for duplicate mappings:

when(Conditions.isNotNull()).map(source.getGreen()).setThing(null);
when(Conditions.isNotNull()).map(source.getRed()).setThing(null);

You can find a failing TestNG-Unit-Test at this gist.


Solution

  • This is a bit of an unusual case, so there's no neat way of doing this. But you can always use a Converter - something like:

    using(new Converter<SourceBigThing, TargetColorThing>(){
      public TargetColorThing convert(MappingContext<SourceBigThing, TargetColorThing> context) {
        TargetColorThing target = new TargetColorThing();
        if (context.getSource().getGreen() != null)
          target.setName(context.getSource().getGreen().getName());
        else if (context.getSource().getRed() != null)
          target.setName(context.getSource().getRed().getName());
        return target;
    }}).map(source).setThing(null);