Question

Sorry in advance for any bad english language in this question.

I have in mind to create a sort of factory which can only create instances of classes defined in a list implemented by a concrete factory instance class. First, i defined this interface :

public interface ValuesSystem {

    public interface AllowedValue<T extends Class<? extends SystemValue>>{};

    AllowedValue<Class<? extends SystemValue>> getAllowedValue(Enum<?> id);

    Map<? extends Enum<?>, AllowedValue<Class<? extends SystemValue>>> getAllowedValues();

    <T extends SystemValue> T create(AllowedValue<Class<T>> allowedClass, ValueData data) throws InvalidValueException;
}

The interface AllowedValue is just a "marker wrapper" interface using generics to define a Class instance "allowed" to be create by my factory.

The getAllowedValue is a method used to get a wrapped allowed Class instance from my allowed Class "list" using an internal enumeration from a concrete class implementing this interface (example of a concrete class will come).

The create method is intended to finally create an instance of my allowed Class instance given in the allowedClass argument.

Here is an example of a concrete class implementing this interface :

public class BasicValueSystem implements ValuesSystem {

    public BasicValueSystem() {
        super();
        allowedValues = (Map<VALUES_ID, AllowedValue<Class<? extends SystemValue>>>) getAllowedValues();
    }

    public static enum VALUES_ID {
        MODIFIER
    }

    private static Map<VALUES_ID, AllowedValue<Class<? extends SystemValue>>> allowedValues;

    private class BasicAllowedValue<T extends Class<? extends SystemValue>>
            implements AllowedValue<Class<? extends SystemValue>> {

    }

    @Override
    public <T extends SystemValue> T create(
            AllowedValue<Class<T>> allowedClass, ValueData data)
                throws InvalidValueException {
        if (!(allowedClass instanceof BasicAllowedValue)) {
            throw new InvalidValueException();
        }
        return null;
    }

    @Override
    public AllowedValue<Class<? extends SystemValue>> getAllowedValue(Enum<?> id) {
        return allowedValues.get(id);
    }

    @Override
    public Map<? extends Enum<?>, AllowedValue<Class<? extends SystemValue>>> getAllowedValues() {
        Map<VALUES_ID, AllowedValue<Class<? extends SystemValue>>> allowed = new EnumMap<VALUES_ID, AllowedValue<Class<? extends SystemValue>>>(VALUES_ID.class);
        allowed.put(VALUES_ID.MODIFIER, new BasicAllowedValue<Class<ModifierValue>>());
        return allowed;
    }
}

For the moment the create method return null, but the problem is elsewhere and this not the point of my question

The problem occurs when I tried to create an instance of one of my "allowed" values instance with the following code :

BasicValueSystem bvs = new BasicValueSystem();
AllowedValue<Class<? extends SystemValue>> allowed = bvs
    .getAllowedValue(BasicValueSystem.VALUES_ID.MODIFIER);
bvs.create(allowed, new ModifierValueData());

The compiler tells me :

The method create(ValuesSystem.AllowedValue<Class<T>>, ValueData) in the type BasicValueSystem is not applicable for the arguments (ValuesSystem.AllowedValue<Class<? extends SystemValue>>, ModifierValueData)

I think i missed something concerning the type inference made by generics in general.

Can anyone can explain me the create method signature is not applicable in this case and how to fix it ?

Thanks in advance for taking your time.

Was it helpful?

Solution

Note that public interface AllowedValue<T extends Class<? extends SystemValue>> does not make much sense. The only valid type for T would be Class<? extends SystemValue> as the class Class is final and can’t have subclasses. So you can replace it with interface AllowedValue<Class<? extends SystemValue>> without any change in the semantic, but what you really mean (imho) is interface AllowedValue<T extends SystemValue>. Don’t mess around with Class in a type signature. The interface still might have methods referring to Class<T> then.

public interface ValuesSystem {

  public interface AllowedValue<T extends SystemValue>{};

  AllowedValue<? extends SystemValue> getAllowedValue(Enum<?> id);

  public <T extends SystemValue> T create
                     (AllowedValue<T> allowedClass, ValueData data);
}

Adapt the implementation accordingly, BasicAllowedValue becomes

private class BasicAllowedValue<T extends SystemValue> implements AllowedValue<T>

Then your problem with the using code disappears.

BasicValueSystem bvs = new BasicValueSystem();
AllowedValue<? extends SystemValue> allowed = bvs
    .getAllowedValue(BasicValueSystem.VALUES_ID.MODIFIER);
bvs.create(allowed, new ModifierValueData());

will compile.


Note that if AllowedValue shall remain a marker interface without methods only, it is unnecessary, Class<T> already fulfills this role. It will also work when doing it like this:

public interface ValuesSystem {
  Class<? extends SystemValue> getAllowedValue(Enum<?> id);
  public <T extends SystemValue> T create(Class<T> allowedClass, ValueData data);
}

and

BasicValueSystem bvs = new BasicValueSystem();
Class<? extends SystemValue> allowed = bvs
    .getAllowedValue(BasicValueSystem.VALUES_ID.MODIFIER);
bvs.create(allowed, new ModifierValueData());
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top