📜 ⬆️ ⬇️

Impressions from working with Play! Framework 2.1 + Java

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:

Controversial moments:

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:
 //  @if(user == null) //  ,    : @if (user == null) 

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:




[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.

Source: https://habr.com/ru/post/173211/


All Articles