Play Framework: Java and Scala in one Project and the HTTP Context

9 Aug
2014

For my newest Project I’m using the Play!Framework in Version 2.3.
As I’m just starting out with Scala since a long abstinence, I choose to create a project where I could create controllers in either Java or Scala code.

To do this, I added the line

lazy val root = (project in file(".")).enablePlugins(PlayScala, PlayJava)

to my build.sbt file.

While developing Java Controllers and corresponding views works like a charm, I got an error like

[RuntimeException: There is no HTTP Context available from here.]

when I tried to use the same template also for a Scala Controller.

After some digging around, I found out that the reason for this is that for Java Controllers, a “Context-Object” is created which holds all the relevant stuff for rendering the view ( to be precise a play.mvc.Http.Context is created by the trait play.core.j.JavaAction which then provides everything the view could require as implicits through play.mvc.Http.Context.Implicit )

If you now create a normal Scala Action like this:


object EmailTesting extends Controller {

  def index = Action {
        Ok(views.html.testing.email.index.render())
  }
}

The magic that’s happening for the Java Controllers is missing.. your template tries to access the context/request/session but can’t find it because you would need to add it as implicit parameter which you can’t do if you want to use it from a Java Controller…

So, the trick to make your templates/views work both with Scala and with Java Controllers is to generate the play.mvc.Http.Context explicitly for rendering the view. I created a little helper class to make it easier to use:


object JavaContext {

  import play.mvc.Http
  import play.core.j.JavaHelpers

  def withContext[Status](block: => Status)(implicit header: RequestHeader): Status = {
    try {
      Http.Context.current.set(JavaHelpers.createJavaContext(header))
      block
    }
    finally {
      Http.Context.current.remove()
    }
  }
}

you can apply it then like this (note the requirement for the “implicit requestHeader : RequestHeader“):


object EmailTesting extends Controller {

  def index = Action {
    implicit requestHeader: RequestHeader =>

      JavaContext.withContext {
        Ok(views.html.testing.email.index.render())
      }
  }
}

Now you can use your templates from Java and Scala controllers! You can also use the JavaContext to store objects for usage in your Views without the need to add implicits all over the place.

Feel free to use this code under the Apache 2.0 License.

Update 2017:

For PlayFramework 2.6 you need to slightly adjust the code:

import play.api.mvc.RequestHeader

/**
  * Taken from http://dominikdorn.com/2014/08/play-framework-java-scala-in-one-project-no-http-context-available/
  */
object JavaContext {

  import play.mvc.Http
  import play.core.j.JavaHelpers

  def withContext[Status](block: => Status)(implicit header: RequestHeader): Status = {
    try {
      Http.Context.current.set(JavaHelpers.createJavaContext(header, JavaHelpers.createContextComponents()))
      block
    }
    finally {
      Http.Context.current.remove()
    }
  }
}


Comment Form

top