Замените java .io.File во время выполнения на ByteBuddy - PullRequest
1 голос
/ 06 марта 2020

Как вы можете заменить java.io.File для данного веб-приложения (работающего в контейнере сервлета) для следующих условий

Учитывая, что у меня есть класс class AmazonS3File extends java.io.File

  1. Заменить каждые java.io.File с AmazonS3File
  2. Заменить каждый java.io.File на AmazonS3File, но при условии, что вызов поступил из определенной c библиотеки, скажем, com.jetbrains пакета (не уверен, что это даже теоретически возможно)

Однако вот код псевдо , который у меня есть:

    new AgentBuilder.Default()
            .with(AgentBuilder.Listener.StreamWriting.toSystemOut())
            .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
            .type(ElementMatchers.is(java.io.File.class))
            .transform((builder, typeDescription, classLoader, module) ->
                    new ByteBuddy().redefine(java.io.File.class).constructor(ElementMatchers.anyOf(AmazonS3File.class) /* <-- What to put here?*/))
            .installOnByteBuddyAgent();
    File videoFile = new File(OUTPUT_PATH);
    System.out.println(videoFile.getPath());

Что нужно поместить в ByteBuddy().redefine(java.io.File.class).constructor, чтобы загрузить его вместо конструктора AmazonS3File?

1 Ответ

1 голос
/ 19 марта 2020

Byte Buddy позволяет вам корректировать код библиотеки, например, с помощью агента Java. Агент Java получает уведомление о загрузке любого класса и, используя его, вы можете заменить любой вызов на new File() своим new AmazonS3File(). Для этого вам необходимо преобразовать все классы в пакете, где эта замена в коде актуальна. Для этого вы должны использовать MemberSubstitution:

new AgentBuilder.Default()
        .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
        .type(nameStartsWith("pkg.of.library."))
        .transform((builder, typeDescription, classLoader, module) -> builder.visit(MemberSubstitution.strict()
             .constructor(isDeclaredBy(File.class))
             .replaceWith(MyFactory.class.getMethod("file", String.class))
             .on(any()))
        .installOnByteBuddyAgent();

Чтобы сделать эту работу, вам нужно будет создать некоторый фабричный класс MyFactory, который возвращает любой экземпляр типа File, где вы можете, например, верните ваш файл Amazon, если он имеет значение Java File.

Подстановка в основном говорит: для любого типа в пакете и подпакетах pgk.of.library , scan any() метод или конструктор для конструкторов File и замена их вызовом MyFactory::file. Чтобы это работало, фабрика должна иметь те же аргументы, что и заменяемый конструктор файла.

...