Tutorial: Play Framework, JPA, JSON, jQuery, & Heroku

UPDATE: This tutorial is for Play 1.x (an old version). Check out my Play 2 Tutorial if you want to get started with the latest stuff. (Thanks to John Borys for pointing this out.)

If you are a Java developer then you really need to give Play Framework a try. It is really refreshing to take a few minutes, step out of the legacy-feeling world of traditional Java web app development and into something modern and fun. I want to walk you through a very simple tutorial where we will build a web application with Play Framework. The application will use JPA for persistence and expose access to the data through a JSON over HTTP interface. The client-side of the application will be built with jQuery. Lets get started.

Step 1) Download and install Play Framework 1.2.3

Step 2) Create a new Play app from the command line and then move to the new directory:

play new playbars
cd playbars

Optional Step 3) If you want to work in an IDE then you can run one of the following commands and then open the generated project in your IDE:

play idealize
play eclipsify

I won’t walk though the IDE specific steps here, but you can refer to the Play documentation on IDE integration if you want to get that setup. Note that IntelliJ IDEA has great support for Play Framework with a console right in the IDE.

Step 4) Start the Play server from the new project’s directory :

play run --%test

This starts Play in test mode which will automatically recompile any changes we make to the application. No packaging, redeploying, or restarting servers will be needed.

Step 5) Open the application in your browser:

The default page provides you with great Play documentation on how to get started. But we will soon be changing that page. If you want to view the documentation locally after we change the page you can use these links:

Step 6) Lets start by creating a new JPA entity. Keeping it very simple, lets create a new “app/models/Bar.java” file containing:

package models;
import play.db.jpa.Model;
import javax.persistence.Entity;
public class Bar extends Model {
    public String name;

This entity uses the standard JPA Entity annotation but also extends the Play Model class which provides some nice conveniences which you can read more about in the Play JPA docs. I’m using just a plain public property on this class but you can also use the Java Bean getter/setter stuff in you like.

Step 7) Create a simple unit / integration test for this Bar object by creating a “test/BarTest.java” file with the following contents:

import org.junit.*;
import java.util.*;
import play.test.*;
import models.*;
public class BarTest extends UnitTest {
    public void integrationTest() {
        Bar bar = new Bar();
        bar.name = "a new bar";
        assertTrue(Bar.findAll().size() >= 1);
        assertTrue(Bar.findAll().size() == 0);

Step 8) Setup the default database by editing the “conf/application.conf” file and uncommenting the following line:

# db=mem

This sets up the default database to be an in-memory database.

Step 9) Run the application’s tests by opening the following URL in your browser:

Select “BarTest” and then click the “Start!” button. The test should pass.

Step 10) Add the following two methods to the “app/controllers/Application.java” file:

    public static void addBar(Bar bar) {
    public static void listBars() {

The addBar method takes a Bar, saves it, and then redirects back to the index page. Play will automatically parse request parameters and populate the Bar object. The listBars method queries for all of the Bars in the database and then outputs then as serialized JSON.

Step 11) Play has a very flexible model for mapping URLs to controllers. Lets setup two new routes that will map URLs to the new methods we’ve added to the Application controller. Add the following lines to the “conf/routes” file but make sure you either add them above the “Catch all” or simply remove the “Catch all” route:

POST    /                                       Application.addBar
GET     /bars.json                              Application.listBars

The first route handles HTTP POST requests to the “/” URL and handles them with the Application.addBar method. The second route handles requests to the “/bars.json” URL and handles them with the Application.listBars method.

Step 12) Lets add a FunctionalTest that will actually make requests to the Controller and test that our new routes and controller methods are working. Add the following method to the “test/ApplicationTest.java” file:

    public void barTest() {
        Response addBarResponse = POST("/", APPLICATION_X_WWW_FORM_URLENCODED, "bar.name=foo");
        assertStatus(302, addBarResponse);
        Response listBarsResponse = GET("/bars.json");

This test adds a new Bar by doing an HTTP POST to “/” and passing it some form encoded data. Then a request is made to “/bars.json” and the response is checked to make sure there wasn’t an error. Since there isn’t a DELETE method (which could easily be added) there isn’t a good way to clean up what this test does.

Run the ApplicationTest Functional Test in the Play Framework Web Test Runner:

Because the test didn’t clean up after itself you can now see the JSON from “/bars.json” in your browser by visiting:

Step 13) Now it is time to create the actual web UI for this application. A combination of plain HTML (via Play’s Groovy templates) and jQuery will be used. Play Framework uses a convention to render the HTML from the “app/views/Application/index.html” template when Application.index‘s render method is called. In the “index.html” file and you will see:

#{extends 'main.html' /}
#{set title:'Home' /}
#{welcome /}

You can also take a look at the referenced “app/views/main.html” file to see what the base template looks like. It does the standard HTML page stuff and then inserts the body of the “index.html” page into the “#{doLayout /}” section. The “main.html” template also loads jQuery and provides a way to insert some JavaScript into the head section of the page. In the “index.html” file, replace the “#{welcome /}” line with a form that will allow users to create new bars:

#{form @addBar()}
    <input type="text" name="bar.name"/>
    <input type="submit"/>

The “#{form @addBar()}” syntax is Groovy that creates a form tag and sets the form action to the URL that corresponds to the Application.addBar method. You can test this out by loading this page in your browser:

The form should be functional now. Enter the name of a bar and click the submit button. Because the “addBar” method calls the “index” method, after the POST, the browser is redirected back to the index page. You can verify that the data is being saved by loading the bars.json page again.

Now lets add some Ajax / jQuery to the “index.html” page that will get the JSON data and display it in the page. Add an empty ul tag with an id of “bars”:

<ul id="bars">

Now we will insert the JavaScript into the correct place in the page by setting the “moreScripts” variable:

#{set 'moreScripts'}
<script type="text/javascript">
    $(function() {
        $.get("bars.json", function(data) {
            $.each(data, function(index, item) {
                $("#bars").append("<li>Bar " + item.name + "</li>");

Using jQuery this bit of JavaScript adds a function handler for when the page is loaded, then in that function it makes a get request to “bars.json”. That request has a function handler for when the result comes back from the Ajax request. Inside that function handler the data is iterated through and each “bar” is appended into the page element with the id of “bars” – the ul tag.

Try out the application and make sure that you can still add new bars and see the list of all the bars in the database.

Now that everything works locally, lets deploy the app on the cloud using Heroku.

Step 1) Create an account on Heroku.com, install the Heroku Toolbelt and git and then login to Heroku from the command line:

heroku login

If this is the first time you’ve done this then new ssh keys for git will be created and associated with your Heroku account.

Step 2) Each application on Heroku has a Postgres database for testing. To use that database when running on Heroku we need to configure it. Play applications on Heroku run in “prod” mode. To set the database to use the Heroku database add the following lines to the “conf/application.conf” file:


The default way to provide database (and other resource) connection strings to an application on Heroku, is through environment variables. The DATABASE_URL environment variable will contain the database host, name, username, and password. Play Framework knows how to handle that information and setup the JDBC connections.

Step 3) Heroku uses git as a means to uploading applications. Whether or not you use git for your SCM tool you can use git as the tool to upload an app to Heroku. In the root directory of your project create git repo, add the files to it, and then commit the files:

git init
git add app conf public test
git commit -m init

Note: Instead of doing a selective “git add” you can create a “.gitignore” file containing the files to not add to the git repo.

Step 4) Now we will provision a new application on Heroku using the Heroku CLI. Each application you create gets 750 free “dyno” hours per month. So as a developer you can use Heroku for free and only pay when you need to scale beyond one dyno. On the command line create a new application using the “cedar” stack:

heroku create -s cedar

This creates an HTTP endpoint and a git endpoint for your application. You can also use a custom name and point your own domain names at the application.

Step 5) The application is ready to be deployed to the cloud. From a command line do a “git push” to the master branch on Heroku:

git push heroku master

Once the files have been received by Heroku, Play Framework’s precompiler will be run, Heroku will assemble a “slug file”, and then the “slug” will be deployed onto a dyno.

Step 6) You can now open the application in your browser by navigating to the domain outputted following the “heroku create” or by simply running:

heroku open

You’ve built a Play Framework application with JPA, JSON, & jQuery and then deployed that application on the cloud with Heroku! Now get the code and check out a demo on Heroku. Let me know if you have any questions.

  • Guest

    Nice tutorial.
    There should be a caveat though — the Play developers made a very controversial decision to embark on a “great rewrite” for the next version of the framework (2.0), now in beta, which is pretty much a completely new framework, incompatible with the 1.2.x branch.

    • I started learning Play 2 and I think the change will be worth it.  I’ll be blogging about Play 2 here, so stay tuned.

  • Hello, thanks for this poc i’m trying it and noticed one little mistake at step 9 : should be http://localhost:9000/@tests

    Assuming i’m using v1.2.4 and not v1.2.3, could be that ? I think it’s only about the @ missing.


    • Whoops.  That was a typo.  Thanks for catching it!

  • Neoh59

    Just run “play test” command instead of “play run –%test” in this caseBut it’s interesting to know the Play! ID system.Thanks for your demo, I thnk I will reuse it to show Play! at my friends.

    • Oh yeah.  Forgot about that shortcut.  Thanks!

  • Working great ! http://cem-play-poc.herokuapp.com/

    Just lets see know what gonna happen with Play! v2…


  • SSK

    Great tutorial. I was able to deploy my app and get started real quickly :)
    Now, I keep getting a page with a message “Oops, an error occured” when I try to do any db related operations with my app. I’ve been wondering if it’s got something to do with creating the related tables on the remote db? How do I know for sure?

  • SSK

    Okay, figured that out. Apparently postgre doesn’t support creating a table by the name ‘user’. For everyone else who runs into this problem, refer this: https://play.lighthouseapp.com/projects/57987/tickets/596-cant-create-table-called-user-in-postgresql

  • Koen

    Good tutorial! Got it running in an hour. Helped me exploring the framework. Great and Thanx 

  • tbrew

    That was too easy. Love this framework.

  • Ming-der Wang

    Great help!

  • Mymailnot

    thanks. nice tutorial. is it possible to get the json as in following format

    bars: [{“name”:”x”,”id”:1},{“name”:”xx”,”id”:2},{“name”:”xxx”,”id”:3}]

    • Mymailnot

      my bad, i just have to add this to a map and get the json of that :). problem resolved.

  • Yiannis

    Hi there!
    Just one thing, if someone deploys application in heroku for the first time, he should execute heroku keys:add ~/.ssh/id_rsa.pub before step 5) of the heroku deployment procedure!
    Best Regards

  • Marcelino Ramos de Avelar

    Obrigado, seu post me ajudou muito!!!! parabéns!!!
    Marcelino Avelar – Barra do Garças – MT – Brasil.

  • Jill

    I’ve developed a full play app, everything running fine locally, but when i push to heroku i get:  !     Heroku push rejected, no Rails or Rack app detected
    I’m pushing from my root directory and verified that my local git has conf/application.conf.

    Any insights greatly appreciated!

    • Jill

      Heroku support got back to me, they said only their latest cedar stack supports play. Tried again this morning and it worked.

  • Andreas K


    thanks for that great tutorial. I have tried similar but with websocket controller.  The Websocket part somehow does not work on heroku…

    Deployment went fine but I see the following from the heroku logs, when client tries a ws request:

    2012-01-14T10:36:29+00:00 heroku[router]: Error H12 (Request timeout) -> GET pla
    y-push-imgsel.herokuapp.com/application/pushimgsel/process dyno=web.1 queue= wai
    t= service=30000ms status=503 bytes=0

    My route for that request is as follows:
    WS      /application/pushimgsel/process    Application.PushSelectionSocket.process

    On my local machine the demo is working just fine (Safari 5.0.5 on Winxp)…

    Using Play 1.2.4, Code on https://github.com/multikoop/play-push-imgsel

    Any Hints would be greatly appreciated.


    • WebSockets are not support on Heroku yet.  You will have to use Comet / Long Polling instead.  Sorry.

  • Andreas K

    Thanks, I have  filed an support/enhencement request at heroku.

    I don’t want to go with legacy web push technologies;)

  • Jamesward_blog

    Do me one solid, change:

         $(“#bars”).append(“Bar ” + item.name + “”);


         $(“#bars”).append($(“”).text(“Bar ” + item.name));

    or the more jQueryish:

         $(“”).text(“Bar ” + item.name).appendTo(‘#bars’);


  • Amit Smoller

    Excellent Tutorial. Easy to follow and gets you up and running in a couple of hours!
    Thank you

  • This is a great tutorial. I’m looking for something to start with Heroku as the platform is completely new to me. But, this clarified few doubts that I had. Thanks.

  • james

    Im a total beginner in this world, so please understand the ignorant question, but when i follow the tutorial and open the deployed web app i get instead of my app the following line “You application is ready!” what am i missing ? it is probably something silly but i cant seem to find it.


    • That is the default welcome message in prod mode.  So I’m not sure if you did anything wrong.

    • Did you git add and commit your changes before pushing to heroku? (step 3)

  • Pingback: Tutorial: Play Framework 2 with Scala, Anorm, JSON, CoffeeScript, jQuery & Heroku()

  • Andreas

    Great tutorial. Thank you very much.

  • Rick H.

    Nice work James, thank you. And I totally agree, have been doing Java/J2EE for 11 years and Play for one, Play is the most productive and fun way to do Java that I have every used.

  • Udar

    Any chance of updating this for play 2.0?

    • In progress…  https://github.com/jamesward/play2torial/blob/master/JAVA.md

      Let me know what you think.

  • hello world

    good tutorial James,
    but I wanna ask something, is that a real AJAX ?
    coz I saw the whole page reloaded after clicking the button
    How to make the entire page does not reloaded ?Sorry for my bad EnglishThanks

    • It’s just half Ajax.  The submit / create is not, but the fetch is.

  • Fantastic tutorial, thanks!  Helped get me back up to speed with this awesome framework after over a year’s absence.  I tried the new 2.0 but I gotta say that thing is not ready for regular devs to use yet so went back to 1 and am loving it.  :)

    • Cool.   Thanks.  What didn’t you like about Play 2?

      • Todd

        I am with Brandon. I was able to run through the tutorial and docs for Play 1.2 and be competent pretty quickly.  With 2.0 the tutorial and docs are not as complete while the framework got more complicated.  Thank God for Stack Exchange or I would have given up.
        I didn’t keep a list of the many things that gave me trouble.  I remember simply getting JPA working on a Postgres db was one of them.  Now it takes changes in more than one config file and I didn’t find all that documented in one place.

        I found a bug (?) where the getter for the ID is not automatically visible despite the claims of the docs. http://stackoverflow.com/questions/10590021/id-not-automatically-available-in-playframework-models

  • yogesh sb


  • yogesh sb

    @jlward4th:disqus : Excellent article.. i am using play@33c7515e9f40ab84e31de7ab6db931b9:disqus
    . i have some static data(some question and answers), i want to display those static data in my website(scala). So when the user clicks the particular question then the answer should be displayed in my website, which should be come from my application itself, say data should come from memory.java file. i dont want to use any external database. So can any one tel me how to to put those static data in my memory.java file and then later fetch it when ever the user the clicks it in my website. using json or xml?  please tel help me out with the complete procedures. because am trying it out from many days.


    • I’m not totally sure what you are looking for.

  • Martha Kumi

    Hello James, 
    Thanks for this tutorial. I actually use Play at work, and I have a little problem. Do you know how I could use Selenium to send HTTP requests to an API and receive HTTP responses? All using Selenium syntax. 
    I am working on testing an API’s functionality when it comes to it receiving HTTP requests and sending responses to applications. I believe I am not sure as to the write procedure or commands to use to attain this. Can you help me out?

    • I would actually write this as an integration test instead of using Selenium.  There are multiple ways you can do this kind of test via Play.  What version of Play are you using?

  • Pingback: Java (programming language): What are some good tutorials for the Play framework (Java)? - Quora()

  • Nice Explanation.

    java training in chennai

  • jackson

    This information you provided in the blog that was really unique I love it!!, Thanks for sharing such a great blog..Keep posting..

    JAVA Training in Chennai

  • ImadEddine

    Hi James from other side,

    I work with Play and Spring Data JPA (v 1.5)

    Have you got a problem like this ?!!

    Uncaught error from thread [play-akka.actor.default-dispatcher-6] shutting down JVM since ‘akka.jvm-exit-on-fatal-error’ is enabled for ActorSystem[play]

    [ERROR] [09/02/2014 09:08:53.736] [play-akka.actor.default-dispatcher-6] [ActorSystem(play)] Uncaught error from thread [play-akka.actor.default-dispatcher-6] shutting down JVM since ‘akka.jvm-exit-on-fatal-error’ is enabled

    java.lang.ExceptionInInitializerError at


    Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘kSession’: Cannot resolve reference to bean ‘kbase1’ while setting bean property ‘kBase’; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘kbase1’: Invocation of init method failed; nested exception is java.lang.RuntimeException: Unable to get bytes for: /home/imadeddine/git/maretraitev4/play/target/scala-2.10/classes/Routes$$anonfun$routes$1$$anonfun$applyOrElse$69$$anonfun$apply$171.class


    What’s the problem … i am stooped

    • That is a strange error. It looks like a file corruption. Do a clean and then try again.

      • ImadEddine

        I do :

        play clean compile

        play run

        no problem !!

        in browser : localhost:9000 —> Error started with

        [ERROR] [09/02/2014 15:24:57.842] [play-akka.actor.default-dispatcher-7] [ActorSystem(play)] Uncaught error from thread [play-akka.actor.default-dispatcher-7] shutting down JVM since ‘akka.jvm-exit-on-fatal-error’ is enabled
        java.lang.NoClassDefFoundError: Could not initialize class fr.adservio.ret.play.utils.SpringEnv
        at fr.adservio.ret.play.services.impl.LoginUserService.getLocalTokenService(LoginUserService.java:128)
        at fr.adservio.ret.play.services.impl.LoginUserService.doDeleteExpiredTokens(LoginUserService.java:50)
        at securesocial.core.java.BaseUserService.deleteExpiredTokens(BaseUserService.java:144)
        at securesocial.core.UserServicePlugin$$anonfun$onStart$1.apply$mcV$sp(UserService.scala:133)
        at akka.actor.Scheduler$$anon$9.run(Scheduler.scala:80)
        at akka.actor.LightArrayRevolverScheduler$$anon$3$$anon$2.run(Scheduler.scala:241)
        at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:42)
        at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:386)
        at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
        at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
        at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
        at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)

        Uncaught error from thread [play-akka.actor.default-dispatcher-7] shutting down JVM since ‘akka.jvm-exit-on-fatal-error’ is enabled for ActorSystem[play]

        java.lang.NoClassDefFoundError: Could not initialize class fr.adservio.ret.play.utils.SpringEnv


        End with :

        Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘kSession’: Cannot resolve reference to bean ‘kbase1’ while setting bean property ‘kBase’; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘kbase1’: Invocation of init method failed; nested exception is java.lang.RuntimeException: Unable to get bytes for: /home/imadeddine/git/maretraitev4/play/target/scala-2.10/classes/Routes$$anonfun$routes$1$$anonfun$applyOrElse$13$$anonfun$apply$13.class

        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:328) ~[spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]

        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:107) ~[spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]

        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1456) ~[spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]

        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1197) ~[spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]

        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537) ~[spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]

        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475) ~[spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]

        Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘kbase1’: Invocation of init method failed; nested exception is java.lang.RuntimeException: Unable to get bytes for: /home/imadeddine/git/maretraitev4/play/target/scala-2.10/classes/Routes$$anonfun$routes$1$$anonfun$applyOrElse$13$$anonfun$apply$13.class

        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1553) ~[spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]

        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539) ~[spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]

        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475) ~[spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]

        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304) ~[spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]

        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228) ~[spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]

        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300) ~[spring-beans-4.0.2.RELEASE.jar:4.0.2.RELEASE]

        Caused by: java.lang.RuntimeException: Unable to get bytes for: /home/imadeddine/git/maretraitev4/play/target/scala-2.10/classes/Routes$$anonfun$routes$1$$anonfun$applyOrElse$13$$anonfun$apply$13.class
        at org.drools.compiler.kie.builder.impl.FileKieModule.getBytes(FileKieModule.java:46) ~[drools-compiler-6.0.1.Final.jar:6.0.1.Final]
        at org.drools.compiler.kie.builder.impl.AbstractKieModule.getClassesMap(AbstractKieModule.java:137) ~[drools-compiler-6.0.1.Final.jar:6.0.1.Final]
        at org.drools.compiler.kie.builder.impl.KieModuleKieProject.getClassesMap(KieModuleKieProject.java:79) ~[drools-compiler-6.0.1.Final.jar:6.0.1.Final]
        at org.drools.compiler.kie.builder.impl.KieModuleKieProject.initClassLoader(KieModuleKieProject.java:66) ~[drools-compiler-6.0.1.Final.jar:6.0.1.Final]
        at org.drools.compiler.kie.builder.impl.KieModuleKieProject.getClonedClassLoader(KieModuleKieProject.java:98) ~[drools-compiler-6.0.1.Final.jar:6.0.1.Final]
        at org.drools.compiler.kie.builder.impl.AbstractKieModule.buildKnowledgePackages(AbstractKieModule.java:166) ~[drools-compiler-6.0.1.Final.jar:6.0.1.Final]

        • Looks like you are missing a dependency.