首页 > 解决方案 > 将运行时的 java.io.File 替换为 ByteBuddy

问题描述

如何java.io.File在以下条件下替换给定的 Web 应用程序(在 servlet 容器上运行)

鉴于我有一堂课class AmazonS3File extends java.io.File

  1. 将每个替换java.io.FileAmazonS3File
  2. 将 every 替换java.io.FileAmazonS3File但在调用来自特定库的情况下,比如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

标签: javabyte-buddy

解决方案


Byte Buddy 允许您通过例如使用 Java 代理来调整库代码。Java 代理会在任何类被加载和使用时收到通知,您确实可以将任何调用替换为new File()您的new AmazonS3File(). 为此,您需要转换与此代码内替换相关的包中的所有类。您将MemberSubstitution为此使用 a :

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如果它扩展了 Java 的File.

替换基本上是说:对于pgk.of.library的包和子包中的任何类型,扫描any()方法或构造函数的构造函数,File并用调用替换它们MyFactory::file。为此,工厂必须具有与被替换的文件构造函数相同的参数。


推荐阅读