Skip to content
Advertisement

Use another MapStruct mapper only inside an expression clause

I have a mapper that, for a particular attribute of the target class, needs to choose one from a list of objects inside the source object, and map it using a differente mapper class.

Simplifying it a lot, the Game class contains a list of Transaction objects, and my GameMapper class looks like this:

@Component
@Mapper(injectionStrategy = InjectionStrategy.CONSTRUCTOR, uses = {TransactionMapper.class, EventMapper.class})
public interface GameMapper {

@Mapping(target = "transaction", 
    expression = "java(transactionMapper.transactionToDto(findTransactionForPlayer(game, idPlayer)))")
GameResultDto gameToGameResultDto(Game game, Long idPlayer);

// Some more methods

}

The thing is, EventMapper gets generated as a private final EventMapper eventMapper; attribute inside GameMapperImpl, but TransactionMapper is not, so the build fails because MapStruct cannot find transactionMapper.

My best guess is that this is due to no other methods in GameMapper using TransactionMapper explicitly, so Mapstruct decides that it’s not needed and doesn’t inject it in the implementation.

So… is there any way to force MapStruct to include the mappers in the uses clause, even it if looks like they are not being used, or any other way to work around this?

Advertisement

Answer

My best guess is that this is due to no other methods in GameMapper using TransactionMapper explicitly, so Mapstruct decides that it’s not needed and doesn’t inject it in the implementation.

That is correct. MapStruct will not inject mappers from Mapper#uses if they are not used by MapStruct.

What you could do is to use an abstract class.

e.g.

@Mapper(injectionStrategy = InjectionStrategy.CONSTRUCTOR, componentModel = "spring", uses = {TransactionMapper.class, EventMapper.class})
public abstract class GameMapper {

    @Autowired
    protected TransactionMapper transactionMapper;

    @Mapping(target = "transaction", 
        expression = "java(transactionMapper.transactionToDto(findTransactionForPlayer(game, idPlayer)))")
    public abstract GameResultDto gameToGameResultDto(Game game, Long idPlayer);

    // Some more methods

}
User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement