Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

How can you replace java.io.File for a given web application (running on a servlet container) for the following conditions

Given I have a class class AmazonS3File extends java.io.File

  • Replace every java.io.File with AmazonS3File
  • Replace every java.io.File with AmazonS3File but under the condition that the call came from a specific library, say com.jetbrains package (not sure if this is even theoretically possible)
  • However, here's the pseudo code I have:

        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());
    

    What should be placed in the ByteBuddy().redefine(java.io.File.class).constructor to make it load the constructor of AmazonS3File instead?

    I also understand that it's not possible to replace if the class has been loaded already as per stackoverflow.com/questions/56641621/… so what would be the strategy if this will be used on a Web Application where app is running on a Servlet Container (Jetty, Tomcat, NGINX Unit to name a few) – quarks Mar 6, 2020 at 7:45 @ThorbjørnRavnAndersen to replace java.io.File calls by a Java library; File saves on disk, what I need is to save on Cloud storage directly and not saving to disk at all due to platform limitation. – quarks Mar 6, 2020 at 8:17 File is an interface. Consider making a class wrapping an AmazonS3File implementing File and pass that into the code. – Thorbjørn Ravn Andersen Mar 6, 2020 at 8:58 @ThorbjørnRavnAndersen File is a concrete class AFAIK public class File implements Serializable, Comparable<File> also the main reason for using ByteBuddy is because we can't modify the library codes (we don't maintain it) that's why we want to just make java.io.File calls substituted at runtime, hence ByteBuddy. – quarks Mar 6, 2020 at 9:37

    Byte Buddy allows you to adjust library code by for example using a Java agent. A Java agent is notified on any class being loaded and using one, you can indeed replace any call to new File() by your new AmazonS3File(). To do so, you would need to transform all classes within a package where this in-code replacement is relevant. You would be using a MemberSubstitution for this:

    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();
    

    To make this work, you will have to create some factory class MyFactory that returns any instance of type File where you can for example return your Amazon file if it exteds Java's File.

    The substitution basically says: for any type in the package and subpackages of pgk.of.library, scan any() method or constructor for constructors of File and replace them with a call to MyFactory::file. For this to work, the factory must have the same arguments as the file constructor being replaced.

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.