Preprocessing dependency classes

Is there a way, in a gradle plugin, to preprocess dependency classes using frameworks like ASM?

I am trying to create an access transformer, to strip private/protected access from certain dependencies, and the best way I can think of doing this would be to modify the dependency classes bytecode.

Thanks

How are you packaging your app? Is it a war or a zip? Perhaps you could transform all the jars in the war/zip once its built.

Another option is to create a tweaked version of some of your dependencies which has a different group/artifact/version to the originals. You may want to borrow some logic from my monkey patch plugin where I create a patched version of a jar file which has the exact same dependencies as the original, so it’s a “drop in” replacement for the original.

Regarding ASM, take a look at byte buddy which greatly simplifies ASM

Another option is using a custom configuration.

apply plugin: 'java' 
configurations {
   asmTransform
} 
dependencies {
   asmTransform 'foo:bar:1.0' // this will be transformed and added to the "compile" configuration 
   compile files({tasks.asmTransform})
}
task asmTransform {
   inputs.files configurations.asmTransform
   outputs.dir "$buildDir/asmTransform" 
   doLast {
      // TODO transform the jars in configurations.asmTransform
      // copy the resultant jars to $buildDir/asmTransform
   }
} 
compileJava.dependsOn asmTransform

I am packaging as a zip. The idea is to preprocess dependencies as they are loaded so that they are access transformed in the IDE.

Im not entirely sure how given your method I would actually pass this through an asm transformer?

I’m far from an ASM guru but I believe there’s two approaches

  1. Build time transformation

This would involve a Gradle task which applies byte code manipulation to a jar and saves a new version of the jar which is depended upon instead of the original. This is what my suggestion above is about.

  1. Runtime transformation

This would require an ASM interceptor in your application (and tests) which transform classes prior to loading them. In this case the original jars not be transformed. Gradle would not be involved in this option.

The idea is to preprocess dependencies as they are loaded so that they are access transformed in the IDE.

I’m unsure what this statement means, I’m guessing you’re talking about running tests in the IDE?

I have same goal as topic starter’s.

For example I have couple of dependencies from maven central:

dependencies {
    // No matter what dependencies. Let there be these three.
    implementation "com.google.code.gson:gson:2.7"
    implementation "com.google.guava:guava:10.0"
    implementation "io.netty:netty-all:4.0.23.Final"
}

These dependencies shown as external libraries in IntelliJ IDEA:

Screenshot from 2022-11-10 21-54-22

And because of this IDEA shows code completion hints, code inspections and other cool things that this IDE offer to developers:

Screenshot from 2022-11-10 21-57-21

And I want to make some modifications to all these three dependencies using ASM/ByteBuddy/Javaassist/WhateverElse and completely replace original maven dependency with my modified version.

Your suggested solution makes processed dependencies invisible for IDEA (they disappears from external libraries section). So all power of this IDE lost and IDE turns into plain notepad.

I don’t know how exactly IDEA intergates with gradle and how dependency list is obtained. Something like gradle -q dependencies --configuration testRuntimeClasspath I guess.

Not quite, IntelliJ is not just calling a report task and parsing the output.
It lets Gradle properly resolve the configurations and then gets the actual list of files to use a dependencies as you can also see if you look at the details of the dependencies in the IDE which directly are the JARs in the Gradle cache.

I’d recommend to use an artifact transform, that is exactly what you are after and should then also properly work in the IDE like you expect: Transforming dependency artifacts on resolution