Interface A and its implementation:
public interface A<K, E> {
public void foo();
}
public abstract class AImpl<K, E> implements A<K, E> {
public void foo(){};
}
Interface B, which extends interface A, and its implementation:
public interface B extends A<Integer, String> {
public void bar();
}
public class BImpl extends AImpl<Integer, String> implements B {
public void bar(){};
}
An abstract class C, which gets A injected:
public abstract class C<K, E> {
A<K, E> a;
@Inject
public setA(A<K, E> a){
this.a = a;
}
public A<K, E> getA(){
return a;
}
}
With Guice:
bind(new TypeLiteral<A<Integer, Book>>(){}).to(BImpl.class);
And the last class, which extends class C:
public class D extends C<Integer, String> {
public void fooBar(){
this.getA().bar(); //Gets BImpl injected by Guice, and call bar(): Not working - error
((B) this.getA()).bar(); //Working
}
}
Like you can see from inline comments, BImpl gets properly injected and can be used, if it has no additional methods, that extends A (interface B is empty). If I add any new method in B, I can’t call it in D without it casting to B. My main goal is, giving a user possibility to extend A and use this functionality in D.
If the user needs the functionality provided by
Bbut notA, they should declare that they need aB. ClassDshould declare what it needs – not rely on casting to make sure it was correctly configured beyond what was declared.