Играть! Framework. Может ли мой шаблон просмотра быть локализованным при рендеринге его как AsyncResult?

Недавно я начал использовать Play! framework (v2.0.4) для написания веб-приложения Java. В большинстве моих контроллеров я следую парадигме приостановления HTTP-запроса до тех пор, пока не будет выполнено обещание ответа веб-службы. Как только обещание выполнено, я возвращаю AsyncResult. Вот как выглядит большинство моих действий (с опущенным кодом):

public static Result myActionMethod() {

    Promise<MyWSResponse> wsResponse;
    // Perform a web service call that will return the promise of a MyWSResponse...

    return async(wsResponse.map(new Function<MyWSResponse, Result>() {
        @Override
        public Result apply(MyWSResponse response) {

            // Validate response...
            return ok(myScalaViewTemplate.render(response.data()));
        }
    }));
}

Теперь я пытаюсь интернационализировать свое приложение, но при попытке визуализации шаблона с помощью метода async появляется следующая ошибка:

[error] play - Waiting for a promise, but got an error: There is no HTTP Context available from here.
java.lang.RuntimeException: There is no HTTP Context available from here.
    at play.mvc.Http$Context.current(Http.java:27) ~[play_2.9.1.jar:2.0.4]
    at play.mvc.Http$Context$Implicit.lang(Http.java:124) ~[play_2.9.1.jar:2.0.4]
    at play.i18n.Messages.get(Messages.java:38) ~[play_2.9.1.jar:2.0.4]
    at views.html.myScalaViewTemplate$.apply(myScalaViewTemplate.template.scala:40) ~[classes/:na]
    at views.html.myScalaViewTemplate$.render(myScalaViewTemplate.template.scala:87) ~[classes/:na]
    at views.html.myScalaViewTemplate.render(myScalaViewTemplate.template.scala) ~[classes/:na]

Вкратце, где у меня есть поиск пакетов сообщений в моем шаблоне просмотра, некоторые Play! код пытается получить доступ к исходному HTTP-запросу и получить заголовок accept-languages, чтобы узнать, какой пакет сообщений использовать. Но кажется, что HTTP-запрос недоступен из метода async.

Я вижу пару (неудовлетворительных) способов обойти это:

  • Вернитесь к парадигме "один поток для каждого запроса" и блокируйте потоки, ожидающие ответов.
  • Определите, какой язык использовать на уровне контроллера, и укажите этот выбор в мой шаблон.

Я также подозреваю, что это может быть не проблема в багажнике. Я знаю, что в 2.0.4 аналогичная проблема связана с тем, что не удалось получить доступ или изменить объект Session, который недавно был исправлен. Тем не менее я застрял на 2.0.4 на данный момент, так есть лучший способ решить эту проблему?

Ответ 1

Собираюсь ответить на мой собственный вопрос здесь. Мой коллега нашел то, что было в конечном счете простым решением:

public static Result myActionMethod() {

    final Context ctx = ctx(); // (1)
    Promise<MyWSResponse> wsResponse;
    // Perform a web service call that will return the promise of a MyWSResponse...

    return async(wsResponse.map(new Function<MyWSResponse, Result>() {
        @Override
        public Result apply(MyWSResponse response) {

            Context.current.set(ctx); // (2)

            // Validate response...
            return ok(myScalaViewTemplate.render(response.data()));
        }
    }));
}
  • Получить ссылку на контекст HTTP в начале действия
  • Восстановить его в ThreadLocal, когда вы находитесь в блоке async