有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Java中枚举的通用接口

我在Hibernate/Spring上有一个web应用程序,我想在应用程序中使用的枚举数很少

public enum MerchantStatus {
    NEW("New"),
    ...

    private final String status;

    MerchantStatus(String status) {
        this.status = status;
    }

    public static MerchantStatus fromString(String status) {..}    

    public String toString() {..}
}

public enum EmployerType {
    COOL("Cool"),
    ...

    private final String type;

    EmployerType (String type) {
        this.type = type;
    }

    public static EmployerType fromString(String type) {..}    

    public String toString() {..}
}

我想创建一个转换器,将枚举对象转换为字符串,反之亦然。是这样的:

public class MerchantStatusConverter implements AttributeConverter<MerchantStatus, String> {
    public String convertToDatabaseColumn(MerchantStatus value) {..}

    public MerchantStatus convertToEntityAttribute(String value) {..}
}

问题是,我不想为每个枚举创建转换器,理想情况下,它应该是泛型类/接口,我将在这里使用多态性。问题是fromString是静态方法,似乎不可能创建返回泛型类型的静态方法

这个问题有什么解决办法吗


共 (3) 个答案

  1. # 1 楼答案

    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.

    您别无选择,因为在注释实体时AttributeConverter实现无法参数化

    实际上,您应该只使用AttributeConverter类来指定它:

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

    但是,您可以定义一个抽象类来定义逻辑,并在每个枚举类中将其子类化
    为了实现它,您应该在每个enum类前面引入一个接口,该接口声明一个fromString()和一个toString()方法

    界面:

    public interface MyEnum<T extends MyEnum<T>>{
    
         T fromString(String type);
         String toString(T enumValue);
    }
    

    实现接口的枚举:

    public enum MerchantStatus implements MyEnum<MerchantStatus> {
    
        NEW("New"), ...
    
    
        @Override
        public MerchantStatus fromString(String type) {
         ...
        }
    
        @Override
        public String toString(MerchantStatus enumValue) {
         ...
        }
    }
    

    抽象AttributeConverter类:

    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);
        }
    }
    

    以及具体的AttributeConverter类,该类需要声明一个公共构造函数,以将受保护的myEnum字段分配给枚举值(不管是什么):

    public class MerchantStatusAttributeConverter extends AbstractAttributeConverter<MerchantStatus> {
       public MerchantStatusAttributeConverter(){
          myEnum = MerchantStatus.NEW; 
       }
    }
    
  2. # 2 楼答案

    如果您想要为所有enum类提供一个通用转换器,那么可以使用反射,只要您坚持命名约定

    你的习惯似乎是用toString()表示enum->String转换,以及static{}的String->enum转换

    一个这样的转换器:

    public class EnumConverter<T extends Enum<T>> implements AttributeConverter<T, String> {
        private final Method fromStringMethod;
    
        public EnumConverter(Class<T> enumClass) {
            try {
                this.fromStringMethod = enumClass.getDeclaredMethod("fromString", String.class);
            } catch (NoSuchMethodException e) {
                throw new NoSuchMethodError(e.getMessage());
            }
            if (! Modifier.isStatic(this.fromStringMethod.getModifiers()))
                throw new NoSuchMethodError("fromString(String) is not static");
            if (this.fromStringMethod.getReturnType() != enumClass)
                throw new NoSuchMethodError("fromString(String) does not return " + enumClass.getName());
        }
    
        public String convertToDatabaseColumn(T value) {
            return value.toString();
        }
    
        @SuppressWarnings("unchecked")
        public T convertToEntityAttribute(String value) {
            try {
                return (T) this.fromStringMethod.invoke(null, value);
            } catch (IllegalAccessException e) {
                throw new IllegalAccessError(e.getMessage());
            } catch (InvocationTargetException e) {
                throw new RuntimeException("Error calling fromString(String): " + e, e);
            }
        }
    }
    

    然后通过命名类来构造它,例如

    new EnumConverter<>(MerchantStatus.class)
    
    new EnumConverter<>(EmployerType.class)
    
  3. # 3 楼答案

    你应该能够做到以下几点:

    public class Converter<T extends Enum<T>, U> implements AttributeConverter<T, U> {
    
        public U convertToDatabaseColumn(T value) {
            ...
        }
    
        public T convertToEntityAttribute(U value) {
            ...
        }
    
    }