We can get the latest versions of asm and asm-util from Maven Central.

3. ASM API Basics

The ASM API provides two styles of interacting with Java classes for transformation and generation: event-based and tree-based.

3.1. Event-based API

This API is heavily based on the Visitor pattern and is similar in feel to the SAX parsing model of processing XML documents. It is comprised, at its core, of the following components:

ClassReader – helps to read class files and is the beginning of transforming a class

ClassVisitor – provides the methods used to transform the class after reading the raw class files

ClassWriter – is used to output the final product of the class transformation

It’s in the ClassVisitor that we have all the visitor methods that we’ll use to touch the different components (fields, methods, etc.) of a given Java class. We do this by providing a subclass of ClassVisitorto implement any changes in a given class.

Due to the need to preserve the integrity of the output class concerning Java conventions and the resulting bytecode, this class requires a strict order in which its methods should be called to generate correct output.

The ClassVisitor methods in the event-based API are called in the following order:

3.2. Tree-based API

This API is a more object-oriented API and is analogous to the JAXB model of processing XML documents.

It’s still based on the event-based API, but it introduces the ClassNode root class. This class serves as the entry point into the class structure.

4. Working With the Event-based ASM API

We’ll modify the java.lang.Integer class with ASM. And we need to grasp a fundamental concept at this point: the ClassVisitor class contains all the necessary visitor methods to create or modify all the parts of a class.

We only need to override the necessary visitor method to implement our changes. Let’s start by setting up the prerequisite components:

Next, let’s override the visitField method, where we first check if the field we plan to add already exists and set a flag to indicate the status.

We still have to forward the method call to the parent class — this needs to happen as the visitField method is called for every field in the class. Failing to forward the call means no fields will be written to the class.

This method also allows us to modify the visibility or type of existing fields:

We first check the flag set in the earlier visitField method and call the visitField method again, this time providing the name, access modifier, and description. This method returns an instance of FieldVisitor.

The visitEnd method is the last method called in order of the visitor methods. This is the recommended position to carry out the field insertion logic.

Then, we need to call the visitEnd method on this object to signal that we’re done visiting this field:

It’s important to be sure that all the ASM components used come from the org.objectweb.asm package — a lot of libraries use the ASM library internally and IDEs could auto-insert the bundled ASM libraries.

We now use our adapter in the addField method, obtaining a transformed version of java.lang.Integerwith our added field:

Everything to be done concerning fields happens with the visitField method. This means we can also modify existing fields (say, transforming a private field to the public) by changing the desired values passed to the visitField method.

4.2. Working With Methods

Generating whole methods in the ASM API is more involved than other operations in the class. This involves a significant amount of low-level byte-code manipulation and, as a result, is beyond the scope of this article.

For most practical uses, however, we can either modify an existing method to make it more accessible (perhaps make it public so that it can be overridden or overloaded) or modify a class to make it extensible.

It would be nice to see the imports at the beginning to know which Classes are used, so you kinda have to guess which is the right one. Furthermore do you pass under point 4.1 a variable to the function cv.visitField that occurs nowhere else (fieldType)…