1

I am trying this example, but can't make it work; it throws The method getFromInt(int) is undefined for the type T

T is a generic enum type

public static <T> T deserializeEnumeration(InputStream inputStream) {
        int asInt = deserializeInt(inputStream);
        T deserializeObject = T.getFromInt(asInt);
        return deserializeObject;
    }

am calling the previous method as follows for example:

objectToDeserialize.setUnit(InputStreamUtil.<Unit>deserializeEnumeration(inputStream));

or

objectToDeserialize.setShuntCompensatorType(InputStreamUtil.<ShuntCompensatorType>deserializeEnumeration(inputStream));

or etc...

Salem Masoud
  • 411
  • 11
  • 32
  • 1
    What should `T` be? – Lino Jul 23 '18 at 11:55
  • @Lino it should be generic enum type – Salem Masoud Jul 23 '18 at 11:57
  • 1
    What exactly are you trying to do? – Spitzbueb Jul 23 '18 at 12:00
  • 3
    T in your code is an extend of java.lang.Object and getFromInt is not define for object – Arnault Le Prévost-Corvellec Jul 23 '18 at 12:00
  • @Wernerson I have some enums which all have getFromInt method, I want to use one generic object inside a generic method to pass a value to getFromInt regardless the type of the object. – Salem Masoud Jul 23 '18 at 12:05
  • 2
    I don't believe this is required to be generic for an enum. Enum is a type that can't be extended so it will ALWAYS be the same type. `public static MyEnum deserializeEnumeration(InputStream inputStream)` Now if you want more than one enum to be returned, you will need to pass the type as a parameter `public static T deserializeEnumeration(InputStream inputStream, Class type)` but again, `T` is just an `Object` so the method won't exist. You need a common type that declare `getFromInt` but I don't believe an `enum` can implement an interface, it can't extends a class for sur... – AxelH Jul 23 '18 at 12:05
  • 2
    @AxelH `enum`s can implement interfaces – Lino Jul 23 '18 at 12:11
  • 1
    I wasn't sure about it @Lino, I suspect it, thanks – AxelH Jul 23 '18 at 12:13
  • I edited my post and added more details I hope it is clear now. – Salem Masoud Jul 23 '18 at 12:50

3 Answers3

1

You can hack your way around this. As you've stated in the comments:

I have some enums which all have getFromInt method

With a slight adaptation to the method, by adding a new parameter, the type of the enum, you can use reflection to invoke said getFromInt method:

public static <T> T deserializeEnumeration(Class<? extends T> type, InputStream inputStream){
    try {
        int asInt = deserializeInt(inputStream);
        // int.class indicates the parameter
        Method method = type.getDeclaredMethod("getAsInt", int.class);
        // null means no instance as it is a static method
        return method.invoke(null, asInt);
    } catch(NoSuchMethodException, InvocationTargetException, IllegalAccessException e){
       throw new IllegalStateException(e);
    }
}
Lino
  • 19,604
  • 6
  • 47
  • 65
  • I am calling `deserializeEnumeration` for example `objectToDeserialize.setUnit(InputStreamUtil.deserializeEnumeration(inputStream));` how to modifieded it in order to adapt your code? – Salem Masoud Jul 23 '18 at 12:53
  • @SalemMasoud try `objectToDeserialize.setUnit(InputStreamUtil.deserializeEnumeration(Unit.class, inputStream));` – Lino Jul 23 '18 at 12:54
1

Since you are just converting from int to a new type T, why don't you just try to pass in a lambda functional interface to do the conversion as follows:

public class FunctionInterface {
    public static void main(String... args) {
        getT(1, String::valueOf);
    }

    private static <T> T getT(int i, Function<Integer, T> converter) {
        return converter.apply(i); // passing in the function;
    }
}
Hearen
  • 7,420
  • 4
  • 53
  • 63
1
  1. You haven't specified that T has a method getFromInt(int).
  2. You are trying to call a static method from a generic parameter - this will not work.

Something like this should work:

interface FromInt {
    FromInt getFromInt(int i);
}

enum MyEnum implements FromInt {
    Hello,
    Bye;

    @Override
    public FromInt getFromInt(int i) {
        return MyEnum.values()[i];
    }
}

public static <T extends Enum<T> & FromInt> T deserializeEnumeration(Class<T> clazz, InputStream inputStream) {
    int asInt = 1;
    // Use the first element of the `enum` to do the lookup.
    FromInt fromInt = clazz.getEnumConstants()[0].getFromInt(asInt);
    return (T)fromInt;
}
OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213
  • 2
    Just as a sidenote, if `getFromInt` always does an index lookup, then `clazz.getEnumConstans()[asInt]` may even be used and the method `getFromInt` can be thrown into the trash – Lino Jul 23 '18 at 12:48