Play framework is joining the Typesafe Stack — More information in the official announcement
Community contributed extensions
scala-0.7.2 has been tested with this framework version: Tested with Play-1.1r956
Get help with google
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
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)
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
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.
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"
}
Models can be defined not only in java but in scala as well.
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
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
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.
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
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("peter@gmail.com","secret","my name").asScala[JUser].save()
or
val u = new JUser("peter@gmail.com","secret","my name")
u.asScala.save()
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")}
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("bob@gmail.com", "secret", "Bob").save()
bob = User.find("byEmail", "bob@gmail.com").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'}")
}
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
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
Similar to play.utils.Java, scala specific helper methods are stored in play.utils.Scala object. A few examples:
import play.utils.Scala._
for (stream <- using (new PipeStream()) {
//do something with stream, close() will be called at the end
}
def nuller:String = null
?(nuller.toLowerCase.substring(1)) match { case Some(s) =>s;case None=>"oh no" }
val html = fromURLPath("http://www.playframework.org/@api/play/Play.html").mkString //read and connection timeout can be set too
A scala version of the blog application is bundled with play-scala and can be found here
Mailer classes can be written in Scala too, here is an example
a tutorial can be found here