Search code examples
guice

Question on guice construction injection when there is an additional parameter to the constructor


I'm using guice-4.1.0. The output of the following code is in b, host:. I was expecting an error. Because nowhere was host explicitly given to the constructor. Any idea?

package com.mycompany.app;

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;

public class App
{
    public static void main( String[] args )
    {
        Injector injector = Guice.createInjector(new AppModule());
        Client client = injector.getInstance(Client.class);
        client.foo();
    }
}

class AppModule extends AbstractModule {
    @Override
    protected void configure() {  
        bind(B.class).to(BImpl.class);
    }
}

class Client {
    private B b;

    @Inject
    public Client(B b) {
        this.b = b;
    }

    public void foo() {
        System.out.println(b.foo());
    }
}

interface B {
    String foo();
}

class BImpl implements B {
    private String host;

    @Inject
    public BImpl(String host) {
        this.host = host;
    }

    public String foo() {
        return "in b, host: " + host;
    }
}

Solution

  • This is happening because String class provides and empty constructor. When Guice sees a String is being injected, it tries to find a binding for String or else invoke the empty constructor of the String class.

    From Java's String class code

    /**
     * Initializes a newly created {@code String} object so that it represents
     * an empty character sequence.  Note that use of this constructor is
     * unnecessary since Strings are immutable.
     */
    public String() {
        this.value = "".value;
    }
    

    As you can see, it sets the value to "". This is the reason you are seeing an empty String being printed in the output.

    Try the same thing with Integer for example and you will get

    Could not find a suitable constructor in java.lang.Integer. Classes must have either one (and only one) constructor annotated with @Inject or a zero-argument constructor that is not private. at java.lang.Integer.class(Integer.java:52)