Sunday, April 30, 2017

Spring Data REST

Last week I blogged about doing a RESTful Web Service in Spring.  Towards the end of that post I mentioned that there's another module in Spring Data which can automate some of this work called Spring Data REST.

Following through on that idea, I rewrote essentially the same service here using Spring Data REST.

From what I've seen so far, Spring Data REST helps you in two different ways.  It relieves you of having to write a controller, at least for basic CRUD methods, and it also enables Hypermedia As The Engine Of Application State (HATEOAS).

When I started trying to get my Spring MVC Test Framework integration tests working again, the first thing I noticed was the following test failing:

My test was expecting application/json but it's now returning the HATEAOS mime type application/hal+json.

Spring defines these in the MediaType class.  They don't seem to have one of those for application/hal+json.  I considered just not checking the mime type... But I googled a bit more and found Configuring Spring Data REST and Basic settings for Spring Data REST in the documentation.  I used the following configuration to change the default mime type of the JSON responses back to application/json:

The next thing that was different has to do with the argument to methods which operate on an existing entity.  My original code used a String "name" to identify the entity, but the Spring Data REST methods all use the "id" field.  Here's how I wrote the controller method to get a single entity by name:

But I'm not writing the controllers any more... Spring Data Rest creates a 'GET' endpoint taking an 'id' value, and it also creates one for my findByName() method in the Spring Data JPA repository interface.  Here's my tests for these two cases:

I rewrote the remaining tests to just use the id instead of the name.

One other change was needed... since Spring is now automatically generating a REST endpoint from the findByName() method in the repository interface, instead of me just calling it from the controller method, I needed to give that an annotation to instruct it how to handle the HTTP request parameter as its input:

Spring Data REST strikes me as a huge win for green field development situations where you just drop a dependency in the POM file (or Gradle build file) and, whoosh, instant REST endpoints for all the domain classes.  It might be more problematic to use this in a legacy app where the Spring Data REST endpoints might not match the conventions of the existing endpoints.  Also, the HATEOAS stuff, yeah, it's the semantic web wave of the future, but it is a bit different and might take some getting used to if this is yout first exposure to it.

Friday, April 21, 2017

Java 8

Back around November, I started working problems at Hackerrank.  One of my goals was to learn and get better at Java 8.

Frequently in these problems I had a need to print out an array of integers.

Before we get started in Java, the programming language I've mostly used at work for the last 3 years or so is Groovy, doing application development in Grails, writing Jenkins jobs, and just for general scripting.  Here's how you print an array of integers (int[] a) in Groovy:

It's super-easy and concise.

When I was still working in Java 7, I wrote something like the following code:

Hackerrank sometimes uses huge arrays, like 50K or 200K, so I'm efficiently using StringBuilder.  But the whole thing is super-verbose.  Java 7 lacks anything like the join operator so I'm reduced to implementing it myself, more or less.  There's five lines of code here devoted to adding a space before every character but the first.  The Groovy solution is so concise, it hardly makes sense to write a method for it, but here it would be crazy not to.

Java 8 String.join() finally gives us a string join method like the one I was using in Perl over 20 years ago.  Cool!  Here's the way I was doing this in Java 8 for a while:

That's not bad.  It's a big improvement over Java 7.  It's actually a one-liner, though the line is kind of a long one.  It's basically doing the same thing as the Groovy code, except I need to explicitly shepherd the output through a series of type conversions.

There's still a way to make this a little bit better, though.  In order to come up with the second argument to String.join(), I'm converting my array to a stream, then doing another conversion to get a Collection.  It turns out that the Java 8 team provided a reduce method Collectors.joining() which eliminates the need for String.join().  This makes it possible to do everything in a stream instead of the awkward series of conversions I had before.

And it's a bit more concise, too.

It might be tempting to look at this one example and say 'Groovy wins.'  Well, after all, Groovy is built on top of Java such that the new features of Java 8 are available in Groovy, so, yeah, Groovy does win 😎.

My initial reaction to Java 8 lambdas was 'oh, Java is finally catching up to something Groovy has had since, what, 2007?'  But it's important to understand that streams and the implementation of the filter-map-reduce abstraction implemented by Java 8 is a new thing that didn't exist in Groovy before.  In recent years we've seen a lot of interest in languages like Scala and Clojure which support a functional style of programming in which the creation of mutable state is avoided for the sake of concurrency.  This is what the streams feature of Java 8 is all about, parallelism.

Thursday, April 20, 2017

RESTful Web Service in Spring

I've been spending a lot of time at Hackerrank lately, also getting up to speed on Java 8, but I suddenly realized I hadn't done much with Spring for a while.

So, this is maybe about an 8 hour effort over the course of 2 weeks or so.  It's a RESTful web service for Pokemons.

Writing a RESTful web service in Spring these days is not quite as easy as in Grails, but it's really pretty easy.  I just used MVC and @RestController.

For integration testing I followed the example in Building REST services with Spring.  I had glanced at the documentation for Spring MVC Test Framework before but never really used it, so this part was mostly new to me.  It lets you test MVC requests without bringing up a full Servlet container.

I'm aware of Spring Data Rest.  Here's a pretty good presentation: Advanced Spring Data REST - Oliver Gierke.  I'm getting ready to give this a try but wanted to go through the exercise of doing the REST implementation 'by hand' first.