Интерфейс ClassFileTransformer
public interface ClassFileTransformer
addTransformer, чтобы метод преобразователя transform вызывался при загрузке классов, их redefined или retransformed. Реализация должна переопределять один из определённых здесь методов transform. Преобразователи вызываются до того, как класс будет определён виртуальной машиной Java. Существует два вида преобразователей, которые определяются параметром canRetransform метода Instrumentation.addTransformer(ClassFileTransformer,boolean):
-
способные к повторному преобразованию преобразователи, добавленные с параметром
canRetransform, равным true -
неспособные к повторному преобразованию преобразователи, добавленные с параметром
canRetransform, равным false, или добавленные с помощью методаInstrumentation.addTransformer(ClassFileTransformer)
После регистрации преобразователя с помощью метода addTransformer он будет вызываться для каждого нового определения класса и каждого переопределения класса. Преобразователи, способные к повторному преобразованию, также будут вызываться при каждом повторном преобразовании класса. Запрос на новое определение класса выполняется с помощью метода ClassLoader.defineClass или его нативных эквивалентов. Запрос на переопределение класса выполняется с помощью метода Instrumentation.redefineClasses или его нативных эквивалентов. Запрос на повторное преобразование класса выполняется с помощью метода Instrumentation.retransformClasses или его нативных эквивалентов. Преобразователь вызывается во время обработки запроса, до проверки или применения байтов файла класса. Если преобразователей несколько, преобразования объединяются в цепочку вызовов transform. То есть байтовый массив, возвращённый одним вызовом transform, становится входными данными (через параметр classfileBuffer) для следующего вызова.
Преобразования применяются в следующем порядке:
- Преобразователи, неспособные к повторному преобразованию
- Нативные преобразователи, неспособные к повторному преобразованию
- Преобразователи, способные к повторному преобразованию
- Нативные преобразователи, способные к повторному преобразованию
При повторном преобразовании преобразователи, неспособные к повторному преобразованию, не вызываются; вместо этого повторно используется результат предыдущего преобразования. Во всех остальных случаях вызывается этот метод. В каждой из этих групп преобразователи вызываются в порядке регистрации. Нативные преобразователи предоставляются событием ClassFileLoadHook в интерфейсе Java Virtual Machine Tool Interface.
Входные данные (через параметр classfileBuffer) для первого преобразователя:
- при новом определении класса — байты, переданные в
ClassLoader.defineClass - при переопределении класса —
definitions.getDefinitionClassFile(), гдеdefinitions— параметр методаInstrumentation.redefineClasses - при повторном преобразовании класса — байты, переданные при новом определении класса или, если класс переопределялся, при последнем переопределении; все преобразования, выполненные преобразователями, неспособными к повторному преобразованию, автоматически применяются повторно без изменений; подробности см. в описании метода
Instrumentation.retransformClasses
Если реализующий метод определяет, что преобразования не требуются, он должен вернуть null. В противном случае он должен создать новый массив byte[], скопировать в него входные данные classfileBuffer и все требуемые преобразования, а затем вернуть новый массив. Входные данные classfileBuffer изменять нельзя.
В случаях повторного преобразования и переопределения преобразователь должен поддерживать семантику переопределения: если класс, изменённый преобразователем при первоначальном определении, впоследствии повторно преобразуется или переопределяется, преобразователь должен гарантировать, что второй выходной файл класса является допустимым переопределением первого выходного файла класса.
Если преобразователь выбрасывает исключение (которое он не перехватывает), последующие преобразователи всё равно будут вызваны, а загрузка, переопределение или повторное преобразование всё равно будут предприняты. Таким образом, выбрасывание исключения имеет тот же эффект, что и возврат null. Чтобы предотвратить непредвиденное поведение при возникновении непроверяемых исключений в коде преобразователя, преобразователь может перехватывать Throwable. Если преобразователь считает, что classFileBuffer не является корректно сформированным файлом класса, ему следует выбросить IllegalClassFormatException; хотя это имеет тот же эффект, что и возврат null, такой подход упрощает регистрацию ошибок или отладку повреждений формата.
Обратите внимание, что термин файл класса используется в значении, определённом в главе 4 «Формат файла class» из документа Спецификация виртуальной машины Java, и означает последовательность байтов в формате файла класса независимо от того, хранятся ли они в файле.
- Примечание API:
- При преобразовании основных классов JDK, которые одновременно требуются в процессе преобразования, необходимо проявлять особую осторожность, поскольку это может привести к циклической зависимости классов или ошибкам связывания.
Например, если при вызове метода
transform()для классаCтребуется загрузить или разрешить тот же классC, будет выброшена ошибка, являющаяся экземпляромLinkageError(или его подкласса). ЕслиLinkageErrorвозникает во время разрешения ссылки (см. раздел 5.4.3 «Разрешение» документа Спецификация виртуальной машины Java) для классаD, разрешение соответствующей ссылки в классеDпри любой последующей попытке навсегда завершится той же ошибкой. Это означает, чтоLinkageError, возникшая при преобразованииCв классеD, напрямую не связанном сC, может впоследствии повторно возникать в произвольном пользовательском коде, использующемD. - Начиная с:
- 1.5
- См. также:
Краткое описание методов
| Модификатор и тип | Метод | Описание |
|---|---|---|
default byte[] |
transform |
Преобразует указанный файл класса и возвращает новый файл класса для замены. |
default byte[] |
transform |
Преобразует указанный файл класса и возвращает новый файл класса для замены. |
Подробное описание методов
transform
default byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException
Module, принимающий transform, не переопределён.- Требования к реализации:
- Реализация по умолчанию возвращает null.
- Параметры:
-
loader— загрузчик, определяющий преобразуемый класс; может иметь значениеnull, если это загрузчик начального уровня -
className— имя класса во внутреннем формате полностью квалифицированных имён классов и интерфейсов, определённом в Спецификации виртуальной машины Java. Например,"java/util/List". -
classBeingRedefined— если вызов вызван переопределением или повторным преобразованием, переопределяемый или повторно преобразуемый класс; если это загрузка класса,null -
protectionDomain— домен защиты определяемого или переопределяемого класса -
classfileBuffer— входной байтовый буфер в формате файла класса; изменять нельзя - Возвращает:
- корректно сформированный буфер файла класса (результат преобразования) или
null, если преобразование не выполняется - Выбрасывает:
-
IllegalClassFormatException— если входные данные не являются корректно сформированным файлом класса
transform
default byte[] transform(Module module, ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException
- Требования к реализации:
- Реализация этого метода по умолчанию вызывает метод
transform. - Параметры:
-
module— модуль преобразуемого класса -
loader— загрузчик, определяющий преобразуемый класс; может иметь значениеnull, если это загрузчик начального уровня -
className— имя класса во внутреннем формате полностью квалифицированных имён классов и интерфейсов, определённом в Спецификации виртуальной машины Java. Например,"java/util/List". -
classBeingRedefined— если вызов вызван переопределением или повторным преобразованием, переопределяемый или повторно преобразуемый класс; если это загрузка класса,null -
protectionDomain— домен защиты определяемого или переопределяемого класса -
classfileBuffer— входной байтовый буфер в формате файла класса; изменять нельзя - Возвращает:
- корректно сформированный буфер файла класса (результат преобразования) или
null, если преобразование не выполняется - Выбрасывает:
-
IllegalClassFormatException— если входные данные не являются корректно сформированным файлом класса - Начиная с:
- 9
© 1993, 2025, Oracle and/or its affiliates. All rights reserved.
Documentation extracted from Debian's OpenJDK Development Kit package.
Licensed under the GNU General Public License, version 2, with the Classpath Exception.
Various third party code in OpenJDK is licensed under different licenses (see Debian package).
Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.
https://docs.oracle.com/en/java/javase/25/docs/api/java.instrument/java/lang/instrument/ClassFileTransformer.html