I want to recover my promise and return delegate.call(context) from it, but i can only return SimpleResult.
public class Authenticate extends Action<Authentication> {
@Override
public Promise<SimpleResult> call(final Context context) throws Throwable {
WSRequestHolder holder = WS.url(...);
final Promise<Response> promise = holder.get();
Promise<SimpleResult> result = promise.flatMap(new Function<Response, Promise<SimpleResult>>() {
@Override
public Promise<SimpleResult> apply(Response response) throws Throwable {
JsonNode user = response.asJson().path("response");
context.args.put("user", user);
return delegate.call(context);
}
}).recover(new Function<Throwable, SimpleResult>() {
@Override
public SimpleResult apply(Throwable e) {
/* cant return delegate.call(context); from here */
return redirect(routes.Application.index());
}
});
return result;
}
}
Maybe there are other standard and better ways to store userinfo before method calls?
The solution you posted is not a good solution, you should never, ever use Await.result when doing asynchronous programming, you risk causing deadlocks and massive performance issues.
We need to add a recoverWith
method to the Play promise API, but until that happens, you can do this (using JDK8 syntax for brevity):
public class Authenticate extends Action<Authentication> {
public Promise<SimpleResult> call(final Context context) throws Throwable {
Promise<SimpleResult> result = WS.url(...).get();
Promise<SimpleResult> result = promise.flatMap( response -> {
JsonNode user = response.asJson().path("response");
context.args.put("user", user);
return delegate.call(context);
}).map(Promise::pure).recover( e -> {
return delegate.call(ontext)(routes.Application.index());
}).flatMap(a -> a);
return result;
}
}
Basically, the above unflattens the Promise<SimpleResult>
into Promise<Promise<SimpleResult>>
by mapping with Promise::pure
, then you can recover returning Promise<SimpleResult>
, then you it flattens the promise of a promise by flatMapping with the identity function.