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