1

According to the official example, generating getter/setter methods for a Field can be done by implementing an interface. But this is when I know exactly which Fields will be added to the Class. My program gets the fields to be added from the database every time, so I need to add getter/setter methods for these fields at runtime.

I define a getter method and assign it as FieldAccessor using intercept method. When I define a setter method in the same way and specify it as FieldAccessor, the system throws an exception.

Here is a simplified example code:

@Data
public class MappingFieldBO {
    private String fieldName;
    private int maxScore;
    public MappingFieldBO() {
    }
    public MappingFieldBO(String fieldName, int maxScore) {
        this.fieldName = fieldName;
        this.maxScore = maxScore;
    }
}

@Data
public class BaseMappingFieldBO {
    private Long id;
}
public class Main {
    public static void main(String[] args) {
        List<MappingFieldBO> mappingFields = getFromDB();
        DynamicType.Builder<BaseMappingFieldBO> builder = new ByteBuddy()
                .subclass(BaseMappingFieldBO.class)
                .name("io.buyan.dv.console.MappingBean");
         // add uncertain fields to class
        for (MappingFieldBO mappingField : mappingFields) {
            String fieldName = mappingField.getFieldName();
            builder = builder.defineField(fieldName, String.class, Visibility.PUBLIC)
                    // define getter method
                    .defineMethod(getterName(fieldName), String.class, Visibility.PUBLIC)
                    .intercept(FieldAccessor.ofField(fieldName))
                    // define setter method
                    // throw IllegalArgumentException: Method public void io.buyan.dv.console.MappingBean.setShipping() is no bean accessor
                    .defineMethod(setterName(fieldName), Void.TYPE, Visibility.PUBLIC)
                    .intercept(FieldAccessor.ofField(fieldName));
        }
        Class<? extends BaseMappingFieldBO> clazz = builder.make().load(Thread.currentThread().getContextClassLoader()).getLoaded();
    }

    private static String setterName(String fieldName) {
        return "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
    }
    private static String getterName(String fieldName) {
        return "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
    }

    private static List<MappingFieldBO> getFromDB() {
        List<MappingFieldBO> list = new ArrayList<>();
        list.add(new MappingFieldBO("shipping", 10));
        list.add(new MappingFieldBO("deduct", 8));
        return list;
    }
}

1 Answer 1

1

Your setter lacks a parameter of the field's type. It returns void but needs to accept a value of type String.

Byte Buddy has a convenience method for this. Simply add: withProperty(fieldName, String.class) and everything is setup correctly.

Sign up to request clarification or add additional context in comments.

3 Comments

withProperty seems missing now. Any other suggestions?
It's on DynamicType.Builder. Maybe you are using an older version?
I believe it's called withParameter(fieldName, String.class) probably a bit late now

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.