Imagine a bacon-wrapped Ferrari. Still not better than our free technical reports.
See all our reports

How to make Java more dynamic with Runtime Code Generation

hand-fixing-hand

The programmatic generation of code is something very intrinsic to the Java platform. When a Java application is compiled, the Java compiler serves you bytecode instead of an executable program. Bytecode is a Java-specific format and not of much use by itself. In order to execute bytecode, it is translated into native machine code at runtime by a JVM’s just-in-time compiler.

So much for Java 101. Even though most Java developers have heard about just-in-time compilation, it is one of the strengths of the platform that you do not need to know any details about it while you can still write great Java programs.

However, with the ongoing POJO-revolution, another form of code generation disseminates in the Java landscape. Many modern Java libraries and frameworks do their magic by defining on-demand classes during a Java application’s runtime.

At first glance, this sounds awfully academic. But check your average business application’s stack trace and you will most certainly find plenty of runtime generated classes. And other than just-in-time compiled code, runtime generated classes are part of your running application and are therefore of your concern.

Why do we even need runtime code generation?

Runtime class definitions are not meant to take some weight from lazy typers. Runtime code generation sorts out a significant shortcoming of Java’s type system. Before we dive into the specifics, let’s just do a quick recap of what it is that characterizes this type system.

Types in Java are both strong and static. Only mentioning this property can make some programmers spin. But let us skip the ubiquitous “dynamic versus static types” discussion and assume that we generally like strong, static typing. One great thing about such types is their expressiveness. For each variable, we can immediately tell what methods we are allowed to call on its value.
And as long as we do not forcibly typecast a trail to compiling code, static types uncover a lot of programming errors during compilation and before even starting up our application.

This sort of safety is convenient for us. However, it is sometimes equally inconvenient for those gentlemen writing our Java frameworks and libraries. Static typing implies that an application can only call methods on types that it explicitly knows.

But this contradicts the idea of a framework which wants to offer functionality independently of a specific user domain. For your homegrown, company-internal frameworks, a direct dependency to a specific domain model might still be an option.
However, imagine that the Spring framework had to depend on all of its users’ domain types. While this is most certainly logistically impossible, the framework’s dependency graph would contradict the actual purpose of the framework! It is the third-party code that depends on the framework’s functionality. It should not be the other way round.

Java reflection to the rescue

Of course, avoiding such compile-time dependencies is a textbook use-case for Java Reflection API. And as a matter of fact, reflection is better than its reputation.
java-reflection2

It is true that Java Reflection API comes with a perceptible runtime overhead. However, this overhead is mainly called forth by the lookup of a method. Although a method lookup is cached internally, the contract of the Method class requires any instance to be Accessible what makes these instances mutable. This requires any method lookup to return shallow copies of these cached Method objects such that we want to avoid the repeated creation of these copies at least inside loops.

However, once you received an instance representing a Java method, the Java runtime will take care of genuinely optimizing these reflective invocations if you just call the method often enough. This concept is labeled inflation and is incidentally implemented by code generation. In the end, these reflective calls do not normally conduct a performance bottleneck, despite many rumors which are mainly based on observations on outdated Java versions.

Using reflection for interacting with user code from framework code is therefore most certainly a way out. But reflection is not equally attractive when a user application needs to be weaved into a framework. Let us think of a simple use case to make this hassle more visual. Let us assume that we want to implement a very basic, annotation-driven security framework. This framework is governed by one single annotation:

@Retention(RetentionPolicy.RUNTIME)
@interface Secured { 
  String requiredUser();
}

When using this miniature framework, a user can annotate methods with @Secured in order to expect them to only be invokable on condition that the specified user is logged on. But how do we enforce this rule? It is quite trivial to implement a check for a given user by reading the requirement from a method’s annotation and comparing it to some application state that represents the currently logged-in user. And using reflection, it is equally easy to call the corresponding method in case that the right user is indeed logged in. But how do we make this logic accessible to user code outside the framework? Well, we could of course just wrap the invocation inside a framework object that allows the represented method’s invocation by passing an array with the wrapped method’s parameters:

interface SecuredMethod {
  Object invoke(Object… args);
}

POJOpocalypse

This was easy, so we are done here. Or are we? While this approach most certainly works, we ended up with an API that only a mother can love.

First of all, when using this library implementation, a user needs to explicitly add a security check to any method call. As a consequence, the security library bloats deep into the user code and any accidental direct method invocation would undermine its annotated security requirement. This is nothing you would joyfully deploy into your production system. But even worse, choosing this implementation we just spoiled Java’s much-praised type safety. Because of the method’s general signature, we can now call the above SecuredMethod using any arguments without the Java compiler warning us. Instead, we need to later dig through stack traces investigating these nasty runtime exceptions.

So what else is there? Well, since you are reading an article about code generation, you can guess that the dynamic creation of a Java class might offer a way out. While the JVM does not permit any monkey-patching for enhancing a method’s implementation, you can approximate such a language feature by overriding a method in a subclass. Thanks to Java’s dynamic method dispatch, this allows you to inject any framework functionality into user code by creating a subclass at runtime. And conveniently, you can invoke the user’s method by simply calling its super implementation.

With this approach, we can implement the discussed security library by creating an on-demand subclass for any given type. Doing so, we can inject the security check into the user code and only invoke the actual method after we are sure that this is currently legal. This way, we can ship a security library with a single-interface API:

interface SecurityLibrary {
  <T> Class<? extends T> secure(Class<T> instance);
}

Using code generation, we can simply subclass a UserType by some SecuredUserType where methods are overridden and implement a security check. In case that this security check succeeds, the method call is delegated to the super class which contains the actual logic.

We finally arrived at a basic version of a POJO framework! A security library cannot get much more transparent than this. The greatest advantage of the code generation approach is that it fully retains all user types. Think about how much easier this API can make your life.

By not depending on framework types, you can for example write unit tests without mocking out framework code. And if your requirements change, switching out the security library is as easy as replacing annotations on the secured methods. If you have a look around, you notice that many of your applications’ frameworks go down this road.

After all this discussion about types, we surely need some time to process. I know I do.

However, next week, we will continue looking at the Java code generation at runtime and get our hands dirty and generate us some code by looking into different frameworks for this purpose. Stay tuned!

Update! The second part of the series: How my new friend Byte Buddy enables annotation-driven Java runtime code generation is published.


If you want to know more about Java Bytecode, Mastering Java Bytecode at the Core of the JVM report by JRebel product lead Anton Arhipov is a great resource to get started!

DOWNLOAD THE PDF