Search code examples
javaspringmapstruct

How to make mapstruct mappers return null instead of new objects with all fields set to null


Hello everyone!

I'm implementing Mapstruct mappers in my Spring application.

There are two related entities: User and Order. Just to simplify -> User can have many Orders.

Below I'm attaching these entities with their DTO models.

Order class:

    public class Order {
    
        ...
    
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "user_id")
        private User user;
        ...
    }

OrderDTO class:

    public class OrderDTO {
    
        ...
    
        private Long userId;
    
        ...
    
    }

User class:

    public class User {
    
        ...
    
        @OneToMany(mappedBy = "user", orphanRemoval = false, fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
        private Set<Order> orders;
    
        ...
    }

UserDTO class:

    public class UserDTO {
    
        ...
    
        private Set<Long> ordersIds;
    
        ...
    }

To clarify my problem let me add OrderMapper below:

CommonMapper (just a simple interface, don't care about generic types):

public interface CommonMapper<E extends AbstractEntity, D extends AbstractDto> {

    D toDto(E e);

    E fromDto(D dto);

    Set<D> toSetDto(Set<E> e);

    Set<E> fromSetDto(Set<D> d);

    List<D> toListDto(List<E> e);

    List<E> fromListDto(List<D> d);
}

OrderMapper class:

@Mapper(componentModel = "spring")
public interface OrderMapper extends CommonMapper<Order, OrderDTO> {
    OrderMapper INSTANCE = Mappers.getMapper(OrderMapper.class);

    @Override
    @Mapping(source = "user.id", target = "userId")
    OrderDTO toDto(Order order);

    @Override
    @Mapping(source = "userId", target = "user.id")
    Order fromDto(OrderDTO dto);
}

Ok, so here's my problem:

If I'm passing OrderDTO with:

userID=null

I want my mapped (by OrderMapper) entity to have User set to NULL.

user = null

Instead, mapper creates new User() with all fields set to NULL.

user:
field1 = null,
field2 = null, ...

How it looks in IntelliJ

Do you guys have any ideas how to make mapstruct mapper not to initialize new object when there is null passed?

Situation described before creates huge problem in my application. I'll be grateful for any help.


Solution

  • This is not an elegant solution, but it works. I'm not sure if Mapstruct has fixed this issue or not yet.

    Add this to OrderMapper.

    @AfterMapping
    default Order afterMapping(@MappingTarget Order order) {
        if (order != null && order.getUser().getId() == null) {
            order.setUser(null);
        }
        return order;
    }