ctabin
ctabin

Reputation: 243

Method Generics bound restriction with Class Generics

I am trying to make a somewhat strong typed API:

class PropertyType<T> { ... }
class SubType1<T> extends PropertyType<T> { ... }
class SubType2<T> extends PropertyType<T> { ... }

class PropertyHandler<K extends PropertyType<?>> { 

    // Here, the V generics is not related to the property type,
    // hence the value is not typed
    public <V> getValue(K prop) { ... }

    // In this case, we have correct typing, but T is not bounded to K
    public <V, T extends PropertyType<V>> getValue(T prop) { ... }

    // This would be a solution, but it doesn't compile because K is a type variable
    public <V, T extends K & PropertyType<V>> getValue(T prop) { ... }
}

And that is how it would be used:

PropertyHandler<SubType1<?>> ph = new PropertyHandler<>();

// I want to allow this
SubType1<Integer> p1 = new SubType1<>();
SubType1<Boolean> p2 = new SubType1<>();
Integer v1 = ph.getValue(p1);
Boolean v2 = ph.getValue(p2);

// I don't want to allow this
SubType2<Integer> p3 = new SubType2<>();
Boolean v3 = ph.getValue(p3);

Is there a way to solve this ? Maybe it's some architecture problem that can be handled differently ?

Upvotes: 2

Views: 86

Answers (1)

Danny Daglas
Danny Daglas

Reputation: 1491

The return type for getValue() must be added to the generic signature of PropertyHandler. Otherwise, there is no way for PropertyHandler to infer the getValue() return type from the generic definition of PropertyType.

Therefore, either assign both return type and property type to the PropertyHandler generic signature, or flip it by specifying the return type in PropertyHandler, and having PropertyHandler ensure the correct PropertyType parameter type, like this:

class PropertyType<T, H extends PropertyHandler<T>> {
    public T getValue() { ... }
}
class IntegerType extends PropertyType<Integer, PropertyHandler<Integer>> { ... }
class BooleanType extends PropertyType<Boolean, PropertyHandler<Boolean>> { ... }

class PropertyHandler<V> {
    public <T extends PropertyType<V, PropertyHandler<V>>> V getValue(T prop) {
        return prop.getValue();
    }
}

This is how you would use it:

PropertyHandler<Integer> ph = new PropertyHandler<>();
IntegerType p1 = new IntegerType();
Integer v1 = ph.getValue(p1); // works fine
BooleanType p3 = new BooleanType();
Boolean v3 = ph.getValue(p3); // compile time error

Upvotes: 1

Related Questions