Community contributed extensions

Scala support

The 1.1 release of play will include support for the Scala programming language. Thanks to the flexibility of the play framework architecture, the Scala support is provided with a simple module. You just need to enable the scala module in the conf/application.conf file.

module.scala=${play.path}/modules/scala

Then you can write all or parts of your play application using scala. You can of course mix it with Java.

We are in very very active development on this stuff. You can try it for now as an experimental feature. Don’t expect to write a complete play application in Scala right now.

For a quick overview of the scala support, you can watch this Scala screencast

Create a new application, with Scala support

You can automatically create a scala ready application, by using the --with option of the play new command. Just try:

play new myApp --with scala

The play application will be created as usual, but if you look at the controllers package, the Application.java file is now replaced by a Application.scala file:

package controllers
 
import play._
import play.mvc._
 
object Application extends Controller {
  def index = render()
}

It is very close to the Java version of the default Application controller.

Now just run the application as usual using play run and it will display the standard welcome page. Now just edit the Application.scala file to replace the render() call:

def index = "Hello scala!"

Refresh the page, and see the magic.

if you prefer a more explicit style you can use renderHtml method to directly write to the response object

As always, if you make a mistake, play will just show you the error in a perfect way; (it’s just more difficult now to forget the trailing semicolon)

Return type inference

As shown above, you can directly use the inferred return type to send the action result. For example using a String:

def index = "<h1>Hello world</h1>"

And you can even use the built-in XML support to write XHTML in a literal way:

def index = <h1>Hello world</h1>

If the return type looks like a binary stream, play will automatically use renderBinary(). So generating a captcha image using the built-in Captcha helper can be written as:

def index = Images.captcha

Action parameters, and scala default arguments

You can declare some action parameter the same way you do it in Java:

def index(name: String) = <h1>Hello {name}</h1>

To big plus of scala is the ability to define some default values to these parameters:

def index(name: String = "Guest") = <h1>Hello {name}</h1>

This way if the name HTTP parameter is missing, play will use the default argument value.

Controller composition using traits

A controller can use several traits to combine several interceptor.

Let’s define a Secure trait:

package controllers
 
import play._
import play.mvc._ 
 
trait Secure {
  self: Controller =>
  @Before
  def check {
    session("user") match {
      name: String => info("Logged as %s", name)
      _ => Security.login
    }
  }
}

And you can them use it in the Application controller:

package controllers
 
object Application extends Controller with Secure {
  def index = "Hello world"
}

How to define and access Models

Models can be defined not only in java but in scala as well.

Scala Models have the following characteristics:

here is an example:

import play.db.jpa._
import play.data.Validators._

@Entity
class User(
  //fields

  @Email
  @Required
  var email: String,

  @Required
  var password: String,
  
  var fullname: String

) extends Model {
    //instance methods
    var isAdmin = false
    override def toString = email
}
object User extends QueryOn[User] {
//placeholder for extra finder methods (if any) 
}

Notice the two import statements. Due to changes in scala 2.8 rc2, the previous versions (ie import play.data.validations._ and import javax.persistence._) are no longer working

Running queries against Models

The API is really similar to the java one so, for example to count the number of users, you can just call count on the User class (assuming you defined the appropriate companion object):

User.count

or if you want to run a complex find query with bindings, that would look something like this:

Post.find("select distinct p.id from Post p join p.tags as t where t.name in (:tags) group by p.id having count(t.id) = :size", Map("tags" -> tags.toArray, "size" -> tags.size)).fetch

Interoperability with Java Models

Due to differences in how static methods are handled in Scala and Java, we needed to introduce a few workarounds to make the Scala API look nice. Unfortunately, the workarounds meant that Java models do not work absolutely seamlessly from scala controllers/jobs (ie. calls like JPost.findAll() or jpost.save() will fail). Not all is lost though, with a little effort you can convert your Java models into Scala ones.

How to query Java Models

import play.db.jpa.asScala
import models._
asScala[JUser].findAll
asScala[JPost].find("select distinct p.id from Post p join p.tags as t where t.name in (:tags) group by p.id having count(t.id) = :size", Map("tags" -> tags.toArray, "size" -> tags.size)).fetch

How to manage an instance

import play.db.jpa.asScala
import models._
//this implicit conversion is imported in most packages by default
import play.db.jpa.asScala.enrichJavaModel 
val u  = new JUser("[email protected]","secret","my name").asScala[JUser].save()

or

val u = new JUser("[email protected]","secret","my name")
u.asScala.save()

Cache API

using the scala version of the cache api one can do stuff like this

Cache.get[People]("person-key-25") match {case Some(p) => println (p.name); case None => println("boo")}

Testing

ScalaTest support is integrated into Play, so one can easily write unit and functional tests using ScalaTest, for example:

class SpecStyle extends UnitFlatSpec with ShouldMatchers {
"Creating a user" should "be succesfull" in {
  val user = new User("[email protected]", "secret", "Bob").save()
  bob = User.find("byEmail", "[email protected]").first
  bob should not be (null)
  bob.fullname should be ("Bob")
 }
}
class RenderMethodsTest extends FunctionalTestCase with Matchers{
  val response = GET("/application/json1")
  response shouldBeOk()
  response contentTypeShouldBe("application/json")
  response charsetShouldBe("utf-8")
  response contentShouldBe("{'name':'guillaume'}")
}

Full API

Scala console

play-scala comes with a console which can be really useful to try out various layers of your application.

here is an example session:

kola:yabe-with-scala phausel$ play scala:console
~        _            _ 
~  _ __ | | __ _ _  _| |
~ | '_ \| |/ _' | || |_|
~ |  __/|_|\____|\__ (_)
~ |_|            |__/   
~
~ play! 1.1-unstable-localbuild, http://www.playframework.org
~
15:43:17,805 INFO  ~ Starting /Users/phausel/workspace/play-scala/samples-and-tests/yabe-with-scala
15:43:17,809 INFO  ~ Module secure is available (/opt/local/lib/play-1.1-unstable-r777/modules/secure)
15:43:17,809 INFO  ~ Module scala is available (/Users/phausel/workspace/play-scala/samples-and-tests/yabe-with-scala/../..)
15:43:17,810 INFO  ~ Module crud is available (/opt/local/lib/play-1.1-unstable-r777/modules/crud)
15:43:19,300 WARN  ~ You're running Play! in DEV mode
~
~ Starting up, please be patient
~ Ctrl+D to stop
~
15:43:31,774 INFO  ~ Connected to jdbc:hsqldb:mem:playembed
15:43:33,130 INFO  ~ Application 'Yet Another Blog Engine' is now started !
Welcome to Scala version 2.8.0.Beta1-prerelease (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_17).
Type in expressions to have them evaluated.
Type :help for more information.

scala> import models._
import models._

scala> User.count     
res0: Long = 3

commands are executed in a transaction, so changes to your models will be persistent

Module wrappers

Play comes with 2 default modules (secure and crud) and the scala module provides wrapper for them. For example you can create a CRUD controller by mixing in the CRUDFor trait:

object Companies extends Controller with CRUDFor[Company]

And by mixing in the Secured trait, you can turn on authentication:

object Companies extends Controller with CRUDFor[Company] with Secured

Utils

Similar to play.utils.Java, scala specific helper methods are stored in play.utils.Scala object. A few examples:

import play.utils.Scala._

Automatic Resource Management

for (stream <- using (new PipeStream())   {
//do something with stream, close() will be called at the end
}

Elvis operator

def nuller:String = null
?(nuller.toLowerCase.substring(1)) match  { case Some(s) =>s;case None=>"oh no" }

URL reader

val html = fromURLPath("http://www.playframework.org/@api/play/Play.html").mkString //read and connection timeout can be set too

Yabe with Scala

A scala version of the blog application is bundled with play-scala and can be found here

Mailer example

Mailer classes can be written in Scala too, here is an example

Tutorial

a tutorial can be found here