I want to create an Annotation Processor which replaces the call to GWT.create
.
With an annotation processor, you'd have to generate both classes and then dynamically (at runtime) select among them, depending on the context (you could generate a factory to help doing that, but you'd still have to somehow feed the factory with the current context, e.g. the current locale).
– Source: https://stackoverflow.com/a/29915793/116472
I got my Annotation Processor running it generated the classes very well. The part I do not know is the runtime selection part.
How can I do this runtime selection?
I'll assume that you've got the code generation side covered, and only focus on how we might pick the correct implementation in GWT:
but you'd still have to somehow feed the factory with the current context, e.g. the current locale).
We could do this at runtime, as you suggest, but as of the recently added support for System.getProperty
you could also do this at compile time.
Step one, of course, is to generate the code for each implementation you might want to have access to. Taking locales as an example, you might have Foo_en.java
, Foo_es.java
, Foo_de.java
, etc.
Next, we need a consistent way to get any one implementation - perhaps a generated FooFactory
, with a method like this:
public static Foo getFoo(String locale) {
if ("en".equals(locale)) {
return new Foo_en();
} else if /*...
...*/
throw new IllegalArgumentException("Locale " + locale + " is not supported");
}
If you ask the user at runtime which locale they wanted, you could pass that value in to this factory method to get the implementation you wanted. Likewise, if you could read that value at runtime from something, you could again get the right instance and proceed forward.
But what if you actually want to make the compiler pick for you? Lets keep this code generated with the annotation processor, but move the phase of selecting a locale to the compiler and its permutations.
As in existing GWT code, specify a property for locale, and several values. Then, instead of asking the user or deciding at runtime in your own Java code which locale you want, use the same selection script wiring as GWT typically uses (checks the url, a cookie, meta tags, the user agent itself, etc) - you can construct your own property-provider
for this if you wanted.
As before, we can use getFoo(locale)
, but now we use System.getProperty
to read out the property that we created in our .gwt.xml file. This will be statically compiled out to the correct constant for each permutation. But rather than calling FooFactory.getFoo(System.getProperty("locale"))
each time we need an instance, lets make yet another method in our generated FooFactory:
public static Foo getFoo() {
return getFoo(System.getProperty("locale"));
}
Now we can just call FooFactory.getFoo()
, and we will get the correct class for our current permutation.
Dagger question: Thomas is likely far better suited to address this, but no, Dagger2 doesn't do bind(Foo).to(Bar).in(Scope)
like Guice does, since that would require running the code to resolve the bindings, whereas Dagger operates only from what it can see by reflecting on the types, and not actually running the code. This means you end up with a lot of these @Provides methods or annotating your actual types with details of what should be used to implement what.
FWIW so far I haven't adopted Dagger due to a few quirks that would require me to rethink a few bits, and I haven't taken the time to do that rethinking yet: