How to Implement Enum with Generics

How to implement enum with generics?

You can't. Java doesn't allow generic types on enum constants. They are allowed on enum types, though:

public enum B implements A<String> {
A1, A2;
}

What you could do in this case is either have an enum type for each generic type, or 'fake' having an enum by just making it a class:

public class B<T> implements A<T> {
public static final B<String> A1 = new B<String>();
public static final B<Integer> A2 = new B<Integer>();
private B() {};
}

Unfortunately, they both have drawbacks.

How can I require a generic parameter to be an enum that implements an interface?

Use an '&' instead:

public class MyWidget<T extends Enum<T> & MyInterface> {
...
}

The JLS calls this an "intersection type", but I can find no mention of it in the Java tutorials. I'll just say that it does exactly what you were wishing that "extends" would do.

Also, I should mention that you can have as many types as you want in the intersection type. So if you wanted, you could do:

public class MyWidget<T extends Enum<T> & MyInterface & Serializable & Cloneable> {
...
}

[Note: this code sample should not be construed as an endorsement of the Cloneable interface; it was merely handy at the time.]

Generic interface for enums in Java

The problem is that I don't want to create converter for each enum and
ideally it should be generic class/interface and I will use
polymorphism here.

You have no choice as your AttributeConverter implementation could not be parameterized when you annotate your entity.

You should indeed specify it only with the AttributeConverter class :

@Enumerated(EnumType.STRING)
@Convert(converter = MerchantStatusConverter.class)
private MerchantStatus merchantStatus;

But you could define an abstract class that defines the logic and subclassing it in each enum class.

To achieve it, you should introduce an interface in front of each enum class that declares a fromString() and a toString() method.

The interface :

public interface MyEnum<T extends MyEnum<T>>{

T fromString(String type);
String toString(T enumValue);
}

The enum that implements the interface :

public enum MerchantStatus implements MyEnum<MerchantStatus> {

NEW("New"), ...

@Override
public MerchantStatus fromString(String type) {
...
}

@Override
public String toString(MerchantStatus enumValue) {
...
}
}

The abstract AttributeConverter class :

public abstract class AbstractAttributeConverter<E extends MyEnum<E>> implements AttributeConverter<E, String> {

protected MyEnum<E> myEnum;

@Override
public String convertToDatabaseColumn(E attribute) {
return myEnum.toString(attribute);
}

@Override
public E convertToEntityAttribute(String dbData) {
return myEnum.fromString(dbData);
}
}

And concrete AttributeConverter class that needs to declare a public constructor to assign the protected myEnum field to an enum value (whatever of it):

public class MerchantStatusAttributeConverter extends AbstractAttributeConverter<MerchantStatus> {
public MerchantStatusAttributeConverter(){
myEnum = MerchantStatus.NEW;
}
}

Java Enum as generic type in Enum

In your method implementation PerspectiveCommands is not the enum but your type parameter, which often is called T. It thus shadows the enum of the same name like axtavt already said, thus PERSPECTIVE is unknown here.

Your abstract method declaration is fine but you might use a slightly different approach.

public void test(PerspectiveCommands command) would not work, since this method would not override the generic version. The reason is that with the generic version the type is inferred from the parameter and thus you could pass any enum.

However, I assume you have an interface or abstract class which defines the abstract method. So try something like this:

interface TestInterface<T extends Enum<T>>
{
public abstract void test(T command);
}

class TestImpl implements TestInterface<PerspectiveCommands>
{
@Override
public void test(PerspectiveCommands command) {
if(command == PerspectiveCommands.PERSPECTIVE){
//do something
}
}
}

Get values of generic enum that implements an interface

I suspect you may be looking for something like:

public static <T extends Enum<T> & GenericMethods> T[] getEnums(Class<T> enum1) {
return enum1.getEnumConstants();
}

public static void main(String[] args) {
for (GenericMethods gm : getEnums(SpecificEnum.class)) {
System.out.println(gm.getString());
}
}

Results:

(demo: https://ideone.com/v6on2p)

NOT
RELATED
TEXT

Changes:

  • moved <T extends GenericMethods> before return type since only there generic method can declare its generic type.
  • modified generic type to <T extends Enum<T> & GenericMethods> to force T to also be subtype of some Enum aside from implementing GenericMethods
  • used getEnumConstants() instead of values() as we are using Class, not enum type.

Calling Enum.values() on a generic type

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'

JAVA - Passing a generic enum as a method parameter for a constructor

You can let your enums implement a common interface:

interface CommonInterface {
public String getId();
public String getProductName();
public BuySection getBuySection();
}
enum FstEnum implements CommonInterface {}
enum SndEnum implements CommonInterface {}

class Product<E extends Enum<E> & CommonInterface> {
E type;
Product(E type) {
this.type = type;
}
}

public static <E extends Enum<E> & CommonInterface> void setActualProduct(E itemType) {
actualProduct = new Product<E>(itemType);
}

A few remarks wrt. naming conventions: class names should be singular (BuySection, not BuySections), enums should begin with uppercase letters (as should all types, e.g. ItemsA, not itemsA)



Related Topics



Leave a reply



Submit