Java中枚举的通用接口
我在Hibernate/Spring上有一个web应用程序,我想在应用程序中使用的枚举很少Java中枚举的通用接口,java,generics,enums,Java,Generics,Enums,我在Hibernate/Spring上有一个web应用程序,我想在应用程序中使用的枚举很少 public enum MerchantStatus { NEW("New"), ... private final String status; MerchantStatus(String status) { this.status = status; } public static MerchantStatus fromString
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 class MerchantStatusConverter implements AttributeConverter<MerchantStatus, String> {
public String convertToDatabaseColumn(MerchantStatus value) {..}
public MerchantStatus convertToEntityAttribute(String value) {..}
}
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);
}
}
}
公共类MerchantStatusConverter实现AttributeConverter{
公共字符串convertToDatabaseColumn(MerchantStatus值){..}
public MerchantStatus convertToEntityAttribute(字符串值){..}
}
问题是我不想为每个枚举创建转换器,理想情况下它应该是泛型类/接口,我将在这里使用多态性。问题是fromString
是静态方法,似乎不可能创建返回泛型类型的静态方法
有解决此问题的方法吗?您应该能够执行以下操作:
public class Converter<T extends Enum<T>, U> implements AttributeConverter<T, U> {
public U convertToDatabaseColumn(T value) {
...
}
public T convertToEntityAttribute(U value) {
...
}
}
公共类转换器实现AttributeConverter{
公共U convertToDatabaseColumn(T值){
...
}
公共T convertToEntityAttribute(U值){
...
}
}
如果您想为所有enum
类使用通用转换器,只要您坚持命名约定,就可以使用反射
您的惯例似乎是使用toString()
进行enum
->String
转换,使用静态fromString(String)
进行String
->enum
转换
用于此的转换器如下所示:
public class MerchantStatusConverter implements AttributeConverter<MerchantStatus, String> {
public String convertToDatabaseColumn(MerchantStatus value) {..}
public MerchantStatus convertToEntityAttribute(String value) {..}
}
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);
}
}
}
公共类EnumConverter实现AttributeConverter{
私有final方法fromStringMethod;
公共枚举转换器(类枚举类){
试一试{
this.fromStringMethod=enumClass.getDeclaredMethod(“fromString”,String.class);
}捕获(无此方法例外){
抛出新的NoSuchMethodError(例如getMessage());
}
如果(!Modifier.isStatic(this.fromStringMethod.getModifiers()))
抛出新的NoSuchMethodError(“fromString(String)不是静态的”);
if(this.fromStringMethod.getReturnType()!=enumClass)
抛出新的NoSuchMethodError(“fromString(String)不返回”+enumClass.getName());
}
公共字符串convertToDatabaseColumn(T值){
返回值.toString();
}
@抑制警告(“未选中”)
公共T convertToEntityAttribute(字符串值){
试一试{
返回(T)this.fromStringMethod.invoke(null,value);
}捕获(非法访问例外e){
抛出新的IllegalAccessError(e.getMessage());
}捕获(调用TargetException e){
抛出新的运行时异常(“调用fromString(String)时出错):”+e,e);
}
}
}
然后通过命名类来构造它,例如
new EnumConverter<>(MerchantStatus.class)
新的EnumConverter(MerchantStatus.class)
新的EnumConverter(EmployerType.class)
问题是我不想为每个枚举和
理想情况下,它应该是泛型类/接口,我将使用
这里是多态性
您别无选择,因为在注释实体时,AttributeConverter
实现无法参数化
您确实应该只使用AttributeConverter
类指定它:
@Enumerated(EnumType.STRING)
@Convert(converter = MerchantStatusConverter.class)
private MerchantStatus merchantStatus;
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);
}
}
但是您可以定义一个抽象类来定义逻辑,并在每个枚举类中将其子类化。
为了实现它,您应该在每个枚举类前面引入一个接口,该接口声明一个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
类,该类需要声明一个公共构造函数,以将受保护的myEnum
字段分配给枚举值(不管是什么):
公共类MerchantStatusAttributeConverter扩展了AbstractAttributeConverter{
公共商品StatusAttributeConverter(){
myEnum=MerchantStatus.NEW;
}
}
似乎不可能创建返回泛型类型的静态方法-我只是想知道为什么必须同时使用构造函数和工厂方法?为什么要为枚举创建转换器?Hibernate应该能够正确处理这种情况!将枚举作为字符串保存到DB,并将字符串从DB转换为枚举!您只需要使用@Enumerated注释。或者情况并非如此?顺便说一下,枚举已经可以在不需要存储额外内容的情况下在字符串表示形式之间进行转换(使用enumValue.name()
或enumValue.toString()
;使用YourEnumType.valueOf(string)
或enum.valueOf(clazz,string)
)。内置的字符串表示法是如何准确地编写枚举的,在您的情况下都是大写,而您需要的是首字母大写,因此您可以进行一些简单的大小写转换。
public class MerchantStatusAttributeConverter extends AbstractAttributeConverter<MerchantStatus> {
public MerchantStatusAttributeConverter(){
myEnum = MerchantStatus.NEW;
}
}