'@AfterMapping is not called from @Mapper interface

I'm having trouble using Mapstruct.

I am using a @Mapper annotated interface with @AfterMapping inside like follow:

@Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface ConfiguracionReautorizacionMapper {

    ConfiguracionReautorizacionDTO toConfiguracionReautorizacionDTO(final ConfiguracionReautorizacion configuracionReautorizacion);

    ConfiguracionReautorizacion toConfiguracionReautorizacion(final ConfiguracionReautorizacionDTO configuracionReautorizacionDTO);

    @AfterMapping
    default void fillServiciosAsociados(@MappingTarget final ConfiguracionReautorizacionDTO configuracionReautorizacionDTO, final ConfiguracionReautorizacion configuracionReautorizacion) {
        configuracionReautorizacionDTO.setTieneRolesOServiciosAsociados(!(CollectionUtils.isEmpty(configuracionReautorizacion.getRolesAplicacionEdesk()) && CollectionUtils.isEmpty(configuracionReautorizacion.getRolesAplicacionEdesk())));
    }

}

The mapper works perfectly but the @AfterMappingmethod is never called. I read other post that shows examples using abstract class instead of interface.

Is using abstract class mandatory for use @AfterMapping annotation?



Solution 1:[1]

You can't pass the object (that is assumed to be immutable). You should pass the builder.. like this:

@Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface ConfiguracionReautorizacionMapper {

    ConfiguracionReautorizacionDTO toConfiguracionReautorizacionDTO(final ConfiguracionReautorizacion configuracionReautorizacion);

    ConfiguracionReautorizacion toConfiguracionReautorizacion(final ConfiguracionReautorizacionDTO configuracionReautorizacionDTO);

    @AfterMapping
    default void fillServiciosAsociados(@MappingTarget final ConfiguracionReautorizacionDTO.Builder configuracionReautorizacionDTO, final ConfiguracionReautorizacion configuracionReautorizacion) {
        configuracionReautorizacionDTO.setTieneRolesOServiciosAsociados(!(CollectionUtils.isEmpty(configuracionReautorizacion.getRolesAplicacionEdesk()) && CollectionUtils.isEmpty(configuracionReautorizacion.getRolesAplicacionEdesk())));
    }

}

Checkout out MapStruct issue 1556.. You can also disable builders from 1.3.1 onwards

Solution 2:[2]

When you are using Lombok builder and mapstruct together. @AfterMapping is not much useful though you pass a Builder object, since we can't retrieve the processed values. Instead I have used the custom method in my mapper to resolve this issue.

@Mapping(target ="field", expression = "java(customMethod(obj))")

this solved my use case, hope it helps others too.

Solution 3:[3]

As mentioned in the comments the issue is because you are likely using Lombok Builder annotation for ConfiguracionReautorizacionDTO and ConfiguracionReautorizacion and possibly any of the nested classes of these classes. AfterMapping functionality does not play well with Lombok Builder. Again Lombok generally works with MapStruct, it seems Builder annotation is a specific issue. See if you can create the classes without using Builder annotation and then AfterMapping functionality should work as expected.

Solution 4:[4]

Thanks to @Sjaak answer which is the legit answer. For my case this worked:

 myAfterMapping(...,@MappingTarget MyBean.MyBeanBuilder<?, ?> myBean,...){
 myBean.id(someValue);
 }

MyBeanBuilder is autogenerated (@Builder).

Solution 5:[5]

This is a comment but can't fit in the comment section.

If someone is gonna use @raji's answer, you must pay attention to the name of the variable you pass to customMethod

instead of obj you must put the name of the variable in your mapper method.

for Example:

@Mapping(target ="name", expression = "java(resolveName(userModel))")
UserDTO toDTO(User userModel);


default String resolveName(final User model) {
    return String.format("%s %s", model.firstName, model.lastName);
}

Solution 6:[6]

It is a bug when using Lombok#@Builder and Mapstruct@AfterMapping

Please use this situation @BeanMapping(builder = @Builder(disableBuilder = true)).

see https://github.com/mapstruct/mapstruct/issues/1556#issuecomment-1011493330

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Sjaak
Solution 2 raji
Solution 3 Grizzled DevArch
Solution 4 LovaBill
Solution 5 Tarun Kolla
Solution 6 Xuanyu