0

I am developing a Java agent using ByteBuddy, and I need the ByteBuddy library .jar file to be included in the agent .jar file. So far, in order for the agent to run smoothly, I need the ByteBuddy library .jar files to be present in the classpath both at compile time and at runtime. How can I bundle a .jar file such that the agent is self-contained ?

I tried using the shade plugin (as demonstrated here) as well as a few other techniques found on the web, but none of them seem to really include the dependencies in the .jar file, only a reference.

For every technique, I looked in the resulting .jar file (weighs around 5kB every time) and only found the .class files corresponding to the classes I had written, no class files related to ByteBuddy. To be clear, the ByteBuddy library .jar file weighs about 3MB, so I expect my self-contained agent .jar file to weigh around 3MB, as my code is light.

Below is my pom.xml file :

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.captainhook.agent</groupId>
  <artifactId>agent</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>agent</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>net.bytebuddy</groupId>
      <artifactId>bytebuddy</artifactId>
      <version>1.12.3</version>
      <scope>system</scope>
      <systemPath>${project.basedir}/byte-buddy-1.12.3.jar</systemPath>
   </dependency>
   <dependency>
    <groupId>net.bytebuddy.agent</groupId>
    <artifactId>bytebuddy-agent</artifactId>
    <version>1.12.3</version>
    <scope>system</scope>
    <systemPath>${project.basedir}/byte-buddy-agent-1.12.3.jar</systemPath>
 </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

And this is the output I get after running mvn package :

[...]
[INFO] 
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ agent ---
[INFO] 
[INFO] --- maven-assembly-plugin:2.2-beta-5:single (default) @ agent ---
[INFO] Building jar: /home/bluesheet/svn/stages/captainhook/2021/ijp-frida-jdi-bytebuddy/1/dbg/shared/agent/maven-test/agent/target/agent-1.0-SNAPSHOT-jar-with-dependencies.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.339 s
[INFO] Finished at: 2021-12-31T12:26:59+01:00
[INFO] ------------------------------------------------------------------------

EDIT: So, the reason why all the previous techniques were not working was because of the way I specified the dependencies. This doesn't get included :

<dependency>
    <groupId>net.bytebuddy</groupId>
    <artifactId>bytebuddy</artifactId>
    <version>1.12.3</version>
    <scope>system</scope>
    <systemPath>${project.basedir}/byte-buddy-1.12.3.jar</systemPath>
</dependency>

while this does :

<dependency>
    <groupId>net.bytebuddy</groupId>
    <artifactId>byte-buddy</artifactId>
    <version>1.12.6</version>
</dependency>

I am new to maven so I blindly copy-pasted a piece of code to include the dependencies and I did not spot the error... Thank you very much !

AntoineG
  • 93
  • 7
  • How does the documentation suggest you do this? – Thorbjørn Ravn Andersen Dec 31 '21 at 09:57
  • Does this answer your question? [Including dependencies in a jar with Maven](https://stackoverflow.com/questions/1729054/including-dependencies-in-a-jar-with-maven) – tgdavies Dec 31 '21 at 09:58
  • The documentation ([1](https://maven.apache.org/plugins/maven-shade-plugin/examples/executable-jar.html), [2](https://maven.apache.org/plugins/maven-assembly-plugin/usage.html)) suggests using the shade plugin or the assembly plugin, but both do not include any files related to my dependencies in the final jar file... So the stackoverflow post linked, which is using the assembly plugin, doesn't solve my issue. – AntoineG Dec 31 '21 at 10:05
  • Without seeing your pom.xml with your assembly plugin configuration, it's hard to say what's going wrong. – tgdavies Dec 31 '21 at 10:09
  • I just edited my post to include it – AntoineG Dec 31 '21 at 11:26

1 Answers1

2

Sounds like you need to use the "maven-assembly-plugin" with the "jar-with-dependencies" descriptor.

E.g. here is a full example pom file with a dependency on ByteBuddy:

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>test.example</groupId>
    <artifactId>packaging-example</artifactId>
    <version>1.0-SNAPSHOT</version>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.4.1</version>
                <configuration>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                    <archive>
                        <manifest>
                            <mainClass>test.example.TestByteBuddy</mainClass>
                        </manifest>
                    </archive>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>

        </plugins>
    </build>

    <dependencies>

        <dependency>
            <groupId>net.bytebuddy</groupId>
            <artifactId>byte-buddy</artifactId>
            <version>1.12.6</version>
        </dependency>

    </dependencies>

</project>

And for the sake of completeness - here is the main class also :

package test.example;

import net.bytebuddy.ByteBuddy;

public class TestByteBuddy
{
    public static void main(String... args) throws Exception
    {
        System.out.println("Hello Byte Buddy Class - " + ByteBuddy.class);
    }
}

Building this will produce an additional file in the target directory - packaging-example-1.0-SNAPSHOT-jar-with-dependencies.jar

Then you should be able to run it simply with :

java -jar packaging-example-1.0-SNAPSHOT-jar-with-dependencies.jar 

to give you the output:

Hello Byte Buddy Class - class net.bytebuddy.ByteBuddy
Dharman
  • 30,962
  • 25
  • 85
  • 135
JJS
  • 141
  • 3
  • Daaaaaaaaamn, the root of the problem was that I was providing bytebuddy as a local jar file instead of the maven repo in the dependencies. With the maven repo it works, my jar weighs 3.9MB. I don't understand why it only gets merged into the final jar when it is a maven repo and not when it is a local jar file, but man, thank you very much ! – AntoineG Dec 31 '21 at 11:36