How can I create an enum with fields initialized by each enum constant using Byte Buddy?

Michael :

I would like to generate an enum containing a field using Byte Buddy, where each enum constant passes a different argument to the constructor.

public enum MyEnum {
    private final String blah;
    A("foo")
    B("bar");

    private MyEnum(String blah) {
        this.blah = blah;
    }
}

I tried this:

new ByteBuddy()
    .makeEnumeration("A", "B")
    .name("com.foo.MyEnum")
    .defineField("blah", String.class, Modifier.FINAL | Modifier.PRIVATE)
    .defineConstructor(Visibility.PRIVATE)
    .withParameters(String.class)
    .intercept(
        FieldAccessor.ofField("blah").setsArgumentAt(0)
    )
    .make()

Which generates this (decompiled). The two constructors with the same signature are a bit weird, but anyway.

public enum MyEnum {
    private final String blah;
    A,
    B;

    private MyEnum() {
    }

    private MyEnum() {
        this.blah = var1;
    }
}

I couldn't see any way to associate each enum constant with a set of constructor arguments. The makeEnumeration method only has two signatures, both of which take a collection of strings.

Is this possible with Byte Buddy?

Rafael Winterhalter :

Byte Buddy does not currently allow you to generate this exact byte code pattern but you can achieve the same thing by intercepting methods and by checking the current instance name in the intercepted method and returning values accordingly.

If you wanted to define a field, you could also intercept the enum constructor and replace Byte Buddy's original implementation. The constructor that you define is not valid as the Enum class does not offer a default constructor. Instead apply the following:

builder = builder.constructor(any()).intercept(SuperMethodCall.INSTANCE.andThen(...))

where you can apply any interceptor implementation. For example, you can apply a MethodDelegation such as:

class FieldSetter {
  static void fields(@Argument(0) String name) {
    // implement logic
  }
}

An enumeration defines a single constructor with the enum name as the first argument and the ordinal integer as a second argument. You can also use Advice and register a decoration using visit.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=139952&siteId=1