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?
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
.