JRebel Gradle plugin

When should you use this plugin?

To enable JRebel for a project, you need to add the rebel.xml configuration file to it. The rebel.xml configuration file has to be added to the deployed WAR or JAR archive. This will let the JRebel agent know which workspace paths to monitor for class and resource updates.

The purpose of the JRebel Gradle plugin is to generate the rebel.xml file for your project during the Gradle build.

When using a JRebel IDE plugin, it is recommended to generate rebel.xml files using the IDE plugin. If you do so, there is no need to use the JRebel Gradle plugin. Generating rebel.xml using the JRebel Gradle plugin is intended for situations when generation using the IDE plugin is not available or produces inaccurate results.

Refer to application configuration using rebel.xml for details on rebel.xml file format.


Enable the JRebel Gradle plugin

When using Gradle 2.1 or newer, add the following snippet to the top of your build.gradle script:

plugins {
  id "org.zeroturnaround.gradle.jrebel" version "1.1.5"
}

This will provide your Gradle build with a new task called generateRebel. Add this task to your main build flow, executing it before building the archive with the jar or war tasks.

When your project uses the Gradle Java plugin:

jar.dependsOn(generateRebel)

And when your project uses the Gradle War plugin:

war.dependsOn(generateRebel)

In most cases, this is all you need to do. The plugin should be able to read the locations of your classes and resources from Gradle’s project model and put them into your rebel.xml.


Additional configuration

In some cases, out of the box configuration is insufficient. You need to explicitly set some configuration. To get an idea about this, start off by having a look at the rebel.xml that was generated based on the defaults, and figure out where is it going wrong. You can override the default settings or customize the behavior of the JRebel Gradle plugin by adding a rebel {} element into your build.gradle, specifying any of the parameters below:

rebel {
  /*
   * alwaysGenerate - default is false
   *
   * If 'false' - rebel.xml is generated if timestamps of build.gradle and the current rebel.xml file are not equal.
   * If 'true' - rebel.xml will always be generated
   */
  alwaysGenerate = true

  /*
   * showGenerated - default is false
   *
   * If set to true, generated rebel.xml will be printed out in console during the build, so you can immediately see what was generated.
   */
  showGenerated = true

  /*
   * rebelXmlDirectory - default is 'build/classes'
   *
   * Output directory for rebel.xml.
   */
  rebelXmlDirectory = "build/classes"

}

Configuring <classpath>

The <classpath> element in rebel.xml defines which locations are monitored by JRebel for new versions of your classes. If you use Gradle’s Java or War plugin, the plugin will ask for the classes output location from your Gradle project model. In many cases this will be sufficient to make class reloading work (you just have to check that your IDE is also auto-compiling your classes into that same directory). In that case, you can just completely leave out the classpath { .. } block and the defaults will be used.

If for some reason the plugin is not getting it right, or you want to add additional classpath locations to your rebel.xml or explicitly fine-tune excluded or included resources, you can do so by providing classpath { .. } section in your build.gradle DSL:

rebel {
  // (other config)

  classpath {
    resource {
      directory = "build/main/other-classes-dir"
      includes = ["**/*"]
      excludes = ["*.java", "*.properties"]
    }

    // the default element
    resource {}

    resource {
      directory = "build/integration-tests/classes"
    }
  }
}

Each resource {..} element will define one classpath search location in your rebel.xml. The empty resource {} element has a special meaning – this is a placeholder for the default classpath location asked from the Java or War plugin. It can be used to control the order where the default location will be placed in the generated rebel.xml. For example, the above configuration would generate a rebel.xml that instructs JRebel to search for a class from these directories in that same order:

  1. build/main/other-classes-dir
  2. [the default compilation output directory known by your Gradle Java plugin]
  3. build/integration-tests/classes

When you omit the empty resource {} block, the default classpath will be added as the first element into your rebel.xml. Should you want the default classpath to not appear at all, use the omitDefault configuration option:

rebel {
  // (other config)

  classpath {
    // don't add the default classes target directory
    omitDefaultClassesDir = true

    // don't add the default resources directory
    omitDefaultResourcesDir = true

    resource {
      directory = "build/main/other-classes-dir"
      includes = ["**/*"]
      excludes = ["*.java", "*.properties"]
    }
  }

}

Customizing the root path

You have the option to explicitly specify the root path of your workspace. This is useful when the JRebel Gradle plugin incorrectly receives it by default or when you have multiple symlinks/aliases for the same folder (and you want to specify which one to use).

Notice that for default resources, the plugin will check if the default directories prepended by this workspace root path actually exist. When not, they will not be added to rebel.xml. Non-default locations (the ones manually defined in classpath { .. } and web { .. } blocks) are added even when they do not exist at the moment of the plugin execution.

You can add the rootPath configuration option to your build.gradle as all the other configuration options:

rebel {
  rootPath = "/opt/my-project"
}

This is not ideal when the configuration is shared using a SCM and when workspace paths do not match in different environments. In these cases, it is better to provide the configuration option in your personal gradle.properties file that is not added to the SCM:

rebel.rootPath = /opt/my-project

You can also provide it directly on the command line:

gradle build -Prebel.rootPath=/opt/myproject

This option can be used to generate a rebel.xml that contains a placeholder root directory. This way, every user can specify the value for it via a JVM argument when executing their JRebel-enabled JVM:

build.gradle:

rebel {
  rootPath = "\${my-workspace}"
  classpath {
    resource {
      directory = "build/classes/main"
    }
  }
}

Fragment of the generated rebel.xml:

<classpath>
  <dir name="${my-workspace}/build/classes/main">
  </dir>
</classpath>

When running the JVM, every user would add an extra JVM argument: -Dmy-workspace=/opt/my-project.


Configuring <web>

The <web> element is valid for WAR projects and lets you map specific locations of your workspace against specific locations inside your WAR archive.

For example: your WAR contains a folder /WEB-INF/jsps, the contents of which come from your workspace folder src/main/jsps. To have the changes you make to JSPs in your workspace be immediately available in your deployed application, you have to define a mapping in your rebel.xml.

The corresponding mapping is created by the first resource { .. } block in the example below:

rebel {
  // other config ..

  web {
    resource {
      directory = "src/main/jsps"
      target = "/WEB-INF/jsps"
    }

    resource { }

    resource {
      directory = "src/main/WEB-INF-resources"
      target = "/WEB-INF/"
      includes = ["**/*.xml"]
      excludes = ["*.java", "*.groovy", "*.scala"]
    }
  }
}

The empty resource {} block here has similar meaning and properties as the one in classpath {..} configuration block. It can be used to control the placement of the default resource-mapping element. The default resource-mapping maps your WAR’s root to the main webapp directory known by Gradle’s project model. Here you can also use the omitDefault setting to completely exclude the default configuration from the generated rebel.xml:

rebel {
  // other config ..

  web {
    omitDefault = true
    resource {
      directory = "src/main/jsps"
      target = "/WEB-INF/jsps"
    }
  }
}

Once again, omit the web {..} configuration block as a whole if you are satisfied with the defaults.


Configuring <war>

You can also add the element to your rebel.xml by adding the following to your build.gradle. Refer to JRebel manual for details on the meaning of the element.

rebel {
  war {
    path = "build/dist/my-other-webapp.war"
  }
}

IDE configuration

Please note that the Gradle Eclipse plugin does not seem to generate project files that would configure Eclipse to auto-compile your classes into the same folder where Gradle is compiling them. JRebel class reloading relies on your IDE to automatically re-compile your classes, so that JRebel can pick them up.

The compilation output directory of your IDE and the monitored classes directory have to match in order for the class reloading to work. Therefore, make sure that your IDE is compiling classes into the same directory where your Gradle project model and the rebel.xml file are expecting them (build/classes/main by default, as opposed to bin which is the default for Eclipse).