Search code examples
springspring-bootnullautomappermapstruct

Spring Boot MapStrut null strategy for internal object


I am triying to map with MapStrut and java two objects like that:

@Data
@NoArgsConstructor
public class EventDTO {

  @JsonInclude(Include.NON_NULL)
  private EventStatusDTO eventStatus;
}


@Data
@NoArgsConstructor
public class EventStatusDTO {

  @JsonInclude(Include.NON_NULL)
  private String statusCode;

  @JsonInclude(Include.NON_NULL)
  private String statusDescription;
}

@Data
@NoArgsConstructor
public class Event {
  private String statusCode;
}

When status Code is null I want all EventStatusDTO object to be null inside the EventDTO object. but defining the mapper like this:

@Mappings({
    @Mapping(target = "voltageLevel.voltageLevelCode", source = "voltageLevelCode"),
    @Mapping(target = "eventStatus.statusCode", source = "statusCode", nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.SET_TO_NULL),
    @Mapping(target = "eventType.typeCode", source = "typeCode", nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.SET_TO_NULL),
    @Mapping(target = "eventCause.causeCode", source = "causeCode", nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.SET_TO_NULL)
  })
  public abstract EventDTO fromEntityToDTO(Event source);

I am just able to generate an empty object EventStatusDTO inside the EventDTO.

This is the code generated:

    protected EventCauseDTO eventToEventCauseDTO(Event event) {
        if ( event == null ) {
            return null;
        }

        EventCauseDTO eventCauseDTO = new EventCauseDTO();

        eventCauseDTO.setCauseCode( event.getCauseCode() );

        return eventCauseDTO;
    }

Who can i make this more like

 protected EventCauseDTO eventToEventCauseDTO(Event event) {
        if ( event == null ) {
            return null;
        }

        EventCauseDTO eventCauseDTO = null;

        if(event.getCauseCode() != null) {
            eventCauseDTO = new EventCauseDTO();
            eventCauseDTO.setCauseCode(event.getCauseCode());
        }

        return eventCauseDTO;
    }

I have been testing with some nullValueStrategies of mapStruct but nothing... and I dont would not like to use an @AfterMapping to check all empty object.

Thanks in advance.


Solution

  • This is not supported by MapStruct, when trying to map a nested target object you can't control what will cause that bean (EventCauseDTO) to be null.

    In your example it looks really simple, as it is a single parameter. However, this can get complex really fast. There could be multiple parameters, and arbitrary number of them can lead to the target object being null or not.

    What I would suggest is to provide a custom mapping between String and EventCauseDTO.

    e.g.

    @Mapper
    public interface EventMapper {
    
        @Mapping(target = "voltageLevel.voltageLevelCode", source = "voltageLevelCode"),
        @Mapping(target = "eventStatus.statusCode", source = "statusCode")
        @Mapping(target = "eventType.typeCode", source = "typeCode")
        @Mapping(target = "eventCause", source = "causeCode")
        EventDTO fromEntityToDTO(Event source);
    
        @Mapping( target = "causeCode", source = "cause")
        EventCauseDTO fromCause(String cause);
    
    }
    

    If you do this, then there will be a null check on the source parameter and null will be returned for the EventCauseDTO in the fromCause method.