Java 8 may only have been released a few months ago, but Oracle has already announced the first set of features that will be targeted for Java 9. On August 11th, Mark Reinhold, a Chief Architect for Java, made available an initial feature set to subscribers on the jdk9-dev mailing list.

The crop of features are being run under a relatively new process, known as Java Enhancement Proposals (JEP). This process allows new language and VM features to be prototyped and explored without the full weight of the normal Java standardization process, although the expectation is that suitable, successful JEPs would go on to formal standardization. There will, of course, be many other new features that will be introduced in Java 9, but in this post we are going to focus on two major enhancements — and examine how they relate to features added in Java 7 and 8.

New HTTP Client

The core support for HTTP in Java has not changed much since it was first introduced in Java 1.1 (way back in 1997). This is unfortunate for many reasons, not least of which is that HTTP has come to dominate over virtually every other protocol. This makes the original approach that Java took (which uses URLConnection to support multiple protocols) outdated and unnecessarily complex. The original API is also blocking and only implements HTTP 1.0, making it very expensive in terms of network overhead.

Of course, there have been some improvements in the 17 years since HTTP support was first added. One of the biggest came with Java 7 and the introduction of try-with-resources. This enables us to write code like this:

URL url = new URL("http://www.oreilly.com/"); try (InputStream in = url.openStream()) { Files.copy(in, Paths.get("output.txt")); } catch(IOException ex) { ex.printStackTrace(); } 1 2 3 4 5 6 URL url = new URL ( "http://www.oreilly.com/" ) ; try ( InputStream in = url . openStream ( ) ) { Files . copy ( in , Paths . get ( "output.txt" ) ) ; } catch ( IOException ex ) { ex . printStackTrace ( ) ; }

This snippet is now an extremely compact way to write a simple HTTP client. Unfortunately, the story isn’t all positive. If we want to have more control over the HTTP connection (e.g., by examining some of the headers as well as the HTTP payload), then we can write something like this:

try { URLConnection conn = url.openConnection(); String type = conn.getContentType(); String encoding = conn.getContentEncoding(); Date lastModified = new Date(conn.getLastModified()); int len = conn.getContentLength(); InputStream in = conn.getInputStream(); } catch (IOException e) { // Handle exception } 1 2 3 4 5 6 7 8 9 10 11 try { URLConnection conn = url . openConnection ( ) ; String type = conn . getContentType ( ) ; String encoding = conn . getContentEncoding ( ) ; Date lastModified = new Date ( conn . getLastModified ( ) ) ; int len = conn . getContentLength ( ) ; InputStream in = conn . getInputStream ( ) ; } catch ( IOException e ) { // Handle exception }

This can’t be made to use try-with-resources because the URLConnection class does not implement the AutoCloseable interface, so variables of type URLConnection are not legitimate assignment targets for a try-with-resources clause. So whilst HTTP handling has improved, things are not as good as we might like. In the intervening years, many Java developers have started to use alternative HTTP libraries, such as those provided by Apache. These libraries are better in some respects, but none of them are perfect, andnone — as of the writing of this post — take advantage of Java 8 features (such as lambdas).

With all this in mind, the idea for a new HTTP API in the JDK core libraries seemed an obvious one. Some preliminary work was done as part of JDK 8, but there wasn’t enough time to finish it before the Java 8 ship date. While it would have been nice to have improved support with the current release, delaying until Java 9 means that we should be able to take advantage of the release of the new version of the HTTP protocol: HTTP/2. This major new release of HTTP (previously called HTTP/2.0) is expected to reach its final form by November 2014, in plenty of time for the Java 9 release schedule. We don’t know what the final syntax of the new Java 9 HTTP API will look like, but support for this new protocol is a major goal for the project.

You can find out more and follow the development of the API and supporting code on the JEP Page and the OpenJDK networking support mailing list.

New JSON API

Java has excellent support for XML and web services, but while XML may once have been the data format of choice, it has lost some of its shine in recent years. Instead, the world has increasingly moved towards JSON data delivered by simple web services that adhere to the REST style. In the EE 7 standard, there is some support for this technology. For example, consider this simple web service for initializing sessions with some authentication data:

@Path("session") @Produces("application/json") public class SessionService { private static final Logger logger = LoggerFactory.getLogger(SessionService.class); @POST @Consumes("application/json") public Response createSession(AuthData auth) { long start = System.currentTimeMillis(); logger.info("Incoming: " + auth); final Session session = validate(auth); if (session == null) { return Response.notAcceptable(null).build(); } long end = System.currentTimeMillis(); logger.info("Request took: " + (end - start) + " ms"); return Response.ok(session).build(); } public Session validate(AuthData auth) { if (auth == null) { return null; } // Other validation return new Session(auth); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 @ Path ( "session" ) @ Produces ( "application/json" ) public class SessionService { private static final Logger logger = LoggerFactory . getLogger ( SessionService . class ) ; @ POST @ Consumes ( "application/json" ) public Response createSession ( AuthData auth ) { long start = System . currentTimeMillis ( ) ; logger . info ( "Incoming: " + auth ) ; final Session session = validate ( auth ) ; if ( session == null ) { return Response . notAcceptable ( null ) . build ( ) ; } long end = System . currentTimeMillis ( ) ; logger . info ( "Request took: " + ( end - start ) + " ms" ) ; return Response . ok ( session ) . build ( ) ; } public Session validate ( AuthData auth ) { if ( auth == null ) { return null ; } // Other validation return new Session ( auth ) ; } }

The annotations are quite clear – this is a web service that will reside at a session relative to the application (or WAR file) root. It both produces (sends) and consumes (receives) JSON and expects to receive data via the HTTP POST method. There is some behind-the-scenes magic necessary to configure the mapping from Java objects to JSON, but these mappers are relatively straightforward to write and configure.

That’s all well and good for Java EE developers, but what about projects that are only using SE? Fortunately, Java 8 has a feature that is a huge help. This is the new JavaScript implementation, known as Nashorn. This replaces the older Rhino implementation (Nashorn is German for “Rhino”) with a modern, completely updated version of JavaScript. Nashorn is fully compliant with JavaScript standards and takes full advantage of the JVM. In addition, Nashorn features very tight two-way integration with Java. Let’s look at a simple example of how to use Nashorn to run a snippet of Javascript from a Java program:

ScriptEngineManager m = new ScriptEngineManager(); ScriptEngine e = m.getEngineByName("nashorn"); try { e.eval("print('Hello World!');"); } catch (ScriptException se) { // ... Handle exception } 1 2 3 4 5 6 7 8 ScriptEngineManager m = new ScriptEngineManager ( ) ; ScriptEngine e = m . getEngineByName ( "nashorn" ) ; try { e . eval ( "print('Hello World!');" ) ; } catch ( ScriptException se ) { // ... Handle exception }

This uses the script engine mechanism that was introduced with Java 6. However, it’s possible to run a Javascript REPL (Read-Eval-Print-Loop) on the console so that you can experiment with Nashorn directly. If you have Java 8 installed on your machine, and you have the bin directory of JAVA_HOME on your path, then from the console you can just type jjs and the REPL will come up:

jjs> print("Hello World!"); Hello World! 1 2 jjs > print ( "Hello World!" ) ; Hello World !

This is all well and good, but it’s a fairly simple example. Let’s do something a bit more complex and look at how the integration with Java works. In particular, JavaScript functions are treated as essentially equivalent to lambda expressions. So we can write code like this:

jjs> var clz = Java.type("java.util.concurrent.Callable"); jjs> var obj = new clz(function () { print("Foo"); } ); jjs> obj.call(); Foo 1 2 3 4 jjs > var clz = Java . type ( "java.util.concurrent.Callable" ) ; jjs > var obj = new clz ( function ( ) { print ( "Foo" ) ; } ) ; jjs > obj . call ( ) ; Foo

That’s right – we took a JavaScript function and treated it as a lambda expression that was converted automatically to an instance of Callable. We then used the call() method that was on the resulting object.

Nashorn also provides full support for JSON via the expected parse() and stringify() methods, albeit at the cost of having to use JavaScript code in your programs alongside Java as illustrated below:

jjs> var me = JSON.parse('{"name":"Ben Evans", "details":{"dob":"1976-05-21", "gender":"Male"}}'); jjs> print(me.name); Ben Evans jjs> print(JSON.stringify(me)); {"name":"Ben Evans","details":{"dob":"1976-05-21","gender":"Male"}} 1 2 3 4 5 6 jjs > var me = JSON . parse ( '{"name":"Ben Evans", "details":{"dob":"1976-05-21", "gender":"Male"}}' ) ; jjs > print ( me . name ) ; Ben Evans jjs > print ( JSON . stringify ( me ) ) ; { "name" : "Ben Evans" , "details" : { "dob" : "1976-05-21" , "gender" : "Male" } }

As well as the Nashorn route in Java 8, there’s also been the creation of JSR 353, which was released in May 2013 and was shipped as part of EE 7 (but did not make it into the Java SE 8 standard). Java 9 wants to improve on this by providing a modern, highly efficient API for handling JSON. Oracle hasn’t announced yet whether the new JSON API will build directly on top of JSR 353, but in the meantime, the page describing this new API for the JEP is at: http://openjdk.java.net/jeps/198; discussion can be found on the OpenJDK core libraries mailing list.

Finally, as these APIs are sure to be favorites among Java User Groups, the creation of Adopt groups tracking these evolving projects is more-or-less certain. If you’re interested in participating then watch for an announcement letting everyone know when the group is ready for developers to join and start working with and testing the API as it matures.

Editor’s note: If you can’t wait for Java 9 to hit the streets and want to explore Nashorn, lambda expressions, and the new I/O APIs, check out the newly updated “Java in a Nutshell, 6th Edition” by Ben Evans and David Flanagan.

Public domain coffee roaster illustration courtesy of Internet Archive.