Reputation: 35316
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
java.io.File
with AmazonS3File
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?
Upvotes: 1
Views: 458
Reputation: 44032
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.
Upvotes: 1