Mapper function null parameter check

Viewed 587

I am using MapStruct in combination with Lombok and builder pattern. I have an issue that MapStruct is doing an explicit null check of all parameters inside the generated mapper function and does an early exit in case all parameters are null, e.g.:

// Object A
@Value
@Builder(builderClassName = "Builder")
public class SourceA{
    private int a;
}

// Object B
@Value
@Builder(builderClassName = "Builder")
public class SourceB{
    private int a;
}

// Object C
@Value
@Builder(builderClassName = "Builder")
public class SourceC{
    private int a;
}

// Object Target
@Value
@Builder(builderClassName = "Builder")
public class Target{
    private int a;
    private int b;
    private int c;
}

// Mapper
@Mapper(componentModel = "spring")
public interface Mapper {

    @Mappings({
            @Mapping(target = "a", source = "sourceA.a"),
            @Mapping(target = "b", source = "sourceB.a"),
            @Mapping(target = "c", source = "sourceC.a")
    })
    Target toTarget(SourceA sourceA, SourceB sourceB, SourceC sourceC);
};

// mapstruct impl
// Auto Generated by MapStruct!
public class MapperImpl implements Mapper {
    public Target toTarget(SourceA sourceA, SourceB sourceB, SourceC sourceC){
        // Problamatic line
        if (sourceA == null && sourceB == null && sourceC == null) {
            return null;
        } else {
            Target.Builder builder = Target.builder();
            // map objects
            return builder.builder();
        }
    }
}

I want to achieve that MapStruct does not implement the full null check. It should setup the whole builder even if all parameters are null and call build at the end that the builders null checks takes place (if there are any).

1 Answers

In order to achieve what you are looking for, always create a default instance of the target object you need to use the NullValueMappingStrategy.

On your mapper you can do @Mapper(nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT) when you do that the generated code should look something like:

public class MapperImpl implements Mapper {
    public Target toTarget(SourceA sourceA, SourceB sourceB, SourceC sourceC){

        Target.Builder builder = Target.builder();
        // map objects
        return builder.builder();
    }
}
Related