MCPcopy
hub / github.com/raphw/byte-buddy

github.com/raphw/byte-buddy @byte-buddy-1.18.11 sqlite

repository ↗ · DeepWiki ↗ · release byte-buddy-1.18.11 ↗
24,274 symbols 154,237 edges 1,235 files 11,086 documented · 46%
README

Byte Buddy

Byte Buddy logo

runtime code generation for the Java virtual machine

Actions Status Security Score Coverage Status Maven Central CII Best Practices

Byte Buddy is a code generation and manipulation library for creating and modifying Java classes during the runtime of a Java application and without the help of a compiler. Other than the code generation utilities that ship with the Java Class Library, Byte Buddy allows the creation of arbitrary classes and is not limited to implementing interfaces for the creation of runtime proxies. Furthermore, Byte Buddy offers a convenient API for changing classes either manually, using a Java agent or during a build.

Java version compatibility

The following table lists the minimal versions of Byte Buddy that is required need to support a certain Java class file version without experimental support. The oldest supported Java version is Java 5, whereas class files of any older version can be transformed. As of 1.17.0, support will extend to new Java versions unless previously unknown class file features are discovered. This is possible through Byte Buddy's support of the Class File API.

Byte Buddy version Supported Java version Minimum JVM version
1.18.7 25+ 8
1.18.7-jdk5 25+ 5
1.17.0 25+ 5
1.15.4 24 5
1.14.12 23 5
1.14.8 22 5
1.14.3 21 5
1.12.18 20 5
1.12.9 19 5
1.11.6 18 5
1.10.19 17 5

Usage

In order to use Byte Buddy, one does not require an understanding of Java byte code or the class file format. In contrast, Byte Buddy’s API aims for code that is concise and easy to understand for everybody. Nevertheless, Byte Buddy remains fully customizable down to the possibility of defining custom byte code. Furthermore, the API was designed to be as non-intrusive as possible and as a result, Byte Buddy does not leave any trace in the classes that were created by it. For this reason, the generated classes can exist without requiring Byte Buddy on the class path. Because of this feature, Byte Buddy’s mascot was chosen to be a ghost.

Byte Buddy is written in Java 5 but supports the generation of classes for any Java version. Byte Buddy is a light-weight library and only depends on the visitor API of the Java byte code parser library ASM which does itself not require any further dependencies.

At first sight, runtime code generation can appear to be some sort of black magic that should be avoided and only few developers write applications that explicitly generate code during their runtime. However, this picture changes when creating libraries that need to interact with arbitrary code and types that are unknown at compile time. In this context, a library implementer must often choose between either requiring a user to implement library-proprietary interfaces or to generate code at runtime when the user’s types becomes first known to the library. Many known libraries such as for example Spring or Hibernate choose the latter approach which is popular among their users under the term of using Plain Old Java Objects. As a result, code generation has become an ubiquitous concept in the Java space. Byte Buddy is an attempt to innovate the runtime creation of Java types in order to provide a better tool set to those relying on code generation.


Duke's Choice award

In October 2015, Byte Buddy was distinguished with a Duke's Choice award by Oracle. The award appreciates Byte Buddy for its "tremendous amount of innovation in Java Technology". We feel very honored for having received this award and want to thank all users and everybody else who helped making Byte Buddy the success it has become. We really appreciate it!


Byte Buddy offers excellent performance at production quality. It is stable and in use by distinguished frameworks and tools such as Mockito, Hibernate , Jackson, Google's Bazel build system and many others. Byte Buddy is also used by a large number of commercial products to great result. It is currently downloaded over 75 million times a year.

Hello World

Saying Hello World with Byte Buddy is as easy as it can get. Any creation of a Java class starts with an instance of the ByteBuddy class which represents a configuration for creating new types:

Class<?> dynamicType = new ByteBuddy()
  .subclass(Object.class)
  .method(ElementMatchers.named("toString"))
  .intercept(FixedValue.value("Hello World!"))
  .make()
  .load(getClass().getClassLoader())
  .getLoaded();
assertThat(dynamicType.newInstance().toString(), is("Hello World!"));

The default ByteBuddy configuration which is used in the above example creates a Java class in the newest version of the class file format that is understood by the processing Java virtual machine. As hopefully obvious from the example code, the created type will extend the Object class and overrides its toString method which should return a fixed value of Hello World!. The method to be overridden is identified by a so-called ElementMatcher. In the above example, a predefined element matcher named(String) is used which identifies methods by their exact names. Byte Buddy comes with numerous predefined and well-tested matchers which are collected in the ElementMatchers class and which can be easily composed. The creation of custom matchers is however as simple as implementing the (functional) ElementMatcher interface.

For implementing the toString method, the FixedValue class defines a constant return value for the overridden method. Defining a constant value is only one example of many method interceptors that ship with Byte Buddy. By implementing the Implementation interface, a method could however even be defined by custom byte code.

Finally, the described Java class is created and then loaded into the Java virtual machine. For this purpose, a target class loader is required. Eventually, we can convince ourselves of the result by calling the toString method on an instance of the created class and finding the return value to represent the constant value we expected.

A more complex example

Of course, a Hello World example is a too simple use case for evaluating the quality of a code generation library. In reality, a user of such a library wants to perform more complex manipulations, for example by introducing hooks into the execution path of a Java program. Using Byte Buddy, doing so is however equally simple. The following example gives a taste of how method calls can be intercepted.

Byte Buddy expresses dynamically defined method implementations by instances of the Implementation interface. In the previous example, FixedValue that implements this interface was already demonstrated. By implementing this interface, a user of Byte Buddy can go to the length of defining custom byte code for a method. Normally, it is however easier to use Byte Buddy's predefined implementations such as MethodDelegation which allows for implementing any method in plain Java. Using this implementation is straight forward as it operates by delegating the control flow to any POJO. As an example of such a POJO, Byte Buddy can for example redirect a call to the only method of the following class:

public class GreetingInterceptor {
  public Object greet(Object argument) {
    return "Hello from " + argument;
  }
}

Note that the above GreetingInterceptor does not depend on any Byte Buddy type. This is good news because none of the classes that Byte Buddy generates require Byte Buddy on the class path! Given the above GreetingInterceptor, we can use Byte Buddy to implement the Java 8 java.util.function.Function interface and its abstract apply method:

Class<? extends java.util.function.Function> dynamicType = new ByteBuddy()
  .subclass(java.util.function.Function.class)
  .method(ElementMatchers.named("apply"))
  .intercept(MethodDelegation.to(new GreetingInterceptor()))
  .make()
  .load(getClass().getClassLoader())
  .getLoaded();
assertThat((String) dynamicType.newInstance().apply("Byte Buddy"), is("Hello from Byte Buddy"));

Executing the above code, Byte Buddy implements Java's Function interface and implements the apply method as a delegation to an instance of the GreetingInterceptor POJO that we defined before. Now, every time that the Function::apply method is called, the control flow is dispatched to GreetingInterceptor::greet and the latter method's return value is returned from the interface's method.

Interceptors can be defined to take with more generic inputs and outputs by annotating the interceptor's parameters. When Byte Buddy discovers an annotation, the library injects the dependency that the interceptor parameter requires. An example for a more general interceptor is the following class:

public class GeneralInterceptor {
  @RuntimeType
  public Object intercept(@AllArguments Object[] allArguments,
                          @Origin Method method) {
    // intercept any method of any signature
  }
}

With the above interceptor, any intercepted method could be matched and processed. For example, when matching Function::apply, the method's arguments would be passed as the single element of an array. Also, a Method reference to Fuction::apply would be passed as the interceptor's second argument due to the @Origin annotation. By declaring the @RuntimeType annotation on the method, Byte Buddy finally casts the returned value to the return value of the intercepted method if this is necessary. In doing so, Byte Buddy also applies automatic boxing and unboxing.

Besides the annotations that were already mentioned there exist plenty of other predefined annotations. For example, when using the @SuperCall annotation on a Runnable or Callable type, Byte Buddy injects proxy instances that allow for an invocation of a non-abstract super method if such a method exists. And even if Byte Buddy does not cover a use case, Byte Buddy offers an extension mechanism for defining custom annotations.

You might expect that using these annotations ties your code to Byte Buddy. However, Java ignores annotations in case that they are not visible to a class loader. This way, generated code can still exist without Byte Buddy! You can find more information on the MethodDelegation and on all of its predefined annotations in its javadoc and in Byte Buddy's tutorial.

Changing existing classes

Byte Buddy is not limited to creating subclasses but is also capable of redefining existing code. To do so, Byte Buddy offers a convenient API for defining so-called Java agents. Java agents are plain old Java programs that can be used to alter the code of an existing Java application during its runtime. As an example, we can use Byte Buddy to change methods to print their execution time. For this, we first define an interceptor similar to the interceptors in the previous examples:

public class TimingInterceptor {
  @RuntimeType
  public static Object intercept(@Origin Method method, 
                                 @SuperCall Callable<?> callable) {
    long start = System.currentTimeMillis();
    try {
      return callable.call();
    } finally {
      System.out.println(method + " took " + (System.currentTimeMillis() - start));
    }
  }
}

Using a Java agent, we can now apply this interceptor to all types that match an ElementMatcher for a TypeDescription. For the example, we choose to add the above interceptor to all types with a name that ends in Timed. This is done for the sake of simplic

Extension points exported contracts — how you extend this code

ExampleInterface (Interface)
An example interface with several methods which is used as a specimen in benchmarks. [18 implementers]
byte-buddy-benchmark/src/main/java/net/bytebuddy/benchmark/specimen/ExampleInterface.java
StrategyCreator (Interface)
A strategy creator for Android. [83 implementers]
byte-buddy-android-test/src/main/java/net/bytebuddy/android/test/TestActivity.java
FileProcessor (Interface)
A processor for files that are added to a dex file. [29 implementers]
byte-buddy-android/src/main/java/net/bytebuddy/android/AndroidClassLoadingStrategy.java
VersionLocator (Interface)
A locator for the executing VM's Java version. [206 implementers]
byte-buddy-dep/src/main/java/net/bytebuddy/ClassFileVersion.java
AttachmentProvider (Interface)
An attachment provider is responsible for making the Java attachment API available. [7 implementers]
byte-buddy-agent/src/main/java/net/bytebuddy/agent/ByteBuddyAgent.java
ServiceDefinition (Interface)
(no doc) [14 implementers]
byte-buddy-gradle-plugin/android-plugin-test/service-definition-lib/src/main/java/com/service/definition/ServiceDefinition.java
FileChange (Interface)
A placeholder representation of Gradle's org.gradle.work.FileChange type.
byte-buddy-gradle-plugin/src/main/java-gradle-api/org/gradle/work/FileChange.java
DexProcessor (Interface)
A dex processor is responsible for converting a collection of Java class files into a Android dex file. [9 implementers]
byte-buddy-android/src/main/java/net/bytebuddy/android/AndroidClassLoadingStrategy.java

Core symbols most depended-on inside this repo

of
called by 2290
byte-buddy-dep/src/main/java/net/bytebuddy/utility/JavaConstant.java
get
called by 1441
byte-buddy-dep/src/test/java/net/bytebuddy/implementation/MethodDelegationFieldProxyTest.java
getLoaded
called by 1342
byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/DynamicType.java
getOnly
called by 1216
byte-buddy-dep/src/main/java/net/bytebuddy/matcher/FilterableList.java
load
called by 1202
byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/DynamicType.java
named
called by 1189
byte-buddy-dep/src/main/java/net/bytebuddy/asm/Advice.java
matches
called by 1127
byte-buddy-dep/src/main/java/net/bytebuddy/matcher/ElementMatcher.java
getClassLoader
called by 1058
byte-buddy-dep/src/main/java/net/bytebuddy/utility/JavaModule.java

Shape

Method 18,877
Class 4,345
Interface 571
Enum 481

Languages

Java100%

Modules by API surface

byte-buddy-dep/src/main/java/net/bytebuddy/description/type/TypeDescription.java1,017 symbols
byte-buddy-dep/src/main/java/net/bytebuddy/asm/Advice.java853 symbols
byte-buddy-dep/src/main/java/net/bytebuddy/pool/TypePool.java819 symbols
byte-buddy-dep/src/main/java/net/bytebuddy/agent/builder/AgentBuilder.java818 symbols
byte-buddy-dep/src/test/java/net/bytebuddy/asm/AdviceTest.java577 symbols
byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/scaffold/TypeWriter.java533 symbols
byte-buddy-dep/src/main/java/net/bytebuddy/asm/MemberSubstitution.java480 symbols
byte-buddy-dep/src/test/java/net/bytebuddy/asm/AdviceRepeatOnNonDefaultValueTest.java454 symbols
byte-buddy-dep/src/test/java/net/bytebuddy/asm/AdviceRepeatOnDefaultValueTest.java454 symbols
byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/DynamicType.java447 symbols
byte-buddy-dep/src/test/java/net/bytebuddy/asm/AdviceSkipOnNonDefaultValueTest.java392 symbols
byte-buddy-dep/src/test/java/net/bytebuddy/asm/AdviceSkipOnDefaultValueTest.java392 symbols

Dependencies from manifests, versioned

${project.groupId}:byte-buddy-agent
${project.groupId}:byte-buddy-android
${project.groupId}:byte-buddy-benchmark
${project.groupId}:byte-buddy-dep
${project.groupId}:byte-buddy-gradle-plugin
${project.groupId}:byte-buddy-maven-plugin
cglib:cglib-nodep
codes.rafael.asmjdkbridge:asm-jdk-bridge
com.code-intelligence:jazzer-api
com.code-intelligence:jazzer-junit
com.google.android:android

For agents

$ claude mcp add byte-buddy \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact