0

Let me start with a disclaimer on possible duplicate... I did try to pore over a few questions on this topic but they did not represent my challenge on what I want to achieve. So kindly bear with me and help with a solution.

Here is my situation: I have an interface (in command pattern) as below for which I need an implementation for.

public interface IIntelligentAction<E> {
    /**
     * Set dynamic variable for this action.
     */
     public void setDynamicOperand(Callable<?> getter);

    /*
     * Set validating operand for this action.
     */
     public void setValidatingOperand(Callable<?> getter);

    /*
     * The implementation must check if the operands (dynamic and validating) are 
     * compatible with each other for this action. 
     */
     public boolean areOperandsCompatible();

    /*
     * Execute this action.
     * <p> The implementation must check for both operands being assigned and are
     * compatible with each other, before allowing the action to execute.
     */
     public void execute();

}

The design of the interface is intentional and I understand the rationale (for ex., Date and Calendar are semantically compatible but not type compatible.

Now my concern is in the areOperandsCompatible() method. As can be seen, the method accepts a parameterised Callable, so by reflection I will always see Callable but not the type it will return. How do I get access to the parameterised type of the generic instance I get from the setter methods?

Cup of Java
  • 1,769
  • 2
  • 21
  • 34
Sathya SN
  • 51
  • 5
  • I don't think it's possible due to type erasure. You can pass a class to the method along with the `Callable` and then utilize that at runtime if needed. – Jacob G. Apr 25 '17 at 01:48
  • Your `Callable`s don't have any type parameter, they use a wildcard type. It's not clear what you're trying to check. It's also not clear where `` comes into play. Did you mean to do `Callable`? – shmosel Apr 25 '17 at 02:10
  • You might be able to use the construct talked about [here](http://stackoverflow.com/q/1901164/2891664), but that only works if you have a subclass which provides a concrete type argument, like `class MyCallable implements Callable {...}`. If you have a `class MyCallable implements Callable {...}` then the reflection doesn't work. Passing a `Class` is a lot easier than any other option if you don't understand when/why the reflection works. – Radiodef Apr 25 '17 at 02:38
  • Did you manage to find a solution? I have a similar requirement to compare compatibilities of generic types, for example `Date` and `Calendar` are semantically compatible but not type compatible in Java. Your solution will help me a lot. – Sathya SN May 31 '18 at 02:47

1 Answers1

0

The way I have finally realised the solution for this question was with the following:

public Class<?> getGenericsTypeDeclared(Object any) {
        List<Type> classScope = new ArrayList<Type>();
        classScope.add(any.getClass());
        classScope.add(any.getClass().getGenericSuperclass());

        for (Type type : any.getClass().getGenericInterfaces())
            classScope.add(type);

        Class<?> genericType = null;

        for (Type type : classScope) {
            try {
                genericType = (Class<?>) ((ParameterizedType) type).getActualTypeArguments()[0];
            } catch (ClassCastException e) {
                if (logging != null)
                    logging.warn("Ignoring non-generic type: " + type);
            } catch (ArrayIndexOutOfBoundsException e) {
                if (logging != null)
                    logging.warn("Oddly Generic type without parameters. Found: " + type);
            }

            if (genericType != null) {
                return genericType.getClass();
            }
        }

        return null;
    }

The approach uses native java and so no need for any 3rd party libraries. Hope it helps for others searching for similar needs.

Sathya SN
  • 51
  • 5