如何在GWT中将Java回调传递给返回Promise的JSNI方法?
Hey there! Since you're stuck with GWT 2.7 and can't leverage JsInterop, I totally get how tricky it is to handle Promises returned from JSNI methods called from Java. I’ve dealt with this exact scenario before, so let’s break down a practical approach that works:
1. First, Define a Java Callback Interface
GWT 2.7’s Java code can’t natively understand Promise objects, so we need a way to bridge the Promise’s then/catch callbacks to Java. Start by creating a simple callback interface that your JSNI code can invoke:
public interface PromiseCallback<T> { void onSuccess(T result); void onFailure(Throwable error); }
This interface will let us pass success/failure logic from Java into the JSNI layer.
2. Wrap the Promise in JSNI
Next, write a JSNI method that calls your JavaScript function (the one returning a Promise), then hooks up the Promise’s handlers to trigger your Java callback. Here’s an example:
public native void callJsPromiseMethod(PromiseCallback<String> callback) /*-{ // Replace this with your actual JS function that returns a Promise const jsPromise = $wnd.yourJsFunctionThatReturnsPromise(); jsPromise.then(function(successResult) { // Invoke the Java callback's onSuccess method callback.@com.yourpackage.YourClass.PromiseCallback::onSuccess(Ljava/lang/String;)(successResult); }).catch(function(error) { // Convert JS error to a Java Throwable for error handling const javaError = @java.lang.RuntimeException::new(Ljava/lang/String;)(error.message || error.toString()); callback.@com.yourpackage.YourClass.PromiseCallback::onFailure(Ljava/lang/Throwable;)(javaError); }); }-*/;
Make sure to replace com.yourpackage.YourClass with your actual package and class name, and $wnd.yourJsFunctionThatReturnsPromise() with the correct reference to your JavaScript method.
3. Handle Complex Return Types (If Needed)
If your Promise returns a complex JavaScript object instead of a primitive/string, you’ll need to map it to a Java class. First create a simple Java class to hold the data:
public class JsUserData { private String username; private int userAge; // Empty constructor required for JSNI to instantiate public JsUserData() {} // Getters and setters public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public int getUserAge() { return userAge; } public void setUserAge(int userAge) { this.userAge = userAge; } }
Then update your JSNI method to convert the JS object to this Java class:
public native void fetchUserData(PromiseCallback<JsUserData> callback) /*-{ $wnd.fetchUserPromise().then(function(jsUser) { // Create a new instance of your Java data class const javaUser = @com.yourpackage.JsUserData::new()(); // Map JS object properties to Java fields javaUser.@com.yourpackage.JsUserData::setUsername(Ljava/lang/String;)(jsUser.username); javaUser.@com.yourpackage.JsUserData::setUserAge(I)(jsUser.age); // Pass the Java object to the success callback callback.@com.yourpackage.PromiseCallback::onSuccess(Ljava/lang/Object;)(javaUser); }).catch(function(error) { const javaError = @java.lang.RuntimeException::new(Ljava/lang/String;)(error.message); callback.@com.yourpackage.PromiseCallback::onFailure(Ljava/lang/Throwable;)(javaError); }); }-*/;
4. Use the Callback in Java
Now you can call your JSNI method from Java and handle the Promise results with your callback:
callJsPromiseMethod(new PromiseCallback<String>() { @Override public void onSuccess(String result) { // Handle successful Promise resolution GWT.log("Promise resolved! Result: " + result); } @Override public void onFailure(Throwable error) { // Handle Promise rejection GWT.log("Promise rejected with error: " + error.getMessage(), error); } });
Key Notes to Remember
- Reference JS Functions Correctly: Ensure your JavaScript method is accessible via
$wnd(the global window object) in JSNI, otherwise GWT won’t find it. - Async Context: Remember that Promise callbacks run asynchronously in GWT’s event loop—don’t expect immediate results, and avoid blocking the main thread.
- Type Conversion: When passing data between JS and Java, make sure to match types correctly (e.g., JS
numbermaps to Javaint/double, JSbooleanto Javaboolean). - Error Handling: Always wrap JS errors in a Java
Throwableso you can properly log and handle them in your Java code.
内容的提问来源于stack exchange,提问作者DevOne

