The play framework is a web action-based framework that allows you to create web applications in fast and simple way. The play framework can start fast and reload your java classes in a fast way without restarting your application. Play focuses on developer productivity and targets RESTful architectures. Play doesn’t use a java webserver to start the application so the webserver starts up fast, but it does use many standard java libraries, like jpa with hibernate. Another nice feature of play is that you can start it up in test mode and then you have an embedded selenium test available to you.
Models
You can use existing jpa entities or create new ones extending from the Model that play provides. Extending this base class will get you an id and a number of find methods that can be used as static methods.
The properties are set as public fields in these model classes. This looks like a no-no to any experienced java developer, but if you think about it a bit more, this may not be such an awfull thing. Most models that I have seen are nothing more then a bunch of getters and setters for some properties. So why not make them public. The play framework will create the getters and setters and will use them, however this is done at run time.
Of course, you still can make the properties private and use getters and setters as normal, but public is the convention for this framework. If your properties are public, if you write a setter or getter method for it, these methods will be used automagically, even if you try to assign values to the properties directly (so without using the setter methods). e.g. if some entity contains the following fields and method
public String requiredField = ""; public String setRequiredField(final String requiredField) { if (requiredField == null || requiredField.equals("")) { throw new IllegalArgumentException("requiredField can not be empty"); } }
then assigning a null value directly to the public requiredField will throw an IllegalArgumentException
object.requiredField = null; // errorTemplates
The templating engine that play uses to create the html (or xml or json or just text) uses groovy as the expression language. This means that inside the tags you can use the null aware features of groovy to show content. For instance ${user?.address?.number} will not cause any null pointers or null values to occur in your page even if the user or the address are null.
Nice features
You can map your urls directly to play actions. This is done in a special “routes” file. If the play framework finds these actions in your html files, it will revert it to the correct urls, e.g.
<a href="@{Application.showPerson(person.id)}">Show person</a>
will be translated in the href with the correct syntax, e.g. in this case:
<a href="localhost:8080/Application/showPerson?person.id=1">Show person</a>
Clicking this link will call the showPerson action of the application controller, passing in the person’s id as a parameter.
If you would like your url to be more like a rest interface, all you have to do is add the restlike structure to your routes, e.g.:
GET /showPerson/{id} Application.showPerson
Now, each time play see’s the Application.showPerson in your code, it will be replaced by the url
/showPerson/someId
in your code.
Play has a general configuration file, the application.conf. In this file you can set a number of properties that set general application settings. For instance the key http.port defines on which port the system should normally start. If you work with multiple developers on a project or on multiple locations it is very easy to change these settings in play. Just prefix the key with an id and set the id in play and all is set. For instance in my file I have the following keys:%home.http.port=9001
%laptop.http.port=8080
Then by running the command “play id” I can instruct play which setting to use (e.g home or laptop). Play will then ask which id I would like to use and then I can type either home or laptop or leave it blank to use the defaults. After the id has been set, this will remain the active id. You can also give the requested id as parameter to the start up using “play id –%home”. Using the id parameter the same configuration file can be used without messing up some other settings. Good integration for testing. Out of the box selenium is provided as well as means of loading data for test fixtures. You can define your data in complex structures in a yaml format and tell the test to load the given yaml file. The play framework also supports scala and it seems a good fit for scala projects since scala uses companion objects for things that in play gets done using static methods. The play framework uses reflection heavily but they changed the core to support scala as well. Gotcha’s
- The field names of all the parameters on the html should be the same as in the java class. This is needed for the automatic binding. This also means that if you change a parameter name, you have to change it in the html, the java and optionally in the routes. For instance, if in my routes I have defined the following:
GET /copyEntity/{id} EntityController.copy
and in the controller I have the following method:
public static void copyEntity(Long id) {...}
and in the html I have a hidden field with the name id.
If I would like to change the id field to originalId, I have to change the parameter id everywhere in originalId, so both in the routes, the html and the java class. This also means that you can not directly assign a parameter to the render method. You have to introduce a parameter with the correct name. So this will work:public static void showPerson(Long id) { Person person = (Person) Person.findById(id); render(person); }
An alternative is to use a map with field names and objects, using the renderTemplate method
- The play.db.jpa.Model defines a set of generic methods. These generic methods use a type parameter to specify the method’s return type. When using those methods, the concrete type to be used as return value is derived from the invocation context using type inference. So you either have to cast it yourself or introduce a variable of the correct type or use a java trick. The next example will not work
for (Person person : Person.findAll()) { person.delete(); }
but this will:
List persons = Person.findAll(); for (Person person : persons) { person.delete(); }
and using the java trick:
for (Person person : Person.<Person>findAll()) { person.delete(); }
- When redirecting in a controller to another controller method that shows the template, use the renderTemplate method to add the template name. Otherwise the system can search for the template name of the method that started the request, e.g.
public static void handlePost() { if (validation.hasErrors) { show(); } else { index(); } } public static void show() { renderTemplate("Controllers/show.html"); }
If we wouldnt explicitly use the renderTemplate method with the given show.html name, then the system would try to locate the handlePost template
- No maven integration. For continuous integration we always use maven, so not having this integration is kind of an issue. I have read that there are hudson plugins to start the play test cases (which can be run automatically by issueing “play auto-test”) that can look into the generated output dirs, but it is not a perfect fit.
- Static methods in the controllers, so no overriding in the controllers. For instance the crud plugin is a very convenient way to easily crud your models. However if you would like to change some parts of this controller you will have to copy it completely and change it however you see fit.
When I first looked into the play framework, I first focussed on the downsides but having worked for a bit with it and looking at the code that I have to produce to work with play, I am actually liking it. Another very nice feature is that you dont have to start your application server anymore and the reloading of classes is ery fast, both for html’s and the java classes. Another point worth noting is the documentation. There is a lot of it and very readable.