I'm using jersey and Guice DI and I want to use Mapstruct interfaces
with @Inject
annotation.
So is there some way to force Guice to autowire Mapstruct interface implementations ?
3 Answers
You can configure the implementations of the Mappers to be annotated with JSR 330 annotation by using @Mapper(componentModel = "jsr330")
. You can find more information in the reference documentation
.
You can then bind the Mapper interface with the implementation class in your modules.
One way to bind them is to use Guice Linked Bindings:
bind(MyDtoMapper.class).to(MyDtoMapperImpl.class)
Another way to bind them is to use Instance Bindings:
bind(MyDtoMapper.class).toInstance(MyDtoMapper.INSTANCE)

- 19,269
- 7
- 51
- 60
-
Thanks @filip for fast respond ! `componentModel = "jsr330"` really handy thing. It adds `@javax.inject.Named` and `@javax.inject.Singleton` to mapper implementation but when I'm trying to Inject it using setter like this `@Inject void setBeanMapper(@Named BeanMapper beanMapper) { this.beanMapper = beanMapper; }` it tries to find implementation for BeanMapper annotated with `@com.google.inject.name.Named(value=)` and it fails =( Have you any idea how to resolve this ? – Taras K Apr 13 '17 at 09:17
-
I don't have much experience with guice, maybe we need to add an example for a setup with guice. Which `@Inject` and `@Named` are you using in your setter? Maybe guice does not work with mixed annotations, maybe they need to come from `javax.inject` as well. – Filip Apr 13 '17 at 14:03
-
hi could you please check https://stackoverflow.com/questions/64770274/how-to-inject-guice-dependency-in-mapstruct-interface-java i tried but cant able to inject correctly – Jeya Kumar Nov 11 '20 at 06:34
Ran into issues with using Guice and the jsr330 componentModel, though I don't recall what they were exactly. My use case was a bit more complex because I needed to pass in another service to a mapper decorator as well. Should work for your simple case as well. Ended up doing provider methods in the Guice Module, like so:
public YourModule extends AbstractModule {
//With Decorator
@Provides
@Singleton
FooMapper providesFooMapper(RequiredService requiredSvc) {
FooMapper mapper = Mappers.getMapper(FooMapper.class);
((FooMapperDecorator) mapper).setRequiredService(requiredSvc);
return mapper;
}
//Simple Mapper with no dependencies
@Provides
@Singleton
BarMapper providesBarMapper() {
return Mappers.getMapper(BarMapper.class);
}
}
Works without a hitch, though I would like for the simple case to be handled by MapStruct cleanly at some point. I'll also note that I only use constructor injection; should work the same for setter injection but YMMV.
-
There is already an open issue to support constructor and / or field injection in MapStruct. Follow [this](https://github.com/mapstruct/mapstruct/issues/571) issue if you want to track the status. – Filip Jun 08 '17 at 17:48
Thx @Filip. So yeah @Mapper(componentModel = "jsr330")
almost made all work only thing I had to create binding for each mapper that I use directly in my code bind(MyDtoMapper.class).toInstance(MyDtoMapper.INSTANCE)
and INSTANCE is declared in MyDtoMapper interface this way: MyDtoMapper INSTANCE = Mappers.getMapper( MyDtoMapper.class );
-
I update my answer with your example and the Linked Bindings from Guice. I would prefer to use that as the `Mappers` from MapStruct are thought to be used with the default implementation – Filip May 05 '17 at 17:31