The short answer is that there's no silver bullet here :/
What you've written as a first solution is obvious and functional, and that's good. But as you highlight there is a nontrivial cost of extension.
The second solution you've sketched is something I recommend avoiding, mainly due to the requirement of calling Injector.getInstance(). The pitfall of it is that you sacrifice up-front checking of required bindings, since Guice won't know what Key you're requesting until runtime.
A third solution is to use member injection on the base class, but that suffers from a generally awkward design and the usual downsides of member injection.
A fourth solution, and I've seen gain popularity in practice, is to define a struct to hold the dependencies of the base class. This gives stability to your constructors and allows for extension of dependencies:
public static final BaseDependencies {
private final Dep1 dep1;
private final Dep1 dep2;
...
private final Dep1 dep;
@Inject BaseDependencies(...)
}
public class Base {
protected Base(BaseDependencies deps, String name) {
...
}
}
public class A extends Base {
@Inject A(BaseDependencies deps, @UsedAsName String name) {
super(deps, name);
}
}
All in all I think this pattern of inheritance is not all too frequent, probably because of the tendency to rely on composition. I mention that because the fourth imperfect solution seems to be "good enough" to make it through the day and move one, and so at least I'm not aware of many requests to improve on the situation. If you've got any ideas though I'd be curious to hear what other folks might be thinking about for an improvement.
Fred