raphw / byte-buddy

Runtime code generation for the Java virtual machine.
https://bytebuddy.net
Apache License 2.0
6.23k stars 804 forks source link

How to apply Byte Buddy plugin placed under /src/test? #1579

Closed martyn0ff closed 6 days ago

martyn0ff commented 8 months ago

Hey, I wrote a plugin to enhance some of the classes that are used only in tests. The plugin itself is located under /src/test folder. However I am not sure how to correctly configure POM file for this to work in a way I expect (or if this is possible at all). Below is a snippet from build section.

<build>
  ...
 <plugin>
        <groupId>net.bytebuddy</groupId>
        <artifactId>byte-buddy-maven-plugin</artifactId>
        <version>${byte-buddy.version}</version>
        <executions>
          <execution>
            <goals>
              <goal>transform</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <execution>
          </execution>
          <transformations>
            <transformation>
              <plugin>
               <!-- Some plugin located in /src/main -->
              </plugin>
            </transformation>
            <transformation>
              <plugin>
               <!-- Some plugin located in /src/test -->
              </plugin>
            </transformation>
          </transformations>
        </configuration>
      </plugin>
...
</build>

Running mvn process-classes results in Maven not being able to resolve the second plugin. I've tried to change the goal from transform to transform-test and running process-test-classes phase instead, but that didn't work too. What can I do about this?

raphw commented 8 months ago

What you describe should work. What problem are you encountering when using transform-test?

martyn0ff commented 8 months ago

I'm getting the following error when I execute mvn clean process-test-classes: [ERROR] Failed to execute goal net.bytebuddy:byte-buddy-maven-plugin:1.14.5:transform-test (default) on project <project name>: Cannot resolve plugin: <fqpn of a plugin in /src/test> -> [Help 1]

raphw commented 8 months ago

Is the plugin included in the plugin's dependencies? It seems like a plugin fails to load. It should be added as a dependency to the plugin itself.

martyn0ff commented 8 months ago

@raphw Could you please elaborate? I'm not sure what do you mean.

raphw commented 8 months ago

In Maven, are the plugins available using:

<plugin>
  ...
  <dependencies>...</dependencies>
</plugin>

Or how are the plugins added to the build cycle.

martyn0ff commented 8 months ago

I add Byte Buddy plugins are into build cycle like so:

<!-- Byte Buddy plugins -->
<plugin>
  <groupId>net.bytebuddy</groupId>
  <artifactId>byte-buddy-maven-plugin</artifactId>
  <version>${byte-buddy.version}</version>
  <executions>
    <execution>
      <goals>
        <goal>transform</goal>
        <goal>transform-test</goal>
      </goals>
    </execution>
  </executions>
  <configuration>
    <execution>
    </execution>
    <transformations>
      <transformation>
        <plugin>
          <!-- fqpn of a plugin in /src/main is here !-->
        </plugin>
      </transformation>
      <transformation>
        <plugin>
         <!-- fqpn of a plugin in /src/test is here !-->
        </plugin>
      </transformation>
    </transformations>
  </configuration>
</plugin>
raphw commented 8 months ago

I think you need to define the plugin twice. Once transform for the plugin placed in main, once transform-test for the plugin placed in test. The test scope is not available while the main scope is resolved (and transformed).

martyn0ff commented 8 months ago

Unfortunately, I couldn't get it to work either. This is what I came up with:

<build>
<!-- other plugins -->
<!-- Byte Buddy plugins -->
<plugin>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy-maven-plugin</artifactId>
<version>${byte-buddy.version}</version>
<executions>
  <execution>
    <id>main</id>
    <goals>
      <goal>transform</goal>
    </goals>
    <configuration>
      <transformations>
        <transformation>
          <plugin>
            <!-- fqpn of a plugin in /src/main -->
          </plugin>
        </transformation>
      </transformations>
    </configuration>
  </execution>
  <execution>
    <id>test</id>
    <goals>
      <goal>transform-test</goal>
    </goals>
    <phase>process-test-classes</phase>
    <configuration>
      <transformations>
        <transformation>
          <plugin>
            <!-- fqpn of a plugin in /src/test -->
          </plugin>
        </transformation>
      </transformations>
    </configuration>
  </execution>
</executions>
</plugin>
</build>

Am I missing something here? Logically this should work, I'm binding my plugin to process-test-classes phase explicitly, which by then should be able to see all my compiled test classes. I also have tried declaring byte-buddy-maven-plugin twice, each with its own <execution>, but it also fails (not to mention Maven giving a warning about using same plugin twice).

raphw commented 8 months ago

That's how I'd do it and it works for me.

Could hou create a minimal reproducer?

martyn0ff commented 8 months ago

Sure, here it is: https://github.com/martyn0ff/bytebuddy-reproducer. I'm working with Spring Boot, so this is a minimal Spring Boot project which fails with same error (not sure if it may affect the result somehow).

raphw commented 8 months ago

I see now what the issue is. The configuration refers to a Maven Coordinate. You would need to create a "test-jar" and then set:

<packaging>test-jar</packaging>

In the plugin-tag.

An easier option would however be to create a custom Maven module that includes your plugin and then configure it by setting

<artifactId>my-plugin-module</artifactId>

Alternatively, you can also activate class path discovery and load the plugin from a service. This would trigger both plugins during test, though.

martyn0ff commented 7 months ago

Thank you Rafael, this had worked very well. However now I am experiencing another issue - a ByteBuddy plugin that I wrote can not see classes that are located in test source folder. The plugin is supposed to scan test classes for annotations, find my custom annotation that takes takes an instance of Class<?> as annotation attribute and perform some logic based on the class passed. If I pass a class that is located in source folder, everything is OK, but with classes from test source folder I am getting TypeNotFoundException.

 Failed to transform class com.acme.foo.TestClass using com.acme.foo.ByteBuddyPlugin8021e26: Type com.acme.foo.Baz not present -> [Help 1]

What can I do about it?

raphw commented 7 months ago

Are you still using the transform-test goal? It's resolving the test class path: https://github.com/raphw/byte-buddy/blob/master/byte-buddy-maven-plugin/src/main/java/net/bytebuddy/build/maven/ByteBuddyMojo.java#L668