elect
elect

Reputation: 7190

How can I call the corresponding method given the generic type argument?

I have a method having a generic type T as argument

private static <T> void doValidation(T[] pArray, int size, String firstName, String secondName) {

    ...

    for (int i = 0; i < size; i++) {

        ...

        validate(pArray[i]);
    }
}

And then I have different method given the specific type, such as A, B, etc..

private static void validate(A a) {

}

private static void validate(B b) {

}

I would like it to resolve the type in runtime and call the corresponding method based on the type, is it possible?

At the moment I get

no suitable method found for validate(T)
    method ValidateDataStructure.validate(A) is not applicable
      (argument mismatch; T cannot be converted to A)
    method ValidateDataStructure.validate(B) is not applicable
      (argument mismatch; T cannot be converted to B)
  where T is a type-variable:
    T extends Object declared in method <T>doValidation(T[],int,String,String)
----
(Alt-Enter shows hints)

It wants me to cast of course the argument..

I am trying to do a port of Assimp, my intent is to be as much as possible close to the C structure. This is the function I am trying to port right now..

Upvotes: 1

Views: 90

Answers (2)

davmac
davmac

Reputation: 20631

Depending on your exact needs, which aren't totally clear from your question, you have some options.

It seems like you probably don't actually need your doValidation method to behave differently depending on T, but rather your validate method to behave differently depending on the run-time type of its argument. This is a somewhat different problem, but it is easily solvable: the best option is probably to have it delegate to an overridable method, something like:

private static <T extends Validatable> void validate(T arg)
{
    arg.validate();
}

(You need to define an appropriate Validatable interface of course, and the T type parameter in the doValidation method also needs to be declared as T extends Validatable).

However, the above option requires that you can modify classes A and B (make them implement Validatable). Another option, not nearly as clean from a design point of view but without this limitation, is to determine the type and dispatch to a different method accordingly, by introducing a validate method with an Object argument as follows:

private static void validate(Object arg)
{
    if (arg instanceof A) {
        validate((A) arg);
    }
    else if (arg instanceof B) {
        validate((B) arg);
    }
    else {
        throw new RuntimeException("Don't know how to validate object of class " + arg.getClass.getName());
    }
}

Upvotes: 0

Tagir Valeev
Tagir Valeev

Reputation: 100209

If you want to validate types you cannot extend (e.g. Integer, String), you may implement your own dynamic dispatching. For example, you can create a map of validators like this (Java-8):

private static final Map<Class<?>, Consumer<?>> validators = new HashMap<>();

static {
    validators.put(A.class, (A a) -> validate(a));
    validators.put(B.class, (B b) -> validate(b));
    ...
}

And write a selector method:

static <A> Consumer<A> getValidator(Class<A> clazz) {
    // do nothing for unknown type
    return (Consumer<A>)validators.getOrDefault(clazz, () -> {});
}

Finally you can use it like this:

getValidator(value.getClass()).validate(value);

Upvotes: 1

Related Questions