In my last blog, I marveled how the dull pain of Java EE stacktraces melted away after I started using the Play framework, where each error was clearly reported with the file name and line number of the offending artifact. Here are some small details that I ran into.
With GlassFish, when your code gets recompiled, “hot deployment” sometimes worked, and sometimes not. That was perhaps worse than if it had never worked, because I first tried not to restart the server, hoping for the best, and then confusing stuff would happen, and I had to restart after all. With Play, it always seems to work just fine. And then, when you try out your code, you get a friendly error message, not a stack trace from hell.
I needed to turn what used to be a web app with HTML forms into a web service. JSON in, JSON out. I started with JSON out, leaving the forms intact. GlassFish uses MOXy for this purpose, and my reason for switching to Play in the first place was some obscure bug in it. Taylor Corey was kind enough to email me with a suggestion to use a GenericEntity
, a workaround that he attributed to Adam Bien:
/** * Get all foods in the food manager. * * @return xml or json of all foods */ @GET public Response getAll() { FoodList foodList = FoodManager.getFoods(); GenericEntity<List<Food>> list = new GenericEntity<List<Food>>(foodList) {}; return Response.ok(list).build(); }
That's good to know. Also, there is a way to switch to Jackson in GlassFish, but I must confess I was utterly confused what that even meant when GlassFish first gave me a Stack Trace from Hell instead of JSON.
Now I know a bit more, and I learned that Jackson is the power tool for consuming and producing JSON, with more configuration options than there are galaxies in the known universe. In my case, I wanted to suppress null values and empty lists from the output. Stack Overflow is awash with advice on how to use Jackson. Here is what worked for me:
ObjectMapper mapper = new ObjectMapper(); mapper.setSerializationInclusion(Include.NON_DEFAULT); mapper.writeValue(destination, data);
Here, data
is a POJO that contains lists and maps of other POJOS, and the whole thing is turned into sensible JSON. Easy as pie.
So, the Play folks are doing the right thing by deferring this task to the best-of-breed library. In Java EE, the same service method can generate either XML or JSON, and I assume this is where MOXy came in. But is this really useful nowadays?
So, since I still had forms for the input part of my service, I needed to test it. I didn't want to port the actual form. That's what cURL is for. And I once again cursed at the cURL syntax for posting forms. Then I discovered HTTPie, which has a sane syntax:
http --form POST localhost:9000/service key1=value1 key2=@file.txt
Easy as pie, again. If you are still using cURL, stop reading right now and install HTTPie.
Unfortunately, I didn't get JSON back, but an HTML page with an error report. Remember how Play is so friendly to always give you an error page with the file name and line number? That's not so good for testing from the command line.
Once again, StackOverflow to the rescue. You can pipe the output into a browser. This post has a clever way of wrapping the output in a data URI, and it looks easy enough to get it to work. But I found bcat
to work out of the box. Install (sudo apt-get install ruby-bcat
in Ubuntu) and run
http ... | bcat
The output shows up in the browser.
Finally, when I fixed the easy bugs, I had to run the debugger. The details must have changed over time, because StackOverflow is awash in conflicting advice, but here is what worked for me today.
In Eclipse, right-click on the project, select Debug → Debug Configurations → Remote Java Application, click the New button, and set the port to 9999.
Start the server with
activator -jvm-debug 9999 run
Then set a breakpoint and click on the Debug button. Call http localhost:9000/service
or point your browser to the URL, and the breakpoint is triggered in the usual way.
Except for one pesky thing. I get this dialog:
It doesn't seem to do any harm, but it is annoying nonetheless. As a general advice, not specific to Play, StackOverflow tells me to check "Add line numbers to generated class files" in the compiler settings. But that's already checked. The problem is that I don't know who actually does the compiling. Is it Eclipse? Is it the activator
? Both? This is not the only rough edge that I have experienced with Eclipse and Play, so that's definitely something to be concerned about. Or maybe I should just switch to IntelliJ, since I am replacing every other part of my toolkit anyway?