javaobject-object-mappingmapstruct

Mapstruct Mapping : Return null object if all source parameters properties are null


I want the generated mapstruct mapping method to return null if all the properties referenced in @Mapping/source are null. For exemple, I have the following mapping :

@Mappings({
      @Mapping(target = "id", source = "tagRecord.tagId"),
      @Mapping(target = "label", source = "tagRecord.tagLabel")
})
Tag mapToBean(TagRecord tagRecord);

The generated method is then :

public Tag mapToBean(TagRecord tagRecord) {
    if ( tagRecord == null ) {
        return null;
    }

    Tag tag_ = new Tag();

    if ( tagRecord.getTagId() != null ) {
        tag_.setId( tagRecord.getTagId() );
    }
    if ( tagRecord.getTagLabel() != null ) {
        tag_.setLabel( tagRecord.getTagLabel() );
    }

    return tag_;
}

Test case : TagRecord object is not null but has tagId==null and tagLibelle==null.

Current behaviour : the returned Tag object is not null, but has tagId==null and tagLibelle==null

What I actually want the generated method to do is return a null Tag object if (tagRecord.getTagId() == null && tagRecord.getTagLabel() == null). Is it possible and how can I achieve this?


Solution

  • This currently is not supported from MapStruct directly. However, you can achieve what you want the help of Decorators and you will have to manually check if all the fields are empty and return null instead of the object.

    @Mapper
    @DecoratedWith(TagMapperDecorator.class)
    public interface TagMapper {
        @Mappings({
            @Mapping(target = "id", source = "tagId"),
            @Mapping(target = "label", source = "tagLabel")
        })
        Tag mapToBean(TagRecord tagRecord);
    }
    
    
    public abstract class TagMapperDecorator implements TagMapper {
    
        private final TagMapper delegate;
    
        public TagMapperDecorator(TagMapper delegate) {
            this.delegate = delegate;
        }
    
        @Override
        public Tag mapToBean(TagRecord tagRecord) {
            Tag tag = delegate.mapToBean( tagRecord);
    
            if (tag != null && tag.getId() == null && tag.getLabel() == null) {
                return null;
            } else {
                return tag;
            }
        }
    }
    

    The example that I have written (the constructor) is for mappers that are with the default component model. If you need to use Spring or a different DI framework have a look at: