Guice injections on named string fields
Solution 1
Let me just summarize some of the comments already made here ...
- You forgot the
@Inject
Annotation - I would strongly advise to keep Guice/Injector outside of
FizzFuzz
. Use the static main method to bootstrap your App (notrun()
). - Binding String to a constant can easily be done via
bindConstant
.
Ths brings you to something like this:
public class FizzFuzz {
@Inject
@Named("red")
private String service;
public static void main(String[] args) {
FizzFuzz fizzFuzz = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bindConstant().annotatedWith(Names.named("red")).to("red-service");
}
}).getInstance(FizzFuzz.class);
System.out.println(fizzFuzz.service);
}
}
Solution 2
You've forgotten @Inject
before @Named("Red")
.
Also using bindConstant() is prefferable for such things.
P.S. why do you receive String
from inj instead of FizzBuzz
?
Solution 3
It should be more pretty with my way.
Create first your annotation
@Retention(RetentionPolicy.RUNTIME)
public @interface InjectSetting {
String value();
}
Create your guice module
@Slf4j
public class SettingModule extends AbstractModule {
private final Properties properties;
private SettingModule(Properties properties) {
this.properties = properties;
}
@Override
protected void configure() {
binder().bindListener(Matchers.any(), listener(((type, encounter) -> {
for (Field field : type.getRawType().getDeclaredFields()) {
if (field.isAnnotationPresent(InjectSetting.class)) {
field.setAccessible(true);
encounter.register(injector(instance -> {
try {
Object value = properties.get(
field.getAnnotation(InjectSetting.class).value());
field.set(instance, parse(value, field));
} catch (IllegalAccessException e) {
binder().addError(e);
}
}));
}
}
})));
}
TypeListener listener(BiConsumer<TypeLiteral<?>, TypeEncounter<?>> consumer) {
return consumer::accept;
}
MembersInjector<Object> injector(Consumer<Object> consumer) {
return consumer::accept;
}
Object parse(Object value, Field field) {
Type type = field.getType();
if(type == boolean.class)
value = Boolean.parseBoolean(value.toString());
else if(type == int.class)
value = Integer.parseInt(value.toString());
return value;
}
public static Module of(String propertiesPath, String... more) {
Properties properties = new Properties();
try {
properties.load(Files.newInputStream(Paths.get(propertiesPath, more)));
} catch(Exception e) {
log.error("can't load config file {}", propertiesPath);
throw new RuntimeException(e);
}
return new SettingModule(properties);
}
}
And then inject your field
@InjectSetting("database.port")
private int port;
IAmYourFaja
my father is a principal at burgoyne intnl and got me this job programming lisp and development. I aspire to unittesting with a concentration in mobile platforms.
Updated on July 10, 2022Comments
-
IAmYourFaja almost 2 years
I have a class:
public class FizzBuzz { @Named("Red") private String redService; public static void main(String[] args) { GuiceTest testApp = new GuiceTest(); testApp.run(); } private void run() { Injector inj = Guice.createInjector(new MyModule()); redService = (String)inj.getInstance(String.class); // Should print "red-service" but is instead an empty string! System.out.println("redService = " + redService); } // ... Rest of class omitted for brevity } public class MyModule extends AbstractModule { @Override protected void configure() { bind(String.class).annotatedWith(Names.named("Red")).toInstance("red-service"); } }
In my module I instruct Guice to bind all
String.class
instances@Named
"Red" to the string instance "red-service", however I'm not seeing that in the outputted print statement. How am I using Guice incorrectly?