8

The goal is to implement a generic Enum translator. I know Enum1 and Enum2 have the same values and in the same order.

The goal is to implement something like this:(this works)

private static Enum1 translateEnum(Enum2 originalEnum) {
    return Enum1.values()[originalEnum.ordinal()];
}

But I have several enums, so I want to make a generic method: (this doesn't work)

private static < T extends Enum<T>,G extends Enum<G>> T translateEnum(G originalEnum) {
    return T.values()[originalEnum.ordinal()];        
}

My problem is that at T.values() the compiler tells me :

The method values() is undefined for the type T

Do you guys have an idea of how I could solve this issue or do you have any alternative idea to my problem?

Gabriel
  • 306
  • 4
  • 16
  • Pass `Class clazz`? That said, though, this doesn't seem eminently useful; most systems include this sort of thing already. – chrylis -cautiouslyoptimistic- Jul 25 '17 at 17:47
  • @chrylis what do you mean by "most systems include this sort of thing already"? – Gabriel Jul 25 '17 at 17:50
  • If `Enum1` and `Enum2` truly have the same values and in the same order, why are there two of them? – Andreas Jul 25 '17 at 18:01
  • Just in case `Enum1` and `Enum2` begin deviating, and not *"the same values and in the same order"*, it would be better to map by name, so deviating order is auto-adjusted, and missing value will throw exception. This is called [**defensive programming**](https://en.wikipedia.org/wiki/Defensive_programming). – Andreas Jul 25 '17 at 18:03
  • @Andreas Enum1 is an external dependency of the project. Enum2 is a local version of it. About your second comment, I guess defensive programming is a good idea. – Gabriel Jul 25 '17 at 18:07
  • 1
    Then my previous comment about defensive programming becomes even more relevant, because you have no *guarantee* that external dependency is changed without you noticing. – Andreas Jul 25 '17 at 18:09

1 Answers1

10

A common way to do this is to pass the target class object (or an object of the target class) as an argument to the function, then use methods from the class object to do the tricky part. For enum classes, the class object has a method which returns the equivalent of Enum.values(). You can use that to get the enum values from the target class:

public class Scratch {
    enum lower { a, b, c };
    enum upper { A, B, C };

    static <T extends Enum<T>> T translate(Enum<?> aFrom, Class<T> aTo) {
        return aTo.getEnumConstants()[aFrom.ordinal()];
    }

    public static void main(String[] args) {
        for (lower ll : lower.values()) {
            upper uu = translate(ll, upper.class);
            System.out.printf("Upper of '%s' is '%s'\n", ll, uu);
        }
        for (upper uu : upper.values()) {
            lower ll = translate(uu, lower.class);
            System.out.printf("Lower of '%s' is '%s'\n", uu, ll);
        }
    }
}

Running this produces the following output:

Upper of 'a' is 'A'
Upper of 'b' is 'B'
Upper of 'c' is 'C'
Lower of 'A' is 'a'
Lower of 'B' is 'b'
Lower of 'C' is 'c'
Kenster
  • 23,465
  • 21
  • 80
  • 106