1

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 ?

Taras K
  • 85
  • 2
  • 9

3 Answers3

3

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)
Filip
  • 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
0

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
0

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 );

Community
  • 1
  • 1
Taras K
  • 85
  • 2
  • 9
  • 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