简体   繁体   English

如何使用 ByteBuddy 为不确定的 class 字段添加 setter 方法?

[英]How to add setter method for uncertain class fields using ByteBuddy?

According to the official example, generating getter/setter methods for a Field can be done by implementing an interface.按照官方的例子,Field的getter/setter方法可以通过实现一个接口来实现。 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.但是这个时候我就知道Class里面到底要添加哪些Field了。我的程序每次都是从数据库中获取要添加的字段,所以我需要在运行时为这些字段添加getter/setter方法。

I define a getter method and assign it as FieldAccessor using intercept method.我定义了一个 getter 方法并使用拦截方法将其分配为 FieldAccessor。 When I define a setter method in the same way and specify it as FieldAccessor, the system throws an exception.当我用同样的方式定义一个setter方法并指定为FieldAccessor时,系统抛出异常。

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;
    }
}

Your setter lacks a parameter of the field's type.您的设置器缺少字段类型的参数。 It returns void but needs to accept a value of type String .它返回void但需要接受String类型的值。

Byte Buddy has a convenience method for this. Byte Buddy 有一个方便的方法。 Simply add: withProperty(fieldName, String.class) and everything is setup correctly.只需添加: withProperty(fieldName, String.class)正确设置所有内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM