Guice assisted inject with multiple constructors always calls the default constructor

2.6k views Asked by At

I have a class which has two constructors. I am trying to create instances of this class using a guice factory. If no parameter is passed, then default constructor should be called. If a parameter is passed, then constructor with parameter should be called. But currently even if I pass a parameter to the factory method, still the default constructor is getting called. Constructor with parameter is not at all getting called. Below is my factory class.

public interface MapperFactory {

PigBagMapper createPigBagMapper(@Assisted("pigMetaInfoList") List<String> sourceMetaInfoList);

JsonMapper createJsonMapper(@Assisted("apiName") String apiName) throws EndpointNotFoundException, JsonMapperException;

JsonMapper createJsonMapper();

}

Below are the constructors I am trying to inject.

@AssistedInject
public JsonMapper() {
    handlers = new LinkedList<>();
}

 @AssistedInject
 public JsonMapper(@Assisted("apiName") String apiName) throws EndpointNotFoundException, JsonMapperException {
    somelogic();
}

Below is my module binding in Abstract Module implementing class.

install(new FactoryModuleBuilder()
            .implement(PigBagMapper.class, PigBagMapperImpl.class)
            .implement(JsonMapper.class, JsonMapperImpl.class)
            .build(MapperFactory.class));

Below is how I am calling the constructor.

mapperFactory.createJsonMapper(apiName);

What am I doing wrong here? Any help would be much appreciated.

EDIT:

Please note that the JsonMapperImpl class has no constructor. It just has a public method and that's all.

1

There are 1 answers

1
Lachezar Balev On

I see two issues.

Issue 1: You do not need to annotate the factory methods with @Assisted

Issue 2: Guice will try to create an isntance of JsonMapperImpl when you use the factory. It will scan for proper JsonMapperImpl contructors annotated with @AssistedInject. There are none. You can't invoke new JsonMapperImpl("xyz"), for example. This will be a compile time error, because The constructor JsonMapperImpl(String) is undefined.

You also do not have constructors annotated with @AssistedInject in JsonMapperImpl. It is empty.

If you rewrite your class in a similar way:

public class JsonMapperImpl extends JsonMapper
{
    @AssistedInject
    public JsonMapperImpl() {
        super();
    }

     @AssistedInject
     public JsonMapperImpl(@Assisted String apiName) {
         super(apiName);
    }
}

And:

public class JsonMapper
{
    private String apiName;

    public JsonMapper() {

    }

     public JsonMapper(String apiName) {
         this.apiName = apiName;
    }

    public String getAPI(){return apiName;}
}

then JsonMapperImpl will expose appropriate constructors and the code will work, e.g.:

JsonMapper noApi = factory.createJsonMapper();
JsonMapper api = factory.createJsonMapper("test");

System.out.println(noApi.getAPI());
System.out.println(api.getAPI());

Outputs:

null
test

Hope this helps.