Search code examples
javamodelmapper

Modelmapper: How to apply custom mapping when source object is null?


Lets assume I have class MySource:

public class MySource {
    public String fieldA;
    public String fieldB;

    public MySource(String A, String B) {
       this.fieldA = A;
       this.fieldB = B;
    }
}

and I would like to translate it to object MyTarget:

public class MyTarget {
    public String fieldA;
    public String fieldB;
}

using default ModelMapper settings I can achieve it in the following way:

ModelMapper modelMapper = new ModelMapper();
MySource src = new MySource("A field", "B field");
MyTarget trg = modelMapper.map(src, MyTarget.class); //success! fields are copied

It can happen however, that MySource object will be null. In this case, MyTarget will be also null:

    ModelMapper modelMapper = new ModelMapper();
    MySource src = null;
    MyTarget trg = modelMapper.map(src, MyTarget.class); //trg = null

I would like to specify custom mapping in such a way, that (pseudo code):

MySource src != null ? [perform default mapping] : [return new MyTarget()]

Does anybody have idea how to write an appropriate converter to achieve that?


Solution

  • It is not possible using ModelMapper directly because ModelMapper map(Source, Destination) method checks if source is null, in that case it throws an exception...

    Take a look to ModelMapper Map method implementation:

    public <D> D map(Object source, Class<D> destinationType) {
        Assert.notNull(source, "source"); -> //IllegalArgument Exception
        Assert.notNull(destinationType, "destinationType");
        return mapInternal(source, null, destinationType, null);
      }
    

    Solution

    I propose extends ModelMapper class and override map(Object source, Class<D> destinationType) like this:

    public class MyCustomizedMapper extends ModelMapper{
    
        @Override
        public <D> D map(Object source, Class<D> destinationType) {
            Object tmpSource = source;
            if(source == null){
                tmpSource = new Object();
            }
    
            return super.map(tmpSource, destinationType);
        }
    }
    

    It checks if source is null, in that case it initializes then it calls super map(Object source, Class<D> destinationType).

    Finally, you could use your customized mapper like this:

    public static void main(String args[]){
        //Your customized mapper
        ModelMapper modelMapper = new MyCustomizedMapper();
    
        MySource src = null;
        MyTarget trg = modelMapper.map(src, MyTarget.class); //trg = null
        System.out.println(trg);
    }
    

    The output would be a new MyTarget():

    Output Console: NullExampleMain.MyTarget(fieldA=null, fieldB=null)

    Thus it is initialized.