Better Java Hot Code Replace at no cost
- Processes, standards and quality
Why do we want another JRebel?
A standard JVM Hot Code Replace (HCR) doesn’t allow for too much. Actually, it is hardly usable. The only thing that could be done is changing a method body. You cannot change a method signature, you cannot add fields, constants etc.
Some containers / application servers offer kind of “hot redeploy” feature, however when it comes to replacing changed Java code, usually, it’s still necessary to restart the whole application, so it doesn’t help much in development. Sure, there are commercial solutions available but as users of the Java software development ecosystem we are used to free and opensource solutions. For a long time there was no real alternative. However, over the last few years things started to change and now we have a set of quite nice free tools which allow to reduce necessity of completely rebuilding and restarting our applications during development.
When it comes to pure Hot Code Replace, DCEVM (http://dcevm.github.io/) seems to be one of the most interesting tools. It solves most of the limitations of a standard JVM’s HCR. The significant difference with JRebel-like solutions is that it doesn’t work by dynamically modifying classes loaded by JVM. Instead, it’s actually a modified JVM, which could handle more of dynamic code change types.
Therefore, the installation is a matter of replacing a standard JVM with DCEVM.
After starting the installer you simply choose which of current JVM installations you want to replace:
As on output, you can notice that only jvm.dll-s were replaced with new ones.
It’s really easy,painless and causes that every program running on JVM is able to do better HCR out of the box.
DCEVM is precompiled for both java 1.7 and 1.8, however at the time of writing this post, the “full” version is available only for JVM 1.7.
The authors state that the full version can do more advanced operations, such as modifying class hierarchy (e.g. removing a superclass), however, as I’ll describe it further in this post, it actually seems not to work.
Any type of further described changes could be done simply by attaching a debugger to a JVM and by using standard HCR feature present in most IDE-s.
You just run an application with remote debug parameters:
and you can attach a debugger from IDE to port XYZ and replace the changed code after compilation.
What kinds of HCR are possible?
- changing body of a method (and static method as well) – actually, it doesn’t make any difference from a standard JVM
- changing name of method
- changing signature of method
- adding and removing methods
- adding, removing or changing constants
- adding, removing or changing fields
- adding, removing annotations from classes and methods
- changing new inner classes
- introducing/modifying lambdas in 1.8 code (sometimes randomly fails)
What’s still the problem?
- changing class hierarchy (although the documentation states that this should be possible for “full” version 1.7)
- introducing new high-level, inner and anonymous classes
We successfully tested DCEVM while developing a large Swing-based desktop application which needs a good few seconds to start.
DCEVM + HotSwapAgent
HCR is often not only a matter of pure classes replacement. Sometimes some work should be done on a framework level (just to mention such operations as refreshing spring context after introducing new annotated methods or changing, for example, ORM annotations on fields etc.). Also application servers, such as JBoss, don’t allow simple class replacing. And here comes another project accompanying DCEVM: http://hotswapagent.org/.
It has quite many plugins for different popular Java frameworks:
Quite nice list. However, we haven’t tested all of them in development.
HotSwapAgent basically allows for everything that DCEVM does. Furthermore, it adds on-code-changed hooks related to various frameworks.
It works as an agent and running it is simply a matter of adding:
Some additional aspects of hot swap configuration could be given in a file named “hotswap-agent.properties” which should be placed in a resources directory inside your application.
HotSwapAgent proved to work for us while developing an application with the use of:
- EJB2.1 (yes, that’s a legacy pain, especially when a build contains XDoclet code, which takes ages to generate; that’s when we really want such tools)
- EJB3 – it had some problems with injection of beans, however successfully handled all other bean code changes
- Spring DI – it allows to add/modify beans in DI container
- Spring MVC – adds/modifies controller mappings
- hibernate – modifies entities mappings at runtime.
Spring Loaded project (https://github.com/spring-projects/spring-loaded) works internally probably in a similar way as JRebel does – it instrumentates loaded clases in a way that they could be modified in runtime.
We haven’t tested that in projects likewise things mentioned above, however by running some small test projects, it seems to be quite similar to DCEVM+HotSwapAgent, at a first glance. As authors mentioned, Spring Loaded is actually the engine of Grails2 so it should be even more stable. Still, it lacks the functionality of adding new classes.
This article only briefly lists the current free solutions of JVM code reloading problem. I do not think that they are perfect, for sure they are not. However,you don’t have to pay to have better Hot Swap with quite advanced functionalities. Despite some missing features, such as adding new classes, which is painful, you can still benefit from not having to restart your application in most cases.
All of that seems to be rather unimportant in projects consisting of small services, which could be easily and fast restarted. However, it is very useful in developing large monolythic projects (especially desktop) with long startup time. You can save lots of time wasted on unproductive waiting for things to start.
The first two solutions proved to save a lot of my development time in one of my last projects.
What is your experience with free Hot Code Replace / Hot Swap tools in Java?