How do I configure bytecode instrumentation?

We are using Hibernate buildtime bytecode instrumentation for our persistent classes. It is important that the instrumented byte code is used in all later steps (running the tests, building the packages, …). sourceSets.main.classes should also point to the instrumented byte code. Should we use a separate task for instrumenting the code?

There are different scenarios for instrumenting byte code. One aspect is whether the instrumented byte code is going to be shipped as in your case. Or whether for example it is used for test coverage.

For your scenario I would propose to add the instrumentation as a doLast action to the compileJava task. That way incremental build will work fine as the output of the compileJava task is checked after the last action is executed.

If you do it as a separate task it should not overwrite the output of the compileJava task. Otherwise the compileJava will always be triggered even if the sources have not changed. Which again will always trigger the instrumentation task. If you want to do separate tasks you would nee to do the following:

  • Set the output dir of the instrumentation task to the current output dir of the compileJava task. - Change the output dir of the compileJava task to something like classes/main-uninstrumented. - Set the input dir of the instrumentation task to the new output dir of the compileJava task. - Copy the output of the compileJava task to the output dir of the instrumentation task before the actual instrumentation activity. In your case the instrumentation will only instrument a subset of the classes.

The advantage of having a separate task is that you have the full offerings of Gradle available (e.g. excluding, profiling, …). But in your case this seems to be too much of a hazzle. For test byte-code instrumentation that would be a different story as you anyhow need two copies.

In the future we plan to introduce the concept of finalizer tasks. They could provide a nice solution as the would enable incremental build without the necessity to copy.

1 Like

Task.finalizedBy() is in action now…

Does Gradle take snapshots of task.outputs.files AFTER the execution of configured finalizer task(s)?

Because now I have an described above behaviour (compileJava & bytecode instrumentation task triggers each other due to up-to-date check wrong).

That would be nice to have a Task’s method to trigger such inputs/outputs.files snapshot gathering which will operate on files’ current versions.