Skip to content
Advertisement

Generic method to return function returning generic self-type without the need to cast

Honestly, I’m not even sure whether that title makes sense. Hopefully the code following will explain the issue at hand.

package what.ever.you.like;

import java.util.function.UnaryOperator;

class SelfTypeTemplates {

    public static <SELF extends AbstractSelfType> UnaryOperator<SELF> simpleBound() {
        return self -> self;
    }

    public static <SELF extends AbstractSelfType<SELF>> UnaryOperator<SELF> boundWithGenericType() {
        return self -> self;
    }
}

class ConcreteSelfType extends AbstractSelfType<ConcreteSelfType> {

    public ConcreteSelfType() {
        super(ConcreteSelfType.class);
    }

    public ConcreteSelfType applySimpleBound() {
        // How to get rid of the type cast?
        return (ConcreteSelfType) SelfTypeTemplates.simpleBound().apply(this);
    }

    public ConcreteSelfType applyBoundWithGenericType() {
        // Compile error because `this` is ConcreteSelfType, but required is SELF
        return SelfTypeTemplates.boundWithGenericType().apply(this);
    }
}

class AbstractSelfType<SELF extends AbstractSelfType<SELF>> {
    protected final SELF myself;

    protected AbstractSelfType(final Class<?> type) {
        this.myself = (SELF) type.cast(this);
    }
}

My issue is with the two methods applySimpleBound() and applyBoundWithGenericType(). The former is compiling fine, but needs explicit casting, which is what I’d like to get rid of. The later does not compile, because .apply(this) requires a type SELF but provided is ConcreteSelfType.

So my question is, how do I specify the signature of a method in SelfTypeTemplates to return an UnaryOperator<SELF> so that invoking the returned function (.apply(this)), does not need casting in the client code (i.e. ContreteSelfType)?

Tried to play with different bounds in the generic and return type. Haven’t found a working version without type casting.

Advertisement

Answer

Sometimes the compiler cannot infer the correct type for what ever reason. To work around this issue you can specify it like this:

class ConcreteSelfType extends AbstractSelfType<ConcreteSelfType> {

    public ConcreteSelfType() {
        super(ConcreteSelfType.class);
    }

    public ConcreteSelfType applySimpleBound() {
        // How to get rid of the type cast?
        return SelfTypeTemplates.<ConcreteSelfType>simpleBound().apply(this);
    }

    public ConcreteSelfType applyBoundWithGenericType() {
        // Compile error because `this` is ConcreteSelfType, but required is SELF
        return SelfTypeTemplates.<ConcreteSelfType>boundWithGenericType().apply(this);
    }
}

Both options compile this way and you don’t need a cast.

Advertisement