ByteBuddy создание перечислений с помощью конструкторов

#byte-buddy

#byte-buddy

Вопрос:

Использование ByteBuddy как я могу создать перечисление с помощью таких конструкторов, как этот :

 public enum EnumConstructorSample {
    STATE1(10),
    STATE2(15);
    public int count;
    EnumConstructorSample(int count){
        this.count = count;
    }
}
  

Я попробовал этот код, и он выдает ошибку.

 Class enumClass = new ByteBuddy().makeEnumeration("STATE1", "STATE2")
                .name("DynamicEnum")
                .defineConstructor(Visibility.PACKAGE_PRIVATE)
                .withParameters(int.class)
                .intercept(FixedValue.value(1))
                .make()
                .load(EnumWithConstructor.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
                .getLoaded();
        System.out.println(enumClass.getDeclaredConstructors()[0]);
  

Это ошибка, и она происходит в enumClass.getDeclaredConstructors()

 Exception in thread "main" java.lang.VerifyError: Constructor must call super() or this() before return
Exception Details:
  Location:
    DynamicEnum.<init>(I)V @2: return
  Reason:
    Error exists in the bytecode
  Bytecode:
    0x0000000: 0457 b1                                

    at java.lang.Class.getDeclaredConstructors0(Native Method)
    at java.lang.Class.privateGetDeclaredConstructors(Class.java:2671)
    at java.lang.Class.getDeclaredConstructors(Class.java:2020)
    at EnumWithConstructor.main(EnumWithConstructor.java:19)
  

Ответ №1:

Для конструкторов требуется вызвать метод super в конструкторе. Для перечислений вам нужно будет вызвать Enum(String, int) конструктор. Вы можете реализовать это с помощью MethodCall.invoke(...).onSuper() .

Если вы хотите добиться этого, я бы рекомендовал вам выполнить подкласс Enum вручную, поскольку в противном случае вы бы определили несколько конструкторов для создаваемого вами перечисления, где Byte Buddy будет вызывать свой собственный конструктор перечислений, а все поля будут иметь значение по умолчанию.

Скорее, реализуйте метод и возвращайте значение на основе его имени. Вы можете, например, использовать a MethodDelegation , а затем использовать @This Enum<?> val инъекцию, где вы переключаете имя, чтобы вернуть правильное значение, как если бы оно было сохранено в поле.

Комментарии:

1. Java не позволяет расширять класс Enum . С помощью MethodCall.invoke(Enum.class.getConstructor(...)).with(...) я смог создать перечисление, но тогда Java не позволяет Enum создавать s с помощью отражения. Проблема в том, что ByteBuddy не распознает этот новый конструктор и не создает экземпляры Enum, как раньше. Есть ли способ вызвать мой перехватчик после завершения выполнения обычного конструктора Enum, чтобы я просто инициализировал поля?

2. Да, вы также можете определить поля и, например, использовать TypeInitializer или LoadedTypeInitializer .