简体   繁体   中英

Can I autowire a Spring bean into a MapStruct interface?

I am using MapStruct and to do that I have to define an interface with an according mapping function. It is possible to implement some logic by using a default method annotated with @BeforeMapping and @AfterMapping . In such an annotated default method I want to use a configuration class of my SpringBoot application. How can I do this? Can I autowire such a configuration (bean) into an interface? How should such a code look like?


From the documentation and your hint I found out that I can use either a @Context variable or an abstract class instead of using an interface.

I tried both then. Using an abstract class it worked well as demanded but using a @Context variable the default method gets not invoked.

Here's the main mapping method:

@Mapping(target = "myTarget.partNumber", ignore = true)
public MyTarget mapSource2Target(final MySource mySource, final PartNumberMapConfiguration partNumberMapConfiguration);

and the afterMapping method:

@AfterMapping
default void afterMapping(final @MappingTarget MyTarget target, final MySource source, final @Context PartNumberMapConfiguration partNumberMapConfiguration) {. . . }

When I reach the breakpoint where the mapper is invoked, I cannot step into the mapping method. It just steps over...and the code of the afterMapping method is not executed.

Here's the class I intend to use as with @Context:

@Component("PartNumberMap")
@PropertySource("classpath:abc.properties")
@ConfigurationProperties(prefix = "abc")
public class PartNumberMapConfiguration {
    
    private Map<String, String> partNumberMap = new HashMap<String, String>();
    
    public Map<String, String> getPartNumberMap() {
        return partNumberMap;
    }
    
    public void setPartNumberMap(final Map<String, String> partNumberMap) {
        this.partNumberMap = partNumberMap;
    }
}

You can't autowire a bean into an interface. However, you can use the @Context from MapStruct 1.2.0.

For example:

@Mapper
public interface MyMapper {


    Target map(Source source, @Context MyCustomService service);

    @AfterMapper
    void after(Source source, @MappingTarget Target target, @Context MyCustomService service) {
        // Do what you need here
    }
}

Another option would be to use an abstract class instead of an interface.

@Mapper
public abstract class MyMapper {

    private MyCustomService service;


    public abstract Target map(Source source);


    @AfterMapping
    protected after(Source source, @MappingTarget Target target) {
        // Use the service here
    }

    @Autowired
    public void setService(MyCustomService service) {
        this.service = service.
    }    
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM