Search code examples
javascriptjavaasynchronousclojurenashorn

Nashorn - Synchronous Java vs Async Javascript impedance mismatch


I have a Java Project using Nashorn to run some javascript code specifically to take advantage of some JS libs.

The problem I'm facing is that my Java application is a synchronous app that receives a HTTP request and respond. However in Javascript is common to have libs that receive callbacks.

So my questions are:

  • How to deal with the impedance mismatch between sync java and async javascript. Is there a way to wait the callback to be called and only after that respond ?
  • How to pass a Java callback to a Javascript function?
  • Or is there a way to block the Javascript code until the callback completes?

A example code is below. The project is actually in Clojure, but I'm typing in java for the sake of the example:

@RequestMapping(value = "/{customerId}", method = RequestMethod.GET, produces="application/json")
@ResponseStatus(value = HttpStatus.OK)
public @ResponseBody Customer getShoppingCart(@PathVariable String customerId) {
    return getById(customerId).toJson();
}

public Customer getById( String id ) {
     nashorn.invokeFunction("javascriptFunction", expectedCallbackFunction)
}

Thanks!


Solution

  • For converting asynchronous to synchronous API in Clojure you can use promise:

    Javascript code:

    function getCustomer(id, clojureCallback) {
      var jsCallback = function(result) { clojureCallback.invoke(result); };
      callHttp("http://api/customer/" + id, jsCallback);
    }
    

    Clojure code:

    (def js-engine ...)
    
    (defn get-customer-by-id [id]
      (let [customer-promise (promise)]
        (.invokeFunction js-engine "getCustomer" (object-array [id customer-promise]))
        @customer-promise))
    

    Promise result can be submitted by calling deliver function or (as Clojure promise object implements IFn) by calling it with the result (clojureCallback.invoke(result) in Javascript code). Then the result can be derefed (@ is a reader macro for deref).