2
votes

Hello I'm trying to write async code for MongoDB async driver (3.0) http://mongodb.github.io/mongo-java-driver/3.0/driver-async/ with Play Framework 2.4 (Java) in controller with Async result https://www.playframework.com/documentation/2.3.x/JavaAsync , when I'm testing it the Promise results is outside the Async call to MongoDB so sometimes I have empty json in the response, please can you help me with it ?

public F.Promise<Result> list() {
    final List<Document> accounts = new ArrayList<Document>();
    F.Promise<List<Document>> promiseOfAccounts = F.Promise.promise(
        new F.Function0<List<Document>>() {
            public List<Document> apply() {
                accountRepository.getCollection().find().into(accounts,
                        new SingleResultCallback<List<Document>>() {
                            @Override
                            public void onResult(final List<Document> result, final Throwable t) {
                            }
                        });
                return accounts;
            }
        }
    );
    return promiseOfAccounts.map(
        new F.Function<List<Document>, Result>() {
            public Result apply(List<Document> i) {
                return ok(i);
            }
        }
    );
}
1

1 Answers

0
votes

When you return accounts, the SigleResultCallback closure hasn't been executed. That results in the list being empty when the it's serialized in the ok(i) expression. To make it work, you have to resolve the promise yourself inside the SingleResultCallback. Remember Play Promises sit over scala Futures and scala Promises (which are different from Play F.Promises). This is how you'd do it:

Promise<List<Document>> accountsPromise = Promise$.MODULE$.apply();
ArrayList<Document> accounts = new ArrayList<Document>();
accountRepository.getCollection().find().into(accounts,
        new SingleResultCallback<List<Document>>() {
            @Override
            public void onResult(final List<Document> result, final Throwable t) {
                accountsPromise.success(result);
            }
        });
promiseOfAccounts=F.Promise.wrap(accountsPromise.future());
return promiseOfAccounts.map(
        new F.Function<List<Document>, Result>() {
            public Result apply(List<Document> i) {
                return ok(i);
            }
        }
);

the moment you call the success method of the scala Promise resolves, and so the value of the future becomes available, but you return the play F.Promise before that happens, the awesomeness of the reactive programming.