![]() |
高大的木瓜 · 给Spring中注册Bean的几种方式 | 墨寒轩· 21 小时前 · |
![]() |
帅气的松球 · ASP.net core 3.1で Web ...· 17 小时前 · |
![]() |
坏坏的柿子 · "OverflowError: ...· 15 小时前 · |
![]() |
健壮的茶壶 · Exception: ...· 15 小时前 · |
![]() |
灰常酷的伏特加 · OverflowError: string ...· 15 小时前 · |
![]() |
讲道义的乌龙茶 · Max gen~ - MOD Wiki· 1 月前 · |
![]() |
打盹的桔子 · html5 PHP ...· 11 月前 · |
![]() |
开朗的丝瓜 · 小度智能音箱价格_小度智能音箱最新报价_小度 ...· 1 年前 · |
![]() |
侠义非凡的大象 · 温州瓯海民房坍塌 ...· 2 年前 · |
我正在处理一个使用JDK8运行的项目,我们希望将它迁移到OpenJDK11。
但是,有一些遗留代码在运行时动态地创建枚举(使用反射和
sun.reflect.*
包):
public class EnumUtil {
static Object makeEnum(...) {
enumClass.cast(sun.reflect.ReflectionFactory.getReflectionFactory() .newConstructorAccessor(constructor).newInstance(params));
}
或
// before, field is made accessible, the modifier too
sun.reflect.FieldAccessor fieldAccessor = sun.reflect.ReflectionFactory.getReflectionFactory().newFieldAccessor(field, false);
field.set(target, value);
例如,假设我们有枚举
AEnum
:
public enum AEnum {
; // no values at compile time
private String label;
private AEnum (String label) {
this.label = label;
}
然后,我们添加如下枚举值:
EnumUtil.addEnum(MyEnum.class, "TEST", "labelTest");
最后,在运行时,我们有一个带有
AEnum.TEST
= labelTest的值(不是直接调用,而是使用
Enum.valueOf
)。
不幸的是,
sun.reflect.*
类在OpenJDK11中不再可用。
我尝试过使用
jdk.internal.reflect.ConstructorAccessor
,但是我得到了错误
java: package jdk.internal.reflect does not exist
。我不认为依赖
jdk.internal.*
类是个好主意。
在运行时创建枚举有任何OpenJDK11替代方案吗?
发布于 2022-01-21 15:33:33
正如您在注释部分中提到的那样,在运行时添加
enum
值是一个非常糟糕的主意,它打破了枚举的契约。
因此,我已经将所有的情况修改为一个POJO对象,维护一个映射。
在简化格式中,
AEnum
变成:
public class AEnum extends DynamicEnum { // DynamicEnum has utility methods in order to act as close as a real enum.
@Getter
private String label;
private static final Map<String, AEnum> map = new LinkedHashMap<>();
protected AEnum (String name, String label) {
this.name = name;
this.label= label;
public static AEnum addInMap(String name, String label) {
AEnum value = new DossierSousType(name, label);
map.put(name, value);
return value;
}
我们从数据库中读取动态值,因此我创建了一个实用程序类来加载所有内容。
public static <T extends DynamicEnum> T addEnum(final Class<T> type, final String name, final String label) throws TechnicalException {
try {
Method method = type.getDeclaredMethod("addInMap", String.class, String.class);
return (T) method.invoke(null, name, label);
} catch (... e) {
// ...
}
然后:
addEnum(AEnum.class, "TEST", "labelTest");
addEnum(AEnum.class, "TEST2", "labelTest2");
AEnum.getAll() // returns a list with the two entries
此外,如果我们在持久化的
Entity
中使用这个"false enum“,我们就有一个转换器来管理
String
和
AEnum
之间的转换。
@Entity
@Table(name = TABLE_NAME)
public class MyEntity {
@Column(name = COLUMN_TYPE)
@Convert(converter = AEnumConverter.class)
private AEnum type;
AEnumConverter
实现了
javax.persistence.AttributeConverter
:
@Converter
public class AEnumConverter implements AttributeConverter<AEnum , String> {
@Override
public String convertToDatabaseColumn(AEnum type) {
return type != null ? type.getName() : null;
@Override
public AEnum convertToEntityAttribute(String type) {
return AEnum .getEnum(type);
}
有了这个机制,一切都可以完美地工作,我们不再需要
sun.reflect.*
!
发布于 2022-01-19 14:54:46
这个答案 包含一种工作方法,它只使用标准的API,而且仍然有效,即使使用JDK 17也是如此。
由于它在示例中使用了JDK类型,它在启动时需要一个
--add-opens java.base/java.lang=…
参数,因此这里有一个使用自己的
enum
类型的示例,它不需要对环境进行任何修改。
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Constructor;
import java.util.EnumSet;
class EnumHack {
public static void main(String[] args) throws Throwable {
System.out.println(Runtime.version());
Constructor<Example> c
= Example.class.getDeclaredConstructor(String.class, int.class);
c.setAccessible(true);
MethodHandle h = MethodHandles.lookup().unreflectConstructor(c);
Example baz = (Example) h.invokeExact("BAZ", 42);
System.out.println("created Example " + baz + "(" + baz.ordinal() + ')');
EnumSet<Example> set = EnumSet.allOf(Example.class);
System.out.println(set.contains(baz));
set.add(baz);
System.out.println(set);
enum Example {
FOO, BAR
}
因为它不需要特殊的设置,所以可以是 在Ideone上演示
12.0.1+12
created Example BAZ(42)
false
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 42 out of bounds for length 2
![]() |
高大的木瓜 · 给Spring中注册Bean的几种方式 | 墨寒轩 21 小时前 |
![]() |
坏坏的柿子 · "OverflowError: string longer than 2147483647 bytes" when trying requests.put · Issue #2717 · psf/re 15 小时前 |
![]() |
健壮的茶壶 · Exception: OverflowError: string longer than 2147483647 bytes · Issue #646 · python-gitlab/python-gi 15 小时前 |
![]() |
灰常酷的伏特加 · OverflowError: string longer than 2147483647 bytes - Broad Institute Crunch #1 - CrunchDAO 15 小时前 |
![]() |
讲道义的乌龙茶 · Max gen~ - MOD Wiki 1 月前 |