I worked on a project once that had a similar requirement - in my case it was a codebase littered with code to load legacy properties files, scattered throughout it, and I wanted to get that code out of the business of reading files and having to know where they were, and use @Named for the property values. So I needed a way to annotate different packages with the name of what they needed to load.
I don't know if I'd do it again like this, but the solution was this feature of Giulius, a micro-framework on top of Guice for loading settings and application lifecycle:
- A runtime annotation on classes or packages identifies which "namespace" (in your case, a name that specifies which back end) to use
- An annotation processor puts a flat list of all known names used for that into META-INF, which is used when setting up bindings
- A custom Provider will provide the Properties (or in your case, the Client)
- A ProvisionListener wraps the call to actually do injection - when called it
- Looks up the class being instantiated
- Looks for the annotation on the class
- If not present, looks for the annotation on the package and all parent packages, failing over to a default if none present
- Sets a ThreadLocal with the current "namespace" or "context" (important: this can be called reentrantly, so save the old value of the ThreadLocal and restore it after provisioning)
- The custom Provider looks in the ThreadLocal and provides a different object depending on what it contains
https://github.com/timboudreau/giulius/blob/master/giulius/src/main/java/com/mastfrog/giulius/Dependencies.java#L626Hope that provides some inspiration,
Tim