The ability to inject pieces of code into compiled classes and methods, either statically or at runtime, may be of immense help. This applies especially to troubleshooting problems in third-party libraries without source codes or in an environment where it isn’t possible to use a debugger or a profiler. Code injection is also useful for dealing with concerns that cut across the whole application, such as performance monitoring. Using code injection in this way became popular under the name Aspect-Oriented Programming (AOP). Code injection isn’t something used only rarely as you might think, quite the contrary; every programmer will come into a situation where this ability could prevent a lot of pain and frustration.

This post is aimed at giving you the knowledge that you may (or I should rather say “will”) need and at persuading you that learning basics of code injection is really worth the little of your time that it takes. I’ll present three different real-world cases where code injection came to my rescue, solving each one with a different tool, fitting best the constraints at hand.

Why You Are Going to Need It

A lot has been already said about the advantages of AOP – and thus code injection – so I will only concentrate on a few main points from the troubleshooting point of view.

The coolest thing is that it enables you to modify third party, closed-source classes and actually even JVM classes. Most of us work with legacy code and code for which we haven’t the source codes and inevitably we occasionally hit the limitations or bugs of these 3rd-party binaries and need very much to change some small thing in there or to gain more insight into the code’s behavior. Without code injection you have no way to modify the code or to add support for increased observability into it. Also you often need to deal with issues or collect information in the production environment where you can’t use a debugger and similar tools while you usually can at least manage somehow your application’s binaries and dependencies. Consider the following situations:

You’re passing a collection of data to a closed-source library for processing and one method in the library fails for one of the elements but the exception provides no information about which element it was. You’d need to modify it to either log the offending argument or to include it in the exception. (And you can’t use a debugger because it only happens on the production application server.)

You need to collect performance statistics of important methods in your application including some of its closed-source components under the typical production load. (In the production you of course cannot use a profiler and you want to incur the minimal overhead.)

You use JDBC to send a lot of data to a database in batches and one of the batch updates fails. You would need some nice way to find out which batch it was and what data it contained.

I’ve in fact encountered these three cases (among others) and you will see possible implementations later.

You should keep the following advantages of code injection in your mind while reading this post:

Code injection enables you to modify binary classes for which you haven’t the source codes

The injected code can be used to collect various runtime information in environments where you cannot use the traditional development tools such as profilers and debuggers

Don’t Repeat Yourself: When you need the same piece of logic at multiple places, you can define it once and inject it into all those places.

With code injection you do not modify the original source files so it is great for (possibly large-scale) changes that you need only for a limited period of time, especially with tools that make it possible to easily switch the code injection on and off (such as AspectJ with its load-time weaving). A typical case is performance metrics collection and increased logging during troubleshooting

You can inject the code either statically, at the build time, or dynamically, when the target classes are being loaded by the JVM

Mini Glossary

You might encounter the following terms in relation to code injection and AOP:

Advice

The code to be injected. Typically we talk about before, after, and around advices, which are executed before, after, or instead of a target method. It’s possible to make also other changes than injecting code into methods, e.g. adding fields or interfaces to a class.

AOP (Aspect Oriented Programming)

A programming paradigm claiming that “cross-cutting concerns” – the logic needed at many places, without a single class where to implement them – should be implemented once and injected into those places. Check Wikipedia for a better description.

Aspect

A unit of modularity in AOP, corresponds roughly to a class – it can contain different advices and pointcuts.

Joint point

A particular point in a program that might be the target of code injection, e.g. a method call or method entry.

Pointcut

Roughly spoken, a pointcut is an expression which tells a code injection tool where to inject a particular piece of code, i.e. to which joint points to apply a particular advice. It could select only a single such point – e.g. execution of a single method – or many similar points – e.g. executions of all methods marked with a custom annotation such as @MyBusinessMethod.

There are many very different tools that can do the job so we will first have a look at the differences between them and then we will get acquainted with three prominent representatives of different evolution branches of code injection tools.

Basic Classification of Code Injection Tools

I. Level of Abstraction

How difficult is it to express the logic to be injected and to express the pointcuts where the logic should be inserted?

Regarding the “advice” code:

Direct bytecode manipulation (e.g. ASM) – to use these tools you need to understand the bytecode format of a class because they abstract very little from it, you work directly with opcodes, the operand stack and individual instructions. An ASM example:

They are difficult to use due to being so low-level but are the most powerful. Usually they are used to implement higher-level tools and only few actually need to use them.

Intermediate level – code in strings, some abstraction of the classfile structure (Javassist)

Advices in Java (e.g. AspectJ) – the code to be injected is expressed as syntax-checked and statically compiled Java

Regarding the specification of where to inject the code:

Manual injection – you have to get somehow hold of the place where you want to inject the code (ASM, Javassist)

Primitive pointcuts – you have rather limited possibilities for expressing where to inject the code, for example to a particular method, to all public methods of a class or to all public methods of classes in a group (Java EE interceptors)

Pattern matching pointcut expressions – powerful expressions matching joint points based on a number of criteria with wildcards, awareness of the context (e.g. “called from a class in the package XY”) etc. (AspectJ)

II. When the Magic Happens

The code can be injected at different points in time:

Manually at run-time – your code has to explicitly ask for the enhanced code, e.g. by manually instantiating a custom proxy wrapping the target object (this is arguably not true code injection)

At load-time – the modification are performed when the target classes are being loaded by the JVM

At build-time – you add an extra step to your build process to modify the compiled classes before packaging and deploying your application

Each of these modes of injection can be more suitable at different situations.

III. What It Can Do

The code injection tools vary pretty much in what they can or cannot do, some of the possibilities are:

Add code before/after/instead of a method – only member-level methods or also the static ones?

Add fields to a class

Add a new method

Make a class to implement an interface

Modify an instruction within the body of a method (e.g. a method call)

I’ve selected three rather different mature and popular code injection tools and will present them on real-world examples I’ve personally experienced.

The Omnipresent Dynamic Java Proxy

Java.lang.reflect.Proxy makes it possible to create dynamically a proxy for an interface, forwarding all calls to a target object. It is not a code injection tool for you cannot inject it anywhere, you must manually instantiate and use the proxy instead of the original object, and you can do this only for interfaces, but it can still be very useful as we will see.

Advantages:

It’s a part of JVM and thus is available everywhere

You can use the same proxy – more exactly an InvocationHandler – for incompatible objects and thus reuse the code more than you could normally

You save effort because you can easily forward all calls to a target object and only modify the ones interesting for you. If you were to implement a proxy manually, you would need to implement all the methods of the interface in question

Disadvantages:

You can create a dynamic proxy only for an interface, you can’t use it if your code expects a concrete class

You have to instantiate and apply it manually, there is no magical auto-injection

It’s little too verbose

Its power is very limited, it can only execute some code before/after/around a method

There is no code injection step – you have to apply the proxy manually.

Example

I was using JDBC PreparedStatement’s batch updates to modify a lot of data in a database and the processing was failing for one of the batch updates because of integrity constraint violation. The exception didn’t contain enough information to find out which data caused the failure and so I’ve created a dynamic proxy for the PreparedStatement that remembered values passed into each of the batch updates and in the case of a failure it automatically printed the batch number and the data. With this information I was able to fix the data and I kept the solution in place so that if a similar problems ever occurs again, I’ll be able to find its cause and resolve it quickly.

To create a proxy, you first need to implement an InvocationHandler and its invoke method, which is called whenever any of the interface’s methods is invoked on the proxy You can access the information about the call via the java.lang.reflect.* objects and for example delegate the call to the proxied object via method.invoke We’ve also an utility method for creating a proxy instance for a Prepared statement:

You can see that the newProxyInstance call takes a classloader, an array of interfaces that the proxy should implement, and the invocation handler that calls should be delegated to (the handler itself has to manage a reference to the proxied object, if it needs it)

You see that we have to manually wrap a raw object with the proxy and use the proxy further on

Alternative Solutions

This problem could be solved in different ways, for example by creating a non-dynamic proxy implementing PreparedStatement and forwarding all calls to the real statement while remembering batch data but it would be lot of boring typing for the interface has many methods. The caller could also manually keep track of the data it has send to the prepared statement but that would obscure its logic with an unrelated concern.

Using the dynamic Java proxy we get rather clean and easy to implement solution.

The Independent Javassist

JBoss Javassist is an intermediate code injection tool providing a higher-level abstraction than bytecode manipulation libraries and offering little limited but still very useful manipulation capabilities. The code to be injected is represented as strings and you have to manually get to the class-method where to inject it. Its main advantage is that the modified code has no new run-time dependencies, on Javassist or anything else. This may be the decisive factor if you are working for a large corporation where the deployment of additional open-source libraries (or just about any additional libraries) such as AspectJ is difficult for legal and other reasons.

Advantages:

Code modified by Javassist doesn’t require any new run-time dependencies, the injection happens at the build time and the injected advice code itself doesn’t depend on any Javassist API

Higher-level than bytecode manipulation libraries, the injected code is written in Java syntax, though enclosed in strings

Can do most things that you may need such as “advising” method calls and method executions

Still little too low-level and thus harder to use – you have to deal a little with structure of methods and the injected code is not syntax-checked

Javassist has no tools to perform the injection and you thus have to implement your own injection code – including that there isn’t support for injecting the code automatically based on a pattern

(See GluonJ below for a solution without most of the disadvantages of Javassist.)

With Javassist you create a class, which uses the Javassist API to inject code int targets and run it as a part of your build process after the compilation, for example as I once did via a custom Ant task.

Example

We needed to add some simple performance monitoring to our Java EE application and we were not allowed to deploy any non-approved open-source library (at least not without going through a time-consuming approval process). We’ve therefore used Javassist to inject the performance monitoring code to our important methods and to the places were important external methods were called.

You can see the “low-levelness” – you have to explicitly deal with objects like CtClass, CtMethod, explicitly add a local variable etc.

Javassist is rather flexible in where it can look for the classes to modify – it can search the classpath, a particular folder, a JAR file, or a folder with JAR files

You would compile this class and run its main during your build process

Javassist on Steroids: GluonJ

GluonJ is an AOP tool building on top of Javassist. It can use either a custom syntax or Java 5 annotations and it’s build around the concept of “revisers”. Reviser is a class – an aspect – that revises, i.e. modifies, a particular target class and overrides one or more of its methods (contrary to inheritance, the reviser’s code is physically imposed over the original code inside the target class).

Advantages:

No run-time dependencies if build-time weaving used (load-time weaving requires the GluonJ agent library or gluonj.jar)

Simple Java syntax using GlutonJ’s annotation – though the custom syntax is also trivial to understand and easy to use

Easy, automatic weaving into the target classes with GlutonJ’s JAR tool, an Ant task or dynamically at the load-time

Support for both build-time and load-time weaving

Disadvantages:

An aspect can modify only a single class, you cannot inject the same piece of code to multiple classes/methods

Limited power – only provides for field/method addition and execution of a code instead of/around a target method, either upon any of its executions or only if the execution happens in a particular context, i.e. when called from a particular class/method

If you don’t need to inject the same piece of code into multiple methods then GluonJ is easier and better choice than Javassist and if its simplicity isn’t a problem for you then it also might be a better choice than AspectJ just thanks to this simplicity.

The Almighty AspectJ

AspectJ is a full-blown AOP tool, it can do nearly anything you might want, including the modification of static methods, addition of new fields, addition of an interface to a class’ list of implemented interfaces etc.

The syntax of AspectJ advices comes in two flavours, one is a superset of Java syntax with additional keywords like aspect and pointcut, the other one – called @AspectJ – is standard Java 5 with annotations such as @Aspect, @Pointcut, @Around. The latter is perhaps easier to learn and use but also little less powerful as it isn’t as expressive as the custom AspectJ syntax.

With AspectJ you can define which joint points to advise with very powerful expressions but it may be little difficult to learn them and to get them right. There is a useful Eclipse plugin for AspectJ development – the AspectJ Development Tools (AJDT) – but the last time I’ve tried it it wasn’t as helpful as I’d have liked.

Advantages:

Very powerful, can do nearly anything you might need

Powerful pointcut expressions for defining where to inject an advice and when to activate it (including some run-time checks) – fully enables DRY, i.e. write once & inject many times

Both build-time and load-time code injection (weaving)

Disadvantages:

The modified code depends on the AspectJ runtime library

The pointcut expressions are very powerful but it might be difficult to get them right and there isn’t much support for “debugging” them though the AJDT plugin is partially able to visualize their effects

It will likely take some time to get started though the basic usage is pretty simple (using @Aspect, @Around, and a simple pointcut expression, as we will see in the example)

Example

Once upon time I was writing a plugin for a closed-source LMS J2EE application having such dependencies that it wasn’t feasible to run it locally. During an API call, a method deep inside the application was failing but the exception didn’t contain enough information to track the cause of the problem. I therefore needed to change the method to log the value of its argument when it fails.

The aspect is a normal Java class with the @Aspect annotation, which is just a marker for AspectJ

The @Around annotation instructs AspectJ to execute the method instead of the one matched by the expression, i.e. instead of the failingMethod of the TooQuiet3rdPartyClass

The around advice method needs to be public, return an Object, and take a special AspectJ object carrying information about the invocation – ProceedingJoinPoint – as its argument and it may have an arbitrary name (Actually this is the minimal form of the signature, it could be more complex.)

We use the ProceedingJoinPoint to delegate the call to the original target (an instance of the TooQuiet3rdPartyClass) and, in the case of an exception, to get the argument’s value

I’ve used an @Around advice though @AfterThrowing would be simpler and more appropriate but this shows better the capabilities of AspectJ and can be nicely compared to the dynamic java proxy example above

Since I hadn’t control over the application’s environment, I couldn’t enable the load-time weaving and thus had to use AspectJ’s Ant task to weave the code at the build time, re-package the affected JAR and re-deploy it to the server.

Alternative Solutions

Well, if you can’t use a debugger then your options are quite limited. The only alternative solution I could think of is to decompile the class (illegal!), add the logging into the method (provided that the decompilation succeeds), re-compile it and replace the original .class with the modified one.

The Dark Side

Code injection and Aspect Oriented Programming are very powerful and sometimes indispensable both for troubleshooting and as a regular part of application architecture, as we can see e.g. in the case of Java EE’s Enterprise Java Beans where the business concerns such as transaction management and security checks are injected into POJOs (though implementations actually more likely use proxies) or in Spring.

However there is a price to be paid in terms of possibly decreased understandability as the runtime behavior and structure are different from what you’d expect based on the source codes (unless you know to check also the aspects’ sources or unless the injection is made explicit by annotations on the target classes such as Java EE’s @Interceptors). Therefore you must carefully weight the benefits and drawbacks of code injection/AOP – though when used reasonably, they do not obscure the program flow more than interfaces, factories etc. The argument about obscuring code is perhaps often over-estimated.

If you want to see an example of AOP gone wild, check the source codes of Glassbox, a JavaEE performance monitoring tool (for that you might need a map not to get too lost).

Fancy Uses of Code Injection and AOP

The main field of application of code injection in the process of troubleshooting is logging, more exactly gaining visibility into what an application is doing by extracting and somehow communicating interesting runtime information about it. However AOP has many interesting uses beyond – simple or complex – logging, for example:

Solving though problems and avoiding monkey-coding with AOP patterns such as Worker Object Creation (turn direct calls into asynchronous with a Runnable and a ThreadPool/task queue) and Wormhole (make context information from a caller available to the callee without having to pass them through all the layers as parameters and without a ThreadLocal) – described in the book AspectJ in Action

Preserving backwards-compatibility of an API while not blocking its ability to evolve e.g. by adding backwards-compatible methods when return types have been narrowed/widened (Bridge Method Injector – uses ASM) or by re-adding old methods and implementing them in terms of the new API

Turning POJOs into JMX beans

Summary

We’ve learned that code injection can be indispensable for troubleshooting, especially when dealing with closed-source libraries and complex deployment environments. We’ve seen three rather different code injection tools – dynamic Java proxies, Javassist, AspectJ – applied to real-world problems and discussed their advantages and disadvantages because different tools may be suitable for different cases. We’ve also mentioned that code injection/AOP shouldn’t be overused and looked at some examples of advanced applications of code injection/AOP.

I hope that you now understand how code injection can help you and know how to use these three tools.

Newsletter

Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

Email address:

Recent Jobs

No job listings found.

Join Us

With 1,240,600 monthly unique visitors and over 500 authors we are placed among the top Java related sites around. Constantly being on the lookout for partners; we encourage you to join us. So If you have a blog with unique and interesting content then you should check out our JCG partners program. You can also be a guest writer for Java Code Geeks and hone your writing skills!

Disclaimer

All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners. Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries. Examples Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.