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.
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 unknown type hierarchies. 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 type hierarchy 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 such functionality.
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, 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.
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 which is read from the surrounding class. 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.
Of course, Byte Buddy is capable of much more sophisticated class generation. Furthermore, Byte Buddy is not limited to creating subclasses but can transform existing code. Byte Buddy also offers a convenient API for defining so-called Java agents which allow code transformations during the runtime of any Java application. For a taste of such features, have a look at the readme on Byte Buddy's GitHub page or get started with reading the full tutorial on this page!
Byte Buddy is written on top of ASM, a mature and well-tested library for reading and writing compiled Java classes. In order to allow for advanced type manipulations, Byte Buddy is intentionally exposing the ASM API to its users. Of course, the direct use of ASM remains fully optional and most users will most likely never require it. This choice was made such that a user of Byte Buddy is not restrained to its higher-level functionality but can implement custom implementations without a fuss when it is necessary.
ASM has previously changed its public API but added a mechanism for API compatibility starting with version
4 of the library. In order to avoid version conflicts with such older versions, Byte Buddy repackages the
ASM dependency into its own namespace. If you want to use ASM directly, use the byte-buddy-dep
artifact offers a version of Byte Buddy with an explicit dependency to ASM. When doing so, you must
repackage both Byte Buddy and ASM into your namespace to avoid version conflicts.