Hi,
sorry for such a non-descriptive subject...
Longer version: I want to inject configuration values to a class from a Properties object. I.e., @Inject @Named and Names.bindProperties. I want to support all primitive types, their wrapper types, Strings and Guava's Optional of the previous types. The PropertiesModule from the sample project does that just fine.
I also want to support default values, in case a Properties object doesn't contain some key. I like field injection for that, as I can specify the default value nicely -- just by initializing the field. So I can have these 4 combinations (only for Strings, other types work the same):
@Inject @Named("a") private String a;
@Inject @Named("b") private String b = "default value";
@Inject @Named("c") private Optional<String> c;
@Inject @Named("d") private Optional<String> d = Optional.of("default value");
If a key is missing in the Properties object, I want an error to be detected in case of the field "a" above (it's mandatory). In all the other cases, there is a default value to be applied. In case of "b", the field should keep its original value of "default value". In case of "c", a value of Optional.absent() should be injected. And in case of "d", the field should again keep its original value of Optional.of("default value").
What I'm doing in the sample project is
bind(new TypeLiteral<Optional<String>>() {}).annotatedWith(Named.class).toInstance(Optional.absent());
This solves the case "c", but also breaks case "d", because its value is overwritten to Optional.absent(). When it comes to case "b", I have no idea. I could do something similar, like
bind(new TypeLiteral<String>() {}).annotatedWith(Named.class).toInstance("");
But that wouldn't actually work. It would overwrite the value of "b" and it would suppress an error in case "a".
I would be able to do everything I need if I knew the class that is being injected. But in that case, I can just get rid of @Inject and do everything by hand, it's not that hard (that of course depends on the lifecycle, but fortunately, in the real project, I have the lifecycle under control). However, I'd really like to stick with Guice injection, because it does good error detection and if I ever needed more complex configuration values, esp. of generic types, the handrolled solution would become much more complex.
I've seen the OptionalBuilder in the multibindings extension in Guice master, but I don't think it would help me. I've also seen
https://github.com/timboudreau/giulius, which does something very similar, but solves the default values differently. I understand that my way can only work for field injection and prevents immutability, but that's a restriction I can live with.
I'm mostly a Guice newbie, so maybe what I'm trying to do here goes against the Guice philosophy. In that case, what would be your advice?
Thank you very much!
LT