It was the fourth week of heavy fighting with Play! Framework 2.1 + Java. The victory inexorably approached, but it was far from complete surrender.After the encouraging news about the development of Play! 2.1, for example in
LinkedIn , it was decided to try it in one new project. Test it, so to speak, in action. What came out of it? I would say that it was a small war between me and Play! 2.1. Why? Details under the cut, and for the impatient:
Brief conclusion
For the assault, it was necessary to take a secret weapon codenamed Scala. If you stand face to face with Play! Framework 2.1 and shout out with all your might: “You are a Scala-framework!”, He will be afraid of such directness and modestly open his doors into a world of great opportunities.“Don't know Scala?” - “Use Play 1.2”.
“Do you know Scala well?” - “Be sure to try Play 2.1. But still, be patient. ”
Prehistory
For 7 years with a mouse and a keyboard with a sword and a shield, I have been to different states on the planet Java. These were the ancient ruins of the Enterprise, where life is still warming, and the blossoming Springlia, and his vassal Gruvilyandiya with its capital in Grails City, and the once advanced and exotic Playterra. The first, and many, many other states, cities and even deaf villages. But the trip to Playterra II was unexpectedly difficult.I worked on a single project for about 9 months using Play 1.2.x, and I was absolutely delighted. Even after the Spring Framework 3, it seemed like speed and ease of development, not to mention the monstrous Java EE 5 + JSF.
Then there was a short break in which I managed to work intensively with Grails 2.x for 3 months and understand how far behind Java Groovy was in terms of convenience and syntax capabilities. And that Grails is somewhat simpler and faster to develop than pure Spring Framework 3 + Java.
However, it is time to choose a framework for a new project, and the choice fell on Play 2.1. Was this the right decision? Interesting exactly, but the right thing - time will tell.
In the meantime, I want to share my impressions of working with Play 2.1. There will be many comparisons with Play 1.2.x, laments about Java and emotions. There will be almost no code, and generally accepted terms and concepts will not be translated into Russian. For example,
stateless framework .
')
Impressions
Lack of documentation
The maps of the region that the rulers of Playterre II provided were far from complete. The main roads are indicated quite accurately, but there is an impassable thicket around these roads. In order not to stray, the locals had to miss and ask them a lot of questions. By the way, they answered very willingly.Official documentation is rather stingy. There are two books
Play 2 with Java and
Play 2 with Scala . The first, about Java, largely repeats the official documentation with comments for beginners. The second, about Scala, is a bit more useful and touches the right topics, for example Chapter 8. Building a single-page JavaScript application with JSON.
Of course, there is a large and active community. You can ask for help and ask a question in
Google Groups or on
Stackoverflow . But the pleasure of developing a little is lost if you constantly have to look for answers to seemingly simple questions.
I even participated in the improvement of the documentation (
here ), but there are still many places that I want to cover in more detail.
For Play 1.2.x, the documentation was more complete and useful. Search for Stackoverflow and Google Groups had only really unusual things.
Compilation speed
The roads here are far from ideal. Sometimes it was necessary to go for hours, drowning in mud and begging the horse not to give up and gallop faster. The transfer of a large army takes a very long time. On the roads everywhere checkpoint and check.For many, this will not be news, but the compilation works slowly here. Much slower than Play 1.2.x. I understand that almost everything is compiled here, from simple Java classes to Scala temlates and coffee scripts. But it is a long time. Let imputed error messages, but it is long. Lightning, ideally
Hit refresh workflow, stumbles and annoys.
Work with database
Smarty residents do not know how to finish building their own fortresses. They can not say: "Build another tower, but quickly!". Not. They need a detailed plan.There is a built-in Database Evolutions mechanism. But with the generation of these scripts problem. Ebean can still create a complete script, but with incremental problems already. Analog
jpa.ddl=update
for Ebean I, unfortunately, did not find. If someone tells you, I will be immensely pleased. Analog or adaptation of
LiquiBase's Diff would also be very useful.
Hired foragers were strange peasants. It seems to work, but constantly waiting for supply disruptions.Ebean as a concept is very good. Main advantages:
- no sessions (Session, EntityManager, etc.) that fits well with the stateless framework. However, as such, the Persitent Context is.
- Partial Objects support, allowing you to write more efficient queries.
Controversial moments:
- Partial support for JPA. You need to know and understand exactly where this support ends.
- Lack of documentation and examples of use.
- Not as active and not as big a community as Hibernate.
There are transactions here too. You can even mark the controller method as
@Transactional
. But only the controller method or the controller itself. For third-party classes, you have to take care of this yourself.
In general, Ebean is a very interesting library, sometimes even simpler and clearer than Hibernate or JPA, but I can’t get rid of the doubt that there will be enough opportunities to satisfy all the needs of a growing project.
Of course, you can use the standard JPA, but there is a lack of
Model.find("byName", name)
from Play 1.2.x or integration with
Spring Data JPA 1 . There is a feeling that you are going back a few years to the past.
By the way, Ebean has several significant flaws: for more details, see the
Caveats section on the
Using the Ebean ORM page. And the fact that Play 2.1 stops generating getter / setter, if there is at least one such handwritten method in the class, makes it necessary to avoid the names of the methods starting with
get
or
set
. For getters, I now simply omit the word
get
and call the methods
byName
or
byEmail
.
But such an incredible thing, you can even say the
killer feature in Ebean, as the
PagingList in the stateless framework is not applicable. Alas and ah.
As for working with NoSql databases, you can easily find plug-ins for Elasticsearch, MongoDB (even a few pieces) and OrientDB. I did not use it myself, so I can’t say anything about the quality of these plug-ins.
Testing
Check the status of the army is constantly broken by enemy spies. The organization of the exercises is hindered by local living creatures: monkeys are thrown by coconuts, ivy is woven over their feet, and sometimes kamikaze skunks are found.It is, there are many possibilities: from simple unit-tests of models to testing controllers and using Selenium.
In my tests, I tried to use the in-memory database as described in the documentation:
@Before public void setUp() throws Exception { start(fakeApplication(inMemoryDatabase(""))); }
However, I immediately had two problems, big and small.
Small: how to deal with transactions in tests? I found nothing like
@Transactional
from Spring or Grails. It remains only to open and roll back transactions in tests. Inconvenient and immature.
Large: the conflict between the fact that the main base I have MySql, and for tests in-memory H2. So, H2 refuses to understand the evoluation scripts for MySql, and the use is not the default database configuration, for example:
start(fakeApplication(inMemoryDatabase("login-test")));
entails the uncertainty of where the data will still be saved, if you use the
save()
method without specifying the configuration.
I have seen several obscure descriptions of the solution to this problem, but there is no simplicity in it.
Official documentation about how to organize the work of the database in the tests, says nothing.
Out of good. There are useful
~test
or
~test-only
commands that will work every time, as you change the source code. Allows you to save time required to run tests.
Security
In state forges there is only the simplest armor. Craftsmen forge much better things.Authorization and authentication capabilities remained at the level of Play 1.2.x. There is an
Action Composition with the
@With
annotation, there is
Security.Authenticator
and a good example of how to use it: the
Adding authentication page, the section Implementing authenticators.
Third-party plug-ins offer more features. For example,
Deadbolt or
SecureSocial , but they seemed to me too tight for a small project, and I was fine with my handwritten authorization.
By the way, this is surprising, but Play 2.
0 has lost such a useful feature as
Authenticity Token , but there is a
third-party plugin that compensates for lost abilities. However, in Play 2.1, some
filters
were added that are mentioned in the press release of version 2.1, but about which there is very little documentation. Among the filters mentioned just
CSRFFilter
. The only thing that I managed to find about him is this
post , which describes how to work with the filter to protect against CSRF in Scala. How to apply and whether it applies at all to Play 2.1 + Java should also be sorted out.
Instability
Sometimes there were mirages on the way. When approaching, they disappeared. There were no mirages on the maps.Several times the working code stopped working! Apparently, compilation and generation of getters / setters does not always work correctly. Helped
play clean
and restart the project.
The strangest moment I stumbled upon was that the valid for
JDK 7
type code:
catch (IndexOutOfBoundsException | ArrayStoreException e)
brought Play 2.1 into a complete stupor: no errors, no messages, just the server hangs on these lines and nothing happens next. I asked a question
here , waiting for an answer.
Templates
Here come such marshes that can suck head. And they can not suck.I must say bluntly: for the effective use of templates, you need to know Scala well, or at least understand something in it. Otherwise, all this turns into an incomprehensible cobweb of code. And you have to be very careful, because it works like this:
@main(title = "Home") { <h1>Home page</h1> }
and there will already be an error due to
{
on the new line:
@main(title = "Home") { <h1>Home page</h1> }
Or another example:
When I first read about Scala templates in Play 2.0, I was very happy because it looked like a very convenient Razor from .Net. Indeed it seems, and, in my opinion, more convenient than many template engines in the world of Java. However, do not forget that the first line, you must declare all input parameters. And you can only declare the
fullName
variable in the code like this:
@defining(user.getFirstName() + " " + user.getLastName()) { fullName => <div>Hello @fullName</div> }
And what to import for some things:
@import helper._
. And many more “ifs” and “buts”, within the framework of which one feels not very free.
The main advantage - Scala templates are compiled and checked at compile time, which reduces the number of unreported errors and offensive typos.
In general, the Scala template in Play 2.1 is good or bad - a controversial issue, but it recedes into the background, because Javascript MVC frameworks are gaining popularity, and the following becomes relevant:
Work with JSON
Here the brave warrior was completely upset and went to drink in the tavern.In my opinion, Play 2.1 loses Play 1.2.x a little. The main reason is that instead of Gson, Jackson is used as the main library for working with JSON in Java. I enjoyed working with GSON in Play 1.2.x, it was convenient and flexible. With Jackson you have to work quite differently. Apparently, I have not yet reached that level of understanding of Jackson to get pleasure from him. And the fact that the names of the fields in the c JSON string must be escaped with double quotes, caused me a heavy sigh:
return ok(Json.parse("{\"status\": \"success\"}"));
Almost no readability. Especially when compared with the ease of working with JSON in Grails:
render([result: 'fail'] as JSON)
Of course, not everything is so bad, but the best thing you can do in Java is something like
2 :
ObjectNode result = Json.newObject(); ArrayNode arrayNode = result.putArray("photos"); for (Photo photo : photos) { ObjectNode photoAsJson = arrayNode.addObject(); photoAsJson.put("id", photo.id); photoAsJson.put("guid", photo.guid); } return ok(arrayNode);
Quite tolerable.
However, for Scala, JSON support in Play 2.1 version was significantly improved:
Json.obj( "users" -> Json.arr( Json.obj( "name" -> "bob", "age" -> 31, "email" -> "bob@gmail.com" ), Json.obj( "name" -> "kiki", "age" -> 25, "email" -> JsNull ) ) )
But in Groovy, it still looks shorter and simpler. It remains to hope that Scala will still add native JSON support, as it is now for XML.
I decided to simplify my life, I added two additional classes with static methods: one is the
Pair
, an analogue of
Tuple2
from Scala, the other is the class that puts
Pair
s in the
Map
. As a result, it became easier for me:
return ok(toJson(map( pair("status", "fb-logged-in"), pair("user", map( pair("id", fbUser.id), pair("facebookUserId", fbUser.facebookUser.userId), pair("fullName", fbUser.fullName()) )) )));
If we are talking about
Tuples
, then in Play 2.1, functional support for Java is copied from Play 1.2.x, the library
play.libs.F
However, there is no mention in the official documentation of this. It is necessary to watch the
docks for Play 1.2.x.And one more thing: XML support also migrated from Play 1.2.x, and using
play.libs.XPath
to work with XML is very convenient.
Work with mail
Postal pigeons and ravens are all imported here. Get them easy. And it is rumored that the rulers of Playterre II shot all the birds themselves.I want to say a few words about mail because Play 1.2.x had built-in support for sending mail, but not in Play 2.1. There is an official
mail plugin . Here
they say that the creators themselves decided not to add mail support. Ostensibly it is so easy and simple that everyone can do it himself. A lot of questions and disturbances in Google Groups refute this view: people expect from Play 2.1 no less functionality than it was in Play 1.2.x.
Configuration
If earlier contracts were written on scrolls, now on separate sheets.The main thing that is worth noting is that they removed the
framework ID
. Now, instead of one large configuration file, you need to have several separate ones. Controversial point, each approach has its pros and cons. If earlier to start
production
was:
play run --%production
now it looks like this:
play -Dconfig.resource=prod.conf start
And
prod.conf
contains all the settings overrides without any prefixes.
IDE integration
My best horse sprained foot on the local roads!I will not tell you
for all Odessa for all IDEs, but my beloved Intellij Idea has so far from ideal support for Play 2.x. Navigating through the code very often results in generated classes that you don’t need to look and see, sometimes there are problems with editing scala templates, full SBT support will only be available in version 13. Here is just what I found and told myself:
youtrack.jetbrains.com/issues/SCL?q=reported+by%3A+Andrey.Volkov+The pleasure of writing code is not enough. I understand that Play 2.x was released not too long ago and it may not be so popular to spend large resources on its support in the IDE. Just know that you should not expect much help from IDE.
With Play 1.2.x in this regard is much better.
Vanished simplicity
If the country of Playterre the First was full of wonders and much was done by magic, then in Playterre II no magic, just a shovel and hoe, shield and sword.Play 1.2.x was very simple and convenient. Much has been done somehow by itself, and it worked. Yes, I heard opinions that in Play 1.2.x too much happened by itself, too much was generated and it was completely unlike the familiar Java-world, but it worked simply, easily and quickly. All the complexity was hidden from ordinary users, and only the most meticulous programmer had to drip into the intricate source code.
In Play 2.1, almost all the “magic” is left to Scala. And this is no longer magic, this is clearly the definite work of Scala. On which the programmer has to stumble constantly. And without knowing even the basics of Scala, it is very difficult to understand.
Compare for fun:
public static void index() { render() }
and
public static Result login() { return ok( login.render() ); }
The first piece of code is simpler, but you need to know and follow some agreements, and the second piece of code is more verbose, but you also need to know something and follow something. The second may be more flexible, but no more simple. I personally like the first one more.
By the way, what do you think
login
in the second example? This is the class generated from the scala template. Which appears only after compilation of this scala template itself. Those. The IDE will complain that there is no such class or the method signatures do not match if you change something. After compilation, complaints will disappear, but using IDE prompts becomes problematic.
Playterre The first was full of winged fairies and good spirits. In Playterra II there are only mechanical golems in which each gear can be seen.Undeniable benefits
Despite many oddities, if not to say flaws, Play 2.1 has a number of undeniable advantages.
Working with forms and validation
Very comfortable. Full support for JSR-303 (Bean Validation) plus the ability to add your own
validate
method for specific checks. I will not rewrite examples from the official documentation. They can be beautifully seen
here .
For templates, there is a built-in generation of
input
fields, and you can immediately generate markup for Twitter Bootstrap. The only pity is that for version 1.4. You have to write a custom generator (section
Writing your own field constructor ).
If Authenticity Token had not been removed and Twitter Bootstrap 2.3 fields had been generated, then it would be almost ideal.
Akka and other asynchronous things
In the local taverns and taverns very fast service. And never queues.In terms of asynchrony and multithreading support, Play 2.1 is on horseback. Here and native
support for asynchronous HTTP requests and
integration with Akka . If only the verbosity of Java when working with functions, not even mentioned in official documentation ...
Just compare. Java:
public static Result index() { Promise<Integer> promiseOfInt = play.libs.Akka.future( new Callable<Integer>() { public Integer call() { return intensiveComputation(); } } ); return async( promiseOfInt.map( new Function<Integer,Result>() { public Result apply(Integer i) { return ok("Got result: " + i); } } ) ); }
Scala:
def index = Action { val futureInt = scala.concurrent.Future { intensiveComputation() } Async { futureInt.map(i => Ok("Got result: " + i)) } }
Another reason to switch to Scala. Or something else, but more “functional” than Java.
However, competitors are not asleep: in Grails 2.3 will be very good support for asynchronous computing (
post in the official blog ). Moreover, it is more convenient to do asynchronous computing on Groovy than on Java: support for closures plays a role.
Scalability and clouds
The land here is fertile and can feed almost any population. And across the sky float and float clouds of various shapes and sizes.It is said that, due to its asynchronous and stateless nature, Play 2.1 scales well. While my project has not grown to such needs, therefore I can not confirm this on my own experience.
Yes, and Play 2.x is supported by many cloud hosting sites. Moreover, native support, i.e. no need to build a war file and deploy it under Tomcat / Jetty.
If you still need to build a war file, you can do it only with the help of a
third-party plug-in .
CoffeeScript and Less support
Small demons are straightened here, and now they are loyal to serving the people.Native support for CoffeeScript and Less. I do not even know what can be added or explained here. Conveniently. So be it. Even everything is even easier to be
.min.js
: you just load
.min.js
instead of
.js
.
Problems with this has not been.
Console
Customs at the entrance to Playterra II hired new workers. Although who cares, nobody sees their work anyway. Let them work well, then no one will pay attention to them.The console has become much more convenient and functional than it was for Play 1.2.x. But this is more due to SBT (Scala Build Tool) than Play 2.1 itself.
From what came in handy to me, I want to mention the commands starting with
~
, which are executed every time the source code changes. I gave the example with
~test
above.
What is the result?
Going on vacation on Playterra II is interesting. The question of migration there is completely open.For myself, I made the following conclusions:
- To use Play 2.1 to the full, you need to know Scala well.
- Need to quickly write a web application in Java? Take Play 1.2.x. Or Grails. Groovy is not as difficult to understand as in Scala.
- You need to learn Scala. It is to study, because the differences from Java and even Groovy are very significant.
- Java is almost hopelessly behind other programming languages. Getting back to writing code in Java only after starting to enjoy functional programming is very hard. Maybe Java 8 will save the situation.
[1] - to be honest, integrating Spring into Play 2.1 is possible, it
doesn't even
look very difficult . Those. Spring Data JPA and other projects from Spring Data can theoretically be added, but I haven’t found specific examples and articles on this. At the very hands, too, did not reach.
[2] - during the preparation of the article, he discovered that for Java EE 7, the Java API for JSON Processing should be implemented. Judging by this
post in the blog of Oracle, it will be more convenient and better than the given example. Close enough to JSON support in Groovy. Only this in the future.