Search code examples
gwtrpcgwt-rpc

GWT RPC scope issue


I'm having a problem saving the result of a RPC. Basically the call is successful but when I try to save it in a variable it seems to go out of scope.

private String userName = "default";

authService.retrieveUserData(new AsyncCallback<UserData>() {
        @Override
        public void onSuccess(UserData result) {
            userName = result.getUserName();
            shell.setError("The userName is " + userName + "!");
        }
        @Override
        public void onFailure(Throwable caught) {
            //I've checked and it is not failing.
        }
    });

shell.getLoginWidget().setUserName(userName);

shell is a Composite that is added to my RootLayoutPanel. It contains a DivElement of which the InnerText is set by shell.setError(String). shell also has a LoginWidget with a SpanElement of which the InnerText is set by shell.getLoginWidget().setUserName(String). userName is obviously a String that is initialized to "default".

The problem is that the shell.setError("The userName is " + userName + "!"); (inside the AsyncCallback) sets the InnerText to whoever is currently logged in. BUT shell.getLoginWidget().setUserName(userName); (outside the AsyncCallback) sets the InnerText to "default".

I have tried so many different things and they all seem to have the same scope problem. What really confuses me is that this example shows almost exactly the same technique for saving the result of the RPC.


Solution

  • GWT RPC methods are asynchronous - their return values are not available immediately. The flow of control for the code you posted is as follows:

    1. Set userName to "default".
    2. Ask the authService for the UserData. This fires off an asynchronous XMLHttpRequest for the `UserData.
    3. Set the userName in the login widget to the current value of userName, which is "default".
    4. Some time later the asynchronous request initiated in step 2 will return at which point the userName variable will be set to the returned value.

    The correct thing to do is to set the user name in the onSuccess method of the AsyncCallback:

    public void onSuccess(UserData result) {
      userName = result.getUserName();
      shell.getLoginWidget().setUserName(userName);
    }