Добавление поля в класс Java

Посмотрел использование CGLib, ASM, BCEL (аспект) и Javassist для добавления поля в класс во время выполнения....

Просто чтобы понять, похоже, что эти манипуляторы байт-кода не обновляют фактический класс, а позволяют пользователю только сбрасывать модификацию (например, с CGLib и методом writeFile). Надеялся, что найду решение, которое (а) загрузит класс (вместо того, чтобы выполнять InputStream с BCEL) и (б) обновит класс.

Может это нормально? Люди обычно создают прокси и передают прокси?

Что я хочу сделать, так это добавить поле (примечание: не свойство с помощью методов get/set) перед передачей объекта в структуру, которая ищет поля (не свойства) с определенной аннотацией. Итак, «клиенты» создают мои целевые классы, которые я хочу добавить в дополнительное поле. Перехват вызовов АОП на сервисный уровень, где я хочу манипулировать этими объектами.


person Matthew Campbell    schedule 06.08.2012    source источник


Ответы (1)


Вы можете переопределить классы с помощью инструментов. Однако общим ограничением является то, что вы не можете изменить используемые поля. Это связано с тем, что вы не можете изменить содержимое объекта (или добавить к нему) после того, как он был создан.

В вашем случае вы можете,

  • создайте прокси, как вы предлагаете, однако прокси должны быть интерфейсами.
  • создать подкласс, который имеет дополнительные поля
  • добавьте поле до загрузки класса.
person Peter Lawrey    schedule 06.08.2012
comment
точка (3), если вы хотите перехватить загрузчик классов? Пример или ссылка на пример? Пункт (2) у меня не сработает, но пункт (1) выглядит так, как будто в CGLib есть какой-то перехват поля. Поиск примеров на CGLib - это кошмар, так что я не с тобой, на моем прокси должен быть интерфейс? - person Matthew Campbell; 06.08.2012
comment
Если вы знаете, какой класс вы хотите загрузить до того, как он будет использован, вы можете загрузить его самостоятельно, вызвав defineClass. Если вам нужно, чтобы он был динамическим, вы можете создать свой собственный ClassLoader, который переопределяет findClass. Или вы можете использовать Instrumentation, который перехватит загрузку класса без изменения загрузчика класса. Большинству инструментов требуется, чтобы прокси был интерфейсом, например. Proxy.newProxyInstance(classLoader, interfaces, handler) - person Peter Lawrey; 06.08.2012
comment
Найдено github.com/kreyssel/maven-examples/blob/master/javaagent/src/, где с помощью агента вы можете преобразовать класс. Можете ли вы рассказать мне, как это делается при получении ссылки на загрузчик классов? - person Matthew Campbell; 06.08.2012
comment
Что ты имеешь в виду picking up a reference? Вы имеете в виду изменить его до загрузки? В этом случае вы получаете свой загрузчик классов, используете отражения для вызова defineClass с созданным вами байтовым кодом, и пока класс еще не загружен, это будет байтовый код для этого класса. - person Peter Lawrey; 06.08.2012
comment
Что я видел, так это то, что люди подключаются к перехватчику с помощью javaagent (ClassFileTransformer), и когда JVM запускается, вы можете поймать определенные классы, а затем преобразовать их (метод javassist toBytecode()). Когда я говорю взять ссылку, которую я хотел бы преобразовать после запуска JVM (т. е. когда кто-то вызывает мою службу, и я АОП перехватываю вызов, сразу же преобразовываю класс, если это необходимо). - person Matthew Campbell; 06.08.2012
comment
Вы можете сделать это, чтобы изменить код, но не для добавления полей. Если вам нужны дополнительные поля, они должны быть там с самого начала (вам не нужно добавлять код позже) - person Peter Lawrey; 06.08.2012