Custom JRebel plugins – why and when?

JRebel’s purpose is to reload classes. When you change something in your code, the changes get picked up automatically and are instantly reflected in your application. However, sometimes just reloading the classes falls short of what really needs to be done to fully update the application -– without restarting it.

This is because the objects in the memory remain the same – they are not recreated. For most scenarios, this is the desirable outcome (avoiding the system re-initialization penalty is what JRebel is all about). Still, when you alter something in your code that has to do with the way the application initializes (and would results in memory objects being in a different state after a normal application restart), those changes will of course not be reflected in your application state. This is because the initialization code is not run again.

This is when creating a custom JRebel plugin could help you. With a plugin, you can monitor the reloading of resources, and execute any desired custom code as necessary in reaction. You will use a JRebel integration plugin to state: “After this reloading event occurs, go through these initialization steps to update my application state.”

A typical scenario would be this. Your application uses a 3rd party framework. When the application starts, the framework initializes by loading its configuration from various resources (external XML files, Java annotations, etc.). Some of these resources change as you continue application development (e.g. adding a new bean in your Spring applicationContext.xml and wiring it with others).

Without an integration plugin telling what to do, these changes will not reflect in your application’s running state without a restart. However, using an integration plugin, you could state: “When you see that something has changed in applicationContext.xml, perform a full reload of all my beans!”.

This scenario is common for all applications using some framework. Therefore, the plugins should be created per framework and not per application!

Implementing a custom plugin

A JRebel plugin is a small JAR file, containing at minimum a class that implements the Plugin interface of the JRebel SDK and a special manifest entry telling JRebel the name of that class.

It is highly recommended to start creating any plugin project using this template.

The key API in plugin development is JRebel SDK. This provides a means to communicate with JRebel private APIs. Your plugin code can also make use of anything else available on the JVM you are running in. For example, if you are developing a plugin for the Struts2 framework, you can safely import and use classes from Struts2 in your plugin (without providing them yourself).This plugin would be activated only when Struts2 is available in the JVM.

The Plugin interface you need to implement looks like this:

public interface Plugin {
  void preinit();
  boolean checkDependencies(ClassLoader cl, ClassResourceSource crs);
  String getId();
  String getName();
  String getDescription();
  String getAuthor();
  String getWebsite();
  String getSupportedVersions();
  String getTestedVersions();

The most important methods here are:

  • preinit() – The main method. Use this to set up the CBPs, listeners and anything else.
  • checkDependencies(ClassLoader cl, ClassResourceSource crs) – Checks whether this plugin should be loaded for this particular class loader. The safest way to do this is by checking whether a framework class that you rely on is available in that class loader:
 public boolean checkDependencies(ClassLoader classLoader,
                        ClassResourceSource classResourceSource)
    return classResourceSource.getClassResource(
      "org.zeroturnaround.jrebel.flagDemo.AbstractCanvas") != null;

Refer to the example plugin contents for an example. Check out the JRebel SDK API for additional details.

Demo application

To demonstrate working with JRebel plugins, we have created a simple Swing desktop application. Download the source and look for the app in package org.zeroturnaround.jrebel.flagDemo. This application draws three Image objects on a Canvas object, which is in turn placed inside a JFrame object and displayed. Here is the end result:

The class hierarchy of this application looks like this:

A typical situation for writing a JRebel plugin is when you want to provide JRebel integration for a framework maintained by a third party. Let’s imagine that the AbstractCanvas class is our third-party framework, one that we want to provide better JRebel integration for. We have the restriction that we cannot directly edit its code. If we had complete control over the AbstractCanvas code, we could of course simply add our modifications directly into it.

Let’s also imagine that FlagsCanvas is our application in development. Our goal is to build a plugin that provides better JRebel support for reloading any client code of the AbstractCanvas framework (while modifying the FlagsCanvas class).

Begin by downloading the demo app and making yourself familiar with it. To run it with JRebel, you need to edit the file and make jrebel.jar.path point to jrebel.jar on your local machine.

There are three Ant targets that execute the application:

  • ant run – Runs the app without JRebel.
  • ant run-with-jrebel – Runs the app with JRebel, but without the JRebel plugin.
  • ant run-with-jrebel-and-plugin – Runs the app with JRebel and with our ready-made JRebel integration plugin from lib/jr-plugin-template.jar.

The code that controls where the flags get painted to is located in these two methods of

   private void init() {
        estoniaX = 65;
        estoniaY = 50;
        switzerlandX = 400;
        switzerlandY = 50;

    public void paint(Graphics g) {
        System.out.println("Painting the canvas...");

        g.drawImage(switzerlandImg, switzerlandX, switzerlandY, this);
        g.drawImage(estoniaImg, estoniaX, estoniaY, this);
        g.drawImage(iranImg, 650, 50, this);

Try executing the app with JRebel but without the plugin at first. The paint() method gets called by Swing when some event occurs with the frame (gaining or losing focus, etc.). Try modifying the coordinates of the flags and see what happens. Something obviously needs to rebuild your .class files after editing them. It is best to configure your IDE to do this automatically whenever you save your source files. When you re-focus to the demo application, paint() gets called and the Iranian flag should move, provided you edited its coordinates in the Java code.

The other flags demonstrate no reaction. This is because their locations are controlled by the instance variables of the FlagsCanvas class. These get initialized by the init() method – when a new instance of the class is created. Although you might have changed their values in the init() method, the values in the memory remain the same. This is because nobody is calling this method after the instance has been created.

Step 1 – Class bytecode processors (CBPs)

The class reloading works, but this does not do the entire job as the in-memory state of the application does not get updated. Notice that all that we would need to do to fix this is to make an additional call to init() whenever we call paint(). The JRebel SDK provides suitable tools for the job. Whenever you need to modify the behavior of 3rd party code before it runs in your JVM, you can use the class bytecode processors (CBPs), extending the JavassistClassBytecodeProcessor class.

When set up properly, the CBPs intercept the initial class loading in the JVM and load the 3rd party classes with our modifications already in place. Here is what a CBP looks like:

public class ReloadAbstractCanvasStateCBP extends JavassistClassBytecodeProcessor {

  public void process(ClassPool cp, ClassLoader cl, CtClass ctClass) throws Exception {

    LoggerFactory.getInstance().echo("Patching the AbstractCanvas class...");
    try {
      CtMethod paintMethod = ctClass.getDeclaredMethod("repaint");

    catch (NotFoundException e) {

This CBP inserts an extra statement into the top of the repaint() method of the AbstractCanvas class. Thereby it transforms the control flow to a public static method implemented in our plugin. The current instance is passed as an argument ($0 stands for this in Javassist code-strings). The reinitialize() method implemented in our plugin can now make arbitrary customizations and then hand the control back to AbstractCanvas#paint(). Currently it calls the init() method with Reflection API.

Notice that here it would actually make sense to call the init() method right away:


This approach might be reasonable when your customization is trivial. However, as things get any more complicated, simply forwarding the call might be more comfortable than maintaining large chunks of code inside Java strings.

The CBP also has to be registered in the plugin class for things to work:

public class PluginTemplate implements Plugin {

  public void preinit() {

    // Register the CBP
    Integration i = IntegrationFactory.getInstance();
    ClassLoader cl = PluginTemplate.class.getClassLoader();

      new ReloadAbstractCanvasStateCBP()

    // ..

  // ..

Integration is the class through which CBPs can be set up. The instance for it is acquired through IntegrationFactory.

Caution: be very careful with referencing the classes you are about to patch in the CBP code itself (or any other code that is called by the CBP). Remember that the CBP is all about intercepting a class before it gets loaded. If your CBP tries to do something with the very same class, JVM would have to load it to do this. And this would create a cyclic dependency, blowing the thing!

Step 2 – Class reload listeners

If you are prepared to spend some time, I recommend doing this:

  1. Take the demo application and the plugin template.
  2. Reduce the plugin to what we have done so far (basically commenting out call of registerListener() method in preinit() method).
  3. Rebuild the plugin JAR.
  4. Replace the old plugin with the new one in the demo application’s ./lib directory.

If you take the time to do this through you’ll soon discover that our AbstractCanvas-to-JRebel integration has a small flaw. If you change the coordinates of flags and recompile the code, repainting of the canvas happens when Swing wants it to be repainted, not when you actually changed anything. Try splitting your desktop between Eclipse and the application frame and editing the code in Eclipse while you application is inactive. Whatever you do with the code, Swing will not repaint it until you bring focus back to the demo app. This is obviously not a massive problem. Swing always wants to repaint things when you actually do something with the app. We can try to fix that – at least for an educational purpose.

This is the ideal moment to introduce reload listeners. The JRebel SDK provides an API to register listeners that get notified when JRebel reloads something. By creating an implementor of the ClassEventListener interface and registering it through Reloader, we can implement custom reactions to class reload events. This is exactly what we will do:

public void preinit() {
  // ..

  private void registerListener() {
      // Set up the reload listener
      new ClassEventListener() {
      public void onClassEvent(int eventType, Class klass) {
        try {
          String cn = "org.zeroturnaround.jrebel.flagDemo.AbstractCanvas";
          Class abstractCanvasClass = Class.forName(cn);
          // Check if it is child of AbstractCanvas
          if (abstractCanvasClass.isAssignableFrom(klass)) {
            LoggerFactory.getInstance().echo("Repainted the canvas");
        catch (Exception e) {
      // ..


This chunk of code achieves the following: when we see that a class has been reloaded, and when it happens to be a subclass of AbstractCanvas, we force repainting the canvas (without waiting for Swing). The repainting itself is implemented in method DemoAppConfigReloader.repaint().

Now our AbsractCanvas JRebel integration is starting to look much better. Our plugin has added the following functionality:

  • When any subclass of AbstractCanvas gets reloaded, we will repaint the canvas.
  • At any time we repaint, we will also call the init() method to update the application state.

We also demonstrated some cornerstones of the JRebel SDK API:

  • Class bytecode processors (CBPs)
  • Class reload listeners

Basic tasks can already be accomplished with this knowledge. You are of course encouraged to browse the rest of the API to familiarize yourself with the rest of its possibilities – all in order to create better JRebel integration plugins!

Enabling a custom plugin

While playing around with the demo application, we used the ready-made Ant targets to enable the plugin. Still, it would be nice to know how to enable your plugins.

The Ant target run-with-jrebel-and-plugin passes some additional JVM arguments to java through the command line. The full command to do the same thing directly from command line would be:

java -classpath ./bin -agentpath:/path/to/libjrebel64.dylib -Drebel.plugins=./lib/jr-plugin-template.jar -Drebel.jr-plugin-template=true org.zeroturnaround.jrebel.flagDemo.SDKDemoApp

Everything else is as usual, except that two new parameters have appeared:

  • -Drebel.plugins=/path/to/plugin1,/path/to/plugin2 – a comma-separated list of paths to plugin JAR files that you want JRebel to load .
  • – enables the specified plugin. The name has to match with whatever is returned by the getId() method of your main plugin class.

Example: Liferay plugin

The JRebel plugin for Liferay is open sourced and can be used as an example.

The plugin includes monitoring the resource files and re-running parts of the framework code when they change to update the metadata. This functionality can be found in org.zeroturnaround.jrebel.liferay.LiferayReloader.

A good example of making your plugin work with different versions of a framework is contained in org.zeroturnaround.jrebel.liferay.cbp.PortletLocalServiceImplCBP.