MapStruct with Dagger Injection

jsr330componentModel 配合CONSTRUCTORInjectionStrategy可以与Dagger配合使用。

定义Mapper,并在map的同时完成解密:

package net.axqd.mapper;

import org.mapstruct.InjectionStrategy;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;

@Mapper(componentModel = "jsr330",
    uses = DecryptorQualifier.class
    injectionStrategy = InjectionStrategy.CONSTRUCTOR)
public interface AToBMapper {
    @Mapping(
        source = "src.encrypted",
        target = "decrypted",
        qualifiedByName = { "DecryptorQualifier", "decrypt" })
    B mapAToB(final src)
}

其中,DecryptorQualifier的定义如下:

package net.axqd.mapper;

import lombok.NonNull;
import org.mapstruct.Named;
import javax.inject.Inject;

@Named("DecryptorQualifier")
public class DecryptorQualifier {
    private final Service service;

    @Inject
    public DecryptorQualifier(@NonNull final Service service) {
        this.service = service;
    }

    @Named("decrypt")
    public String decrypt(final String encrypted) {
        return service.decrypt(encrypted);
    }
}

定义Mapper的Provider:

package net.axqd.dagger;

import net.axqd.mapper.AToBMapper;
import net.axqd.mapper.AToBMapperImpl;

import dagger.Module;
import dagger.Provides;
import javax.inject.Singleton;

@Module
public class MapperModule {
    @Provides
    @Singleton
    AToBMapper aToBMapper(final DecryptorQualifier qualifier) {
        return new AToBMapperImpl(qualifier);
    }
}

定义Component:

import dagger.Component;
import javax.inject.Singleton;

@Component(modules = {
    MapperModule.class
})
@Singleton
public interface FooBarComponent {
    ...
}

单元测试:

package net.axqd.mapper;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
public class AToBMapperTest {
    private static final String ENCRYPTED = "encrypted";
    private static final String DECRYPTED = "decrypted";

    @Mock
    private DecryptorQualifier qualifier;

    @InjectMocks
    private AToBMapperImpl mapper;

    @Test
    public void aToBMapper_when_xxx() {
        when(qualifier.decrypt(ENCRYPTED)).thenReturn(DECRYPTED);

        final A a = A.builder().xxx.build();
        final B b = mapper.mapAToB(a);

        assertEquals(...);
    }
}