Я использую Byte Buddy для создания классов bean-подобных интерфейсов во время выполнения, сокращая тонны стандартного кода. Создать поля из геттеров и сеттеров тривиально, но я хочу больше использовать Byte Buddy. Начнем с того, что я не хочу писать такой код везде:
if (obj.getMax() < obj.getMin()) {
int temp = obj.getMax();
obj.setMax(obj.getMin());
obj.setMin(temp);
}
obj.setMax(obj.getMax() + 1);
int currentMax = getMax();
, когда я могу просто сделать:
obj.enforceMinMaxOrder();
int currentMax = obj.incrementAndGetMax();
Вот сокращенный пример. Как я могу использовать Byte Buddy, чтобы две вышеупомянутые работы работали? Предположительно с использованием класса перехватчика, но я не сталкивался с примерами, которые модифицируют поля. Важные вещи:
- поля неизвестны во время компиляции, они будут извлечены из имен методов (т. Е. Имя метода «forceceMinMaxOrder» использует «min» и «max» в качестве имен полей)
Я бы хотел избежать отражения во время выполнения, используемого после того, как Byte Buddy генерирует классы, но удерживать ссылки на поля или методы и вызывать их хорошо.
DynamicType.Builder<? extends Object> builder = new ByteBuddy().subclass(Object.class);
builder = builder.implement(MyInterface.class);
builder = builder.method(
(isGetter().or(isSetter())))
.intercept(FieldAccessor.ofBeanProperty());
for (Method m : MyInterface.class.getMethods()) {
String methodName = m.getName();
Class<?> t = m.getReturnType();
if (t != void.class && methodName.startsWith("get")) {
String fieldName = Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);
builder = builder.defineField(fieldName, t, Visibility.PUBLIC);
builder = builder.method(named(fieldName)).intercept(FieldAccessor.ofField(fieldName));
}
}
MyInterface obj = (MyInterface) builder.make().load(BeanUtil.class.getClassLoader()).getLoaded().getConstructor().newInstance();
obj.setMin(10);
obj.setMax(5);
obj.incrementAndGetMin();
obj.ensureMinMaxOrder();
// now, the values should be min=5, max=11