What you are trying to do is emulate the SELF type in Java using generics. See this link or a different site for some means to do so. However, there is no way to enforce that F (or the SELF type) is actually the same type, for example (see type parameter of ConcreteFoo2):
static class Bar implements FooListener<ConcreteFoo, Bar> {
@Override
public void callback(final ConcreteFoo foo) {
// TODO Auto-generated method stub
}
}
static class ConcreteFoo2 extends AbstractFoo<ConcreteFoo, Bar> {
protected ConcreteFoo2(final Class<Bar> listenerClass) {
super(listenerClass);
}
}
static class ConcreteFoo extends AbstractFoo<ConcreteFoo, Bar> {
protected ConcreteFoo(final Class<Bar> listenerClass) {
super(listenerClass);
}
}
Instead of further going this way, I would first think about the design choices made that led you here:
Maybe fewer type parameters are actually the solution, relying on the interfaces alone.
EDIT: One possible solution, if you don't want to cast (F) this
would be to provide an abstract method protected abstract F getSelf();
that the concrete implementations implement by returning this
.
See this simplified code for example:
static final class Bar implements FooListener<ConcreteFoo> {
@Override
public void callback(final ConcreteFoo foo) {
// TODO Auto-generated method stub
}
}
static final class ConcreteFoo extends AbstractFoo<ConcreteFoo> {
protected ConcreteFoo(final Class<? extends FooListener<ConcreteFoo>> listenerClass) {
super(listenerClass);
}
@Override
protected ConcreteFoo getSelf() {
return this;
}
}
static abstract interface FooListener<FOO extends AbstractFoo<FOO>> {
void callback(FOO abstractFoo);
}
static abstract class AbstractFoo<SELF extends AbstractFoo<SELF>> {
private final Class<? extends FooListener<SELF>> listenerClass;
protected AbstractFoo(final Class<? extends FooListener<SELF>> listenerClass) {
this.listenerClass = listenerClass;
}
protected abstract SELF getSelf();
// Bar might implement FooListener, but I don't control it,
// so I have no guarantee
public void externalMethod(final Bar bar) {
if (listenerClass.isInstance(bar)) {
final FooListener<SELF> listener = listenerClass.cast(bar);
listener.callback(getSelf()); // compiles
}
}
}