jOOQ Tuesdays: Rafael Winterhalter is Wrestling Byte Code with Byte Buddy
Welcome to the jOOQ Tuesdays series. In this series, we’ll publish an article on the third Tuesday every other month where we interview someone we find exciting in our industry from a jOOQ perspective. This includes people who work with SQL, Java, Open Source, and a variety of other related topics.
We have the pleasure of talking to Rafael Winterhalter in this seventh edition who will be telling us about the depths of Java byte code, and about his library Byte Buddy, which makes working with byte code extremely easy.
Note that Byte Buddy won the 2015 Duke’s Choice award – congratulations to this from our side!
Hi Rafael – You’re the author of the popular Byte Buddy library. What does Byte Buddy do?
Byte Buddy is a code generation and manipulation library. It offers APIs for creating new Java classes at runtime and for changing existing classes before or after they were loaded.
At first glance, this might sound like a very esoteric thing to do, but runtime code generation is used in a large number of Java projects. Code generation tools are often used by library developers to implement aspect-oriented programming. For example, the mocking library Mockito adopted Byte Buddy to create subclasses of mocked classes at runtime. In order to implement a mock, Mockito overrides all methods of a class such that the user’s original code is not invoked when a method is called in a test. And there are plenty of other well-known users of code generation. Spring, for example, uses code generation to implement its annotation aspects such as security or transactions. And Hibernate uses code-generation to lazily load properties from getter methods by overriding those getters to query the database only if they are invoked.
Why is there a need for Byte Buddy when there are alternatives like ASM, CGLIB, AspectJ or Javassist?
Before I started working on Byte Buddy, I was involved in several other open-source projects as a contributor. As mentioned before, code generation is a typical requirement for implementing many libraries and so I got used to working with mostly CGLIB and Javassist. However, I became constantly frustrated with those libraries’ limitations and I wanted to resolve the problems I had discovered. Eventually, I started to write an alternative library that I later published as Byte Buddy.
To understand the limitations of alternative libraries, mocks are a good example use case. Mocks in Mockito were previously created using CGLIB. CGLIB is a rather mature library. It has been around for over 15 years and when it was originally developed, the library’s developers did of course not anticipate features such as annotations, generic types or defender methods. Annotations did however become an important part of many APIs which would not accept a mock instance because any annotations of overridden methods were lost. In Java, annotations on methods are never inherited when they are overridden. And annotations on types are only inherited if they are explicitly declared to be. To overcome this, Byte Buddy allows to copy any annotation to a subclass what is now a feature in Mockito 2.
In contrast, Javassist allows to copy annotations, but I do not personally like the approach of the library. In Javassist, all generated code is represented as Java code contained in strings. As a result, Javassist code evolves similarly unstructured to Java code that only describes SQL as concatenated strings. Besides creating code that is difficult to maintain, this approach also offers vulnerabilities such as Java code injection similar to SQL injection. It is sometimes possible to attack Javassist code by letting it compile arbitrary code what can cause sever damage to an application.
AspectJ is a powerful tool when manipulating existing code. However, Byte Buddy lets you do anything that AspectJ is capable of but in plain and simple Java. This way, developers do not need to learn a new syntax or programming metaphor or install tools for their build-process and IDEs. Furthermore, I do not find the join-point and point-cut terminology intuitive and decided to avoid it altogether. Instead, I decided to mimic terminology that developers already know from the Java programming language to ease the first steps with Byte Buddy.
ASM on the other hand is the basis on top of which Byte Buddy is implemented. ASM is a byte code parser rather than a code generation library. ASM processes single class files and does not consider type hierarchies. ASM does neither have a concept of class loading and does not include higher-level concepts on top of byte code instructions. Byte Buddy offers however an adapter that exposes the ASM API to users that require the generation of very specific code.
How does one become so involved with low-level Java?
In the beginning, I set myself a goal of only creating a version of CGLIB with annotation support which was what I originally needed. But I quickly found out that a lot of developers were looking for the solution that Byte Buddy has become today. Therefore, I started to plan to make the full feature set of the Java virtual machine accessible. For doing so, learning all the gory details and corner cases of the class file format has become a necessity to implement these features. To be fair, the class file format is fairly trivial once you get the hang of it and I really enjoy to see my library mature.
Between Java byte code (2GL language) and SQL (4GL language), there are many levels of programmatic abstraction. Where do you feel at home the most?
I would want to use the right tool for the right job. Obviously, I enjoy working with byte code, but I would avoid handcrafting byte code when working in a production project. In the end, this is what higher-level abstractions such as Byte Buddy are made for.
Looking at the common use cases, Byte Buddy is however often used for implementing custom features by changing code based on annotations on methods. In a way, Byte Buddy enables developers to implement their own 4G abstraction. Declarative programming is a great abstraction for certain tasks, SQL being one of them.
You’ve become a famous speaker and domain expert in a very short time. What’s your most exciting story, being an influencer?
Mainly, I find it exciting to meet users of my library. I have met folks that implemented internal frameworks with large teams that is based on my software and obviously, it makes me proud that Byte Buddy proves to be that useful.
Thank you very much Rafael
If you want to learn more about Rafael’s work, about byte code or about Byte Buddy, check out his talk at JavaZone:
Reference: | jOOQ Tuesdays: Rafael Winterhalter is Wrestling Byte Code with Byte Buddy from our JCG partner Lukas Eder at the JAVA, SQL, AND JOOQ blog. |