Jenkins : AJAX with JavaScript proxy

This applies to Jenkins 1.402 and later

Introduction

In Jenkins, you can export arbitrary server-side objects to JavaScript via proxy. From inside JavaScript, you can invoke methods on the proxy object, which sends an HTTP request that eventually gets translated to the method call of the exported object. The return value from this Java method is sent back as an HTTP response, and JavaScript can receive this value through a callback method.

As such, this is an useful building block for AJAX.

How-To

To expose a method of a Java class to JavaScript proxy, annotate the method with @JavaScriptMethod. For security reasons, only public methods on public classes annotated with this annotation are invokable from browsers:

import org.kohsuke.stapler.bind.JavaScriptMethod;

public class Foo {
    @JavaScriptMethod
    public int add(int x, int y) {
        return x+y;
    }
}

Then from Jelly scripts, use <st:bind> tag to export a Java object into a proxy. The "value" attribute evaluates to a server-side Java object to be exported, and the tag produces a JavaScript expression that creates a proxy.

In the example below, we are pretending that the JEXL expression evaluates to some instance of Foo.

<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler">
  ...

  <div id="msg" />
  <script>
    var foo = <st:bind value="${some.expression.thatEvaluatesTo().fooInstance}"/>

    foo.add(1,5, function(t) {
      document.getElementById('msg').innerHTML = t.responseObject();
    })
  </script>
  ...
</j:jelly>

Invoking method

As you can see above, one can invoke methods on the proxy created by the <bind> tag. The JavaScript method takes the arguments that the Java method takes, then it can optionally take a function as an additional parameter, which is used as a callback method when the return value is available. The callback method receives an Ajax.Response object.

If the Java method returns an object value (such as int, String, Collection, Object[], JSONObject, etc.), you can use the responseObject() method to evaluate the response into a JavaScript object and use it. If the Java method renders more complex HTTP response (for example by writing directly to StaplerResponse or returning an HttpResponse), JavaScript can use other Ajax.Response methods to access the full HTTP response.

The method call uses XmlHttpRequest underneath, and it gets eventually routed to the corresponding method call on the exact instance that was exported.

Tips

Parameters of the server Java method

The Java method can define arbitrary number of parameters for JavaScript. Each parameter is converted from JSON to Java via StaplerRequest.bindJSON, so aside from primitive Java data types and typeless JSONObject/JSONArray, you can use Stapler databinding to accept typed structured data.

After defining the parameters from JavaScript, you can additionally define parameters that are injectable by Stapler, such as StaplerRequest/StaplerResponse.

Exporting null

If the value attribute of a <bind> tag evaluates to null, then the corresponding JavaScript proxy will be null.