With the thaw in the Cold War that erupted between Sun and Microsoft in 2000, and Microsoft’s embracing Java as a tool for building applications on top of Azure, attitudes in the .NET-leaning camp have changed somewhat significantly toward Java. When combined with the simple fact that Java has been a staple of the enterprise world for close to two decades, it seemed time to pull out the ol’ language passport, dust it off, and wander on over to the land of Java for a while.

Before I get too deep into this, however, let’s be clear about one thing; given the Java language’s syntactic and semantic similarity to C#, the purpose of this article is not to spend a ton of time on the Java language itself. As a progenitor and influence on C#’s design, as well as an extremely popular (in terms of books and articles) language, it seems a reasonable assumption that most readers of this magazine have some degree of familiarity with the language already; barring that, Java and C# are so similar, even readers who’ve never set one foot in the Java world will find the language easy to pick up. (As one friend of mine put it, "Java’s just like C#... if you took all the interesting parts out.")

What also needs to be clear is that the Java ecosystem is easily as large (or larger, by some measurements) as the .NET one, and to try to cover the entirety of the Java ecosystem in one article is laughably impossible. The goal here is to get some major points laid down: Get Java onto your system, build some simple applications to show off a bit of the language, and then build a simple HTTP API endpoint using Spring, a deeply popular open-source set of frameworks and associated tools that have been a staple in "enterprise" Java development for over a decade. (Spring currently is owned and maintained by Pivotal, the cloud company that recently joined the .NET Foundation.)

Along the way, I’ll talk about some of the Java platform’s history. More so than any other contemporary language/platform, and thanks to the complete lack of a strong central benevolent dictator figure (like Guido for Python, Matz for Ruby, or Microsoft for .NET), Java wasn’t "designed" as much as it "evolved" into what you see today, making it largely defined by its history: Decisions that today seem strange and almost irresponsible look far different when viewed from the timeframe in which they were made.

Most of all, however, the goal here is the same as any week-long excursion within a foreign land: Get a taste of the culture, hit the tourist highlights, maybe pick up a tacky T-shirt or two, and head home exhausted, making promises to return for a longer visit next time.

Shall we?

Installing

The first step toward "writing once, running anywhere" is to get a Java Development Kit installed on your system of choice.

Historically, the best way to do this was to download the JDK from Sun (now Oracle); however, thanks to some odd choices on Sun’s part, that’s never been an open-source friendly option. In more recent years, an effort to create an open-source-friendly version of Java has yielded an almost-the-same-thing-JDK called the OpenJDK. For the most part, these two implementations are identical, the differences lying in those parts of the Sun/Oracle JDK codebase that still use non-OSS-licensed code (mostly fonts and audio/video codecs). If the open-source distinction matters, or if you’re not really sure why the license should matter and you just want to explore and play, pull down an OpenJDK installation from http://jdk.java.net/ and unpack. Otherwise, wander on up to the Oracle Java website (http://www.oracle.com/technetwork/java/javase/downloads/index.html) and download the installer for your OS of choice. As of this writing, the latest release version of Java is Java 10, with Java 11 under development, but that brings up the first little diversion.

In the early days, Java and the JDK had some slightly different naming conventions; the first version of Java was called, of course, 1.0, and the one after it became 1.1. After that, however, the next version was called Java 2, owing to a hasty Sun Marketing rebrand; scuttlebutt suggests that the name was supposed to be Java 2000, to compete with the forthcoming Windows 2000, but Sun employees reacted so negatively that marketing trimmed off the last three zeroes to call it Java 2. Three different editions of Java bear that Java2 nomenclature as Sun started to diversify Java from the core bits (Java2 Standard Edition, or J2SE) into the enterprise (Java2 Enterprise Edition, or J2EE) and mobile (Java2 Mobile Edition or J2ME). Unfortunately, this created a ton of confusion for the next decade, as each version of the Java2 software development kit was given its own number: the initial release of the Java2 SDK was called J2SE 1.2; the one after that, J2SE 1.3, and then J2SE 1.4. It wasn’t until JDK 1.5 that the name was finally bumped to Java 5, but the JDKs still had their own version numbers; Java 5 was JDK 1.5, and then JDK 1.6, then Java7, Java8, and so on.

Meanwhile, the 2 was dropped from the various names, so Java2 Enterprise Edition became simply Java Enterprise Edition, or JEE; habit being a hard thing to break, however, many Java developers continue to call it J2EE, so don’t be too surprised if you run across that name while out here in the Java islands. Complicating matters even further, J2EE is essentially nothing more than a pile of specifications to which J2EE-compliant implementations conform, and, just to complete the hat trick, J2EE and JavaEE versions were done separately from JavaSE, so the current version of JavaEE is JavaEE 8, even though JavaSE is at version 10.

Why all this versioning nonsense? In part, it was because Sun was trying very hard (some say too hard) to set up an ecosystem in which everybody had a level playing field, and partly because Sun was a company run by engineers. At the time, the distinction between JavaSE and JavaEE was touted as a strength—compared against .NET in particular and its monolithic installation practices—but the price has been a little steep for those getting started. Simply think of it as a charming anachronism carried over from the good old days.

If you are fond of package managers, there are a couple of options, depending on your operating system of choice. For either macOS or Linux, use Homebrew or the Linux package manager (apt on Ubuntu, for example) to install the OpenJDK, because that’s "open-source friendly" and doesn’t require manual acceptance of the Oracle license agreement. For Windows, there are several options, including Scoop (https://scoop.sh/) or Chocolatey (https://chocolatey.org/), but my current favorite option is to run SDKMAN (for SDK Manager) under a Bash shell in the Windows Subsystem for Linux (WSL) on Windows 10. Getting WSL up and running is a little out of scope to this article; see (https://docs.microsoft.com/en-us/windows/wsl/install-win10) for details.

Once WSL is up and running, fire up a Bash shell, visit the SDKMAN website (https://sdkman.io/), run the indicated command in the Bash shell and use SDKMAN to install Java. SDKMAN also works quite well inside of a Cygwin shell, or MinGW, if you’re a fan of those tools. Or, if you really just don’t want to put anything extra on your computer, there’s running Java in a Docker container (docker run -it openjdk:10, for example), or even creating a virtual machine in the cloud; both Amazon and Microsoft have Java-based cloud virtual machine images that are easily accessible, installable, and runnable within their respective cloud environments.

Note that any of the JDK installations only contain command-line tools (javac, java, jar, etc.). It has been a staple practice of the Java ecosystem for two decades now that the tools should remain entirely command-line, and any sort of extra functionality (like, you know, an editor) should be the developers’ personal choice. In fact, this is a common theme throughout the Java ecosystem: a marked preference for standards and conventions, rather than an umbrella installation including IDE, project templates, and so on (such as what you get when you install Visual Studio). Whether this is a pro or a con is certainly open to debate (hint: it’s both), but if you’re looking for the closest to the Visual Studio experience, you’ll want to visit the JetBrains website and download IntelliJ IDEA, Community Edition (https://www.jetbrains.com/idea/download/) and install that. Note that many of the Java tools and environments—particularly when you get closer toward deploying code—expect a command-line environment, or at least familiarity with where the various JDK pieces are installed but installing the IDE can be an easier way to get up-and-running quickly.

Hello, Java

Once Java is installed, you should be able to run the Java compiler from a command-line terminal of your choice with:

javac --version

It responds with the latest version of Java. In many cases, particularly on Windows, it may be necessary to add the bin directory of the JDK installation to the PATH, but before doing that the simple way, take note: Many Java tools (which are also often command-line driven) expect an environment variable, JAVA_HOME, to be defined and pointing to the root of the JDK. Thus, it’s often a better idea to set up a simple batch file that defines JAVA_HOME, then adds Java to the PATH by use of JAVA_HOME, like so:

@ECHO OFF
title JavaSE10 Prompt
set JAVA_HOME=C:\Prg\openjdk10
set PATH=%JAVA_HOME%\bin;%PATH%
java -version

This way, you have complete control over the environment variables. Note that on Windows, if you use the Oracle installer, historically it installed two things on your system: the Java Runtime Environment (JRE), which is all the bits necessary to run a Java application, and the JDK, which is all the bits necessary to build a Java app. The Oracle installer puts the JRE under C:\Program Files, and that’s often what’s installed on the PATH for you, which means you can run Java, but you can’t build it. Taking an extra second to make sure you know where things are installed and what’s in what location can save a ton of time later.

Basics

Let’s take a second to play with the command-line tooling. Create a project home directory somewhere on your filesystem, call it hello, and put a subdirectory called src in it. In the src directory, create a file Hello.java, and put the following into it:

package com.newardassociates.demo;
public class Hello {
    public static void main(String... args) {
        System.out.println("Hello, world!");
    }
}

You compile this using the javac utility, so while in the hello directory, enter the following into your terminal window of choice:

javac -d classes src/*.java

The -d parameter indicates a target subdirectory into which the compiled code will go; unlike .NET, Java doesn’t create a single output artifact. Instead, owing to almost two decades’ worth of history, Java produces a collection of .class files, on a (nearly) one-to-one basis with the source files. However—and this is where things get really interesting or awkward, depending on your point of view—the generated class files are placed into subdirectories corresponding to the package declaration at the top of the source file. Because the Hello code is in the com.newardassociates.demo package, the classes directory contains a subdirectory called com, which contains newardassociates, which contains demo, which contains the Hello.class file. For this reason, source files typically follow the same directory convention; this means that were this a traditional Java project, the Hello.java file would’ve been in src/com/newardassociates/demo, in direct correlation to the package statement.

To run this, you need to point Java at the location of the compiled code, commonly known as the class path. In the earliest releases of Java, this was defined using the environment variable CLASSPATH but this quickly became untenable, and instead you choose to pass it in when you run the code. Running Java code is done using the java launcher, which bootstraps the JVM into memory and then runs the main method of the class name (not the file name) passed in at the command-line, like so:

java -classpath classes com.newardassociates.demo.Hello

[Note: Due to the constraints of the printed page, many lines of code that aren’t normally broken might be broken in odd places in this article.]

This, of course, produces the traditional greeting to the console. Take note, again, that the entry point is specified by the classname passed on the command-line; for a time, it was common for every Java class to have its own main method, which was used to unit-test the code in that class until more sophisticated unit-testing tools (like JUnit) came along.

The deployment story here is a mess—copying a whole directory tree of .class files around. For this reason, Java developed the JAR (Java ARchive) file as a single-file artifact. Creating one requires the use of the jar command-line tool, and a manifest file to specify the entry point (the Main-Class). Assuming the manifest.txt file contains the following name/value pair:

Main-Class: com.newardassociates.demo.Hello

Then you run the following from the command-line:

jar -c -v -m manifest.txt -f hello.jar -C classes/ .

This produces the hello.jar file, which you can then run from the command-line using Java’s -jar parameter:

java -jar hello.jar

This produces the expected greeting.

Build Tools

If all this sounds ridiculously complicated, welcome to the world of Java in 1997. In the beginning, when Java was first thought to be something for building embedded systems (such as the cable set-top box for which it was originally designed), the whole process was relatively acceptable, but as Java moved into the world of the Web, this was obviously not going to fly for long.

If all this sounds ridiculously complicated, welcome to the world of Java in 1997.

Thus, it should’ve been no surprise when the nascent Java open-source community created tools to solve this problem.

The original tool was called Ant (short for Another Nifty Tool), built to make it easier to build Tomcat (which I’ll get to in a second), and it used XML as a descriptor format to describe the structure of the project and specify which steps should be run in which order and which depended on each other. (Remember, back in the late 90s, we were all excited about XML for, well, just about everything.) The originator of Ant, James Duncan Davidson, has since admitted that the main reason for using XML was to save himself the hassle of writing a custom parser. Fortunately, Ant came with a ton of plug-ins that could be repurposed, and the build-tool explosion had begun.

The next build tool, Maven, went one step better than Ant in that it created on online repository of build artifacts, including both libraries and stereotypes (project templates) that could be downloaded automatically rather than by hand. The Maven build structure was all XML again, and if anything, it was more verbose than Ant’s. Around this time, some of the alternative languages for the JVM (Groovy, Scala, Clojure, to name a few) began to emerge, and each began to build their own build tools. One, incorporating Groovy into the build language itself, called Gradle, has built a following, and has since been adopted by Google to be the build tool of choice for building Android applications.

If you drop a Gradle file to do all that I’ve described (compile source, assemble into a JAR file) into the project root directory, it looks like this:

plugins {
    id 'java'
}
group 'com.newardassociates.demo'
version '1.0-SNAPSHOT'
jar {
    manifest {
        attributes 'Main-Class':
            'com.newardassociates.demo.Hello'
    }
}
sourceCompatibility = 1.8
repositories {
    mavenCentral()
}

By running gradle jar, all of the necessary dependencies (if any) are downloaded from Maven Central (the online repository of Java libraries), the code compiled, and the JAR file assembled in the build/libs directory off the project home. If you’re following this at home, by the way, you may need to download Gradle before this will work; package managers make this easy, so (for example) in SDKMAN grabbing Gradle is one command: sdk install gradle. Once installed, however, Gradle can generate a wrapper script that bootstraps the Gradle download so any future developers won’t need to do that initial step.

Enterprise

What put Java on the map wasn’t its impressive array of build tools but its place in the enterprise. Widely regarded to be the king of the enterprise today, Java certainly didn’t start that way. It largely earned that distinction because it made building Web applications easier than its competitors of the time—Microsoft ASP, ColdFusion, or (shudder) CGI-bin Perl scripts—and had better access to the relational databases that define the core of what it means to be enterprise.

Bear with me for a moment while I fast-forward through about a decade of history.

Databases

For data access, the engineers at Sun realized that getting Java to talk to a relational database was clearly a high priority, and as far back as Java 1.1, they introduced a standard API for accessing the RDBMS called JDBC. In many ways, JDBC was constructed in the same manner as its Microsoft cousin ODBC, in that JDBC itself only specified interfaces, and driver vendorsprovided implementations of those interfaces that knew how to speak to the RDBMS in question. One of the first provided drivers was a reference implementation that allowed JDBC to make use of an ODBC driver, which effectively allowed Sun to bootstrap the enterprise Java story, because almost every database then had an ODBC driver, thereby allowing Java developers to access data. Because the JDBC-ODBC driver wasn’t all that fast, it wasn’t long before database vendors were peppered with requests for better drivers, and before long, all the major database vendors had JDBC drivers available, sans one: Microsoft SQL Server. (Go figure.)

The JDBC story, however, was the first successful salvo in vendor neutrality. This was the idea that Java developers could write code that was somehow vendor-agnostic so that a developer’s code would never be "hostage" to a (database) vendor seeking to exploit the cost of rewriting code by moving to a new vendor. Should Oracle show up one day and demand a million (new) dollars just to hook their database up to the Internet (true story), Java developers could simply pivot the JDBC driver they were using and start using MySQL. Or Postgres. Or any of a dozen other options (in theory). It was largely for this reason that Java developers constantly eschew the use of stored procedures in the database, regardless of whatever benefits might be had from doing so.

Naturally, over time, developers started experimenting with how to represent objects in a relational database, with one of the more popular efforts being the Hibernate project. Various groups sought to standardize the object-relational mapping effort, and eventually settled in on a specification called JPA (Java Persistence API), although it’s nowhere close to being dominant. Several different data access layers—all of which use JDBC as their principal means to connect to the database in question—are all currently in widespread use.

But where Java truly solidified its hold in the enterprise was on the Web.

Servlets

The core of the Web story rested on an idea that Sun called servlets—Java classes that could "plug in" to a Web server, respond to an HTTP request, and hand back a formatted response. This wasn’t revolutionary, per se, but Java offered a nice sweet spot between performance and development speed, and the Java language syntax was more approachable to the C++ developers to whom it was pitched. On the backs of this humble beginning was Java’s enterprise empire built.

Servlets are designed to run inside servlet containers, which originally meant a plug-in to an existing commercial Web server like IIS or Apache. Sun needed to produce a reference implementation of the servlet specification and quickly built one that was code-named Tomcat. Over time, as people began to realize that a Web server really wasn’t all that big an implementation problem to solve, the roles flipped, until Tomcat became one of the open-source Web servers of choice and the staple of Java enterprise server farms.

One important development in the Java Web space was the growth of several open-source Web presentation-layer technologies, including the later-standardized Java Server Pages (JSP), and the growth of Model 2 applications, later called MVC: a servlet took an incoming request and processed it (Controller), interacting with a set of domain objects that usually knew how to be persisted to a database (Model), and then the request was forwarded to a JSP page to display the results (View).

Naturally—this is the Java space and there’s always a competing opinion—several other flavors of MVC-based frameworks emerged, such as Struts, Tapestry, and a few others to boot. Although there was never anything by way of a consensus, the JSP/servlet combination powered a great number of applications for quite some time. More importantly, all of these competing frameworks could all be deployed into the same servlet container because at their heart, they all rested on top of the servlet specification, making Tomcat a common server of choice and simplifying the deployment story by standardizing on a WAR (Web ARchive) file format for deploying Java Web applications. By creating a common infrastructure story, the Java community ensured that opinions could diverge quite a bit without having to start over on the infrastructure, servers, and tools.

The servlet specification itself is pretty simple: Extend a base class, override one of the various HTTP-verb methods (doGet, doPost, and so on), each of which take a request object and a response object, and write the results to the response object’s buffer, and off you go. In and of itself, it’s not particularly interesting, or, to be more accurate about that, not particularly interesting to those who’ve seen ASP.NET or Node’s ExpressJS framework. (In many ways, the design of the servlet concept stood as a template for others to follow—and improve.) For those who’re seriously interested in seeing what a Hello World servlet looks like, have a look at the Tomcat documentation, in the section labeled "Application Developer’s Guide" (https://tomcat.apache.org/tomcat-9.0-doc/appdev/index.html).

What’s important to realize from the Web discussion is that Java grew to embrace the idea of standards over implementations, at least to start. Over time, as we struggled to build enterprise applications, we discovered that embracing standards over implementations carried with it a development-time cost too high for the corresponding benefits (if any) that doing so granted us. What was worse, applications written to the standards often weren’t nearly as implementation-portable as we’d thought they would be, leaving us to drown in a sea of complexity for little added benefit.

To a lot of developers, winter wasn’t just coming, it was here. Enter Spring.

Spring

Originally, the Spring framework was a singular framework, designed to act as a container of other objects, called bean (as in, Java beans, get it? No, really, that’s the truth, that’s why they’re called that. Don’t hate the player, hate the game). Via some simple method interception tricks, the Spring container could provide certain kinds of behavior as calls came in to the beans and went back out again, similar in concept to what the commercial implementations of EJB were doing, but with far fewer restrictions and with far better portability. In essence, developers wrote their code to be Spring beans, and the Spring developers worried about how Spring would live inside of a commercial container.

(It was around this timeframe that aspects and aspect-oriented programming, or AOP, took the Java world by storm, as that was the heart of what and how Spring was able to provide much of its behavior, and Spring doubled down on AOP when they acquired the principal AOP language, AspectJ. Although some of the aspect-oriented mentality would later reach the .NET community, aspects were never as widely adopted in .NET as they were in Java. Whether this was a good thing or a bad thing is still hotly debated within both communities.)

Spring quickly established itself as something of the de facto standard for Java. The principal maintainers of the Spring codebase quickly formed a consulting company (SpringSource) and began working on a number of different related frameworks, until Spring reached a level of complexity on par with the very JavaEE standards it sought to replace. The core Spring framework begat SpringMVC (an MVC framework on top of servlets), SpringData (for doing data access), SpringBatch (for batch-style processing, typically asynchronous in nature), SpringSecurity (just what it sounds like), and so on.

As Spring got more complicated, configuring a Spring application became even more so. Trying to track which libraries and which tools were in use or were necessary on compilation command-lines became almost as much of a nightmare as using the original JavaEE stack. The Spring team, therefore, decided to look for a way to get all of Spring under one (conceptual) umbrella, and the Spring Boot project was born, and (as of this writing) serves as the best way to get started using Spring.

Spring Boot

Let’s assume that your interest is in getting a Spring Boot project up and running, and because this is a greenfield project effort, you want to build an HTTP API endpoint that will do the classic HTTP API endpoint thing: provide CRUD access in the form of JSON input and output against a relational database. (This is, largely, the hello world example of the enterprise world, but it’s a useful way to get started working with any enterprise full-stack Web stack, whether Java’s or anybody else’s. Once this works, it’s usually not difficult to customize and expand a server-side API from here.)

To begin, you’d like to File|New a project, but Spring has a different way to get that started; rather than try to maintain three separate IDE project templates (one for IntelliJ IDEA, one for Eclipse, and one for NetBeans), the Spring team decided to go with a slightly different approach, one that they call Spring Initializr. (Yes, the "e" is missing.) This is an online service that can be used to help create an initial project template with all the dependencies already in place, generating a build script that will mostly never need to be touched again once configured, assuming all the dependencies are known ahead of time.

Using Spring Initializr takes one of two forms: either install the Spring CLI via the package manager (sdk install springboot) or head up to the website http://start.spring.io and fill in the missing fields. Because the website makes it a little easier to visualize, use it; if you’re not already looking at it in a browser, bring it up.

To keep things simple (or at least as simple as you can, anyway), choose to build a Gradle Project, with Java, and using Spring Boot 2.0.3 (which, as of this writing, is the latest non-beta version). The Project Metadata is critical to making sure configuration values and source code gets defined and declared correctly; the Group is the package prefix you want to use for all the source code generated, and typically it’s a reverse-DNS name, like com.newardassociates or something similar. The Artifact is going to be the name of the application itself, which in this case, let’s call helloworld.

Note that the Dependencies section is just a text-edit field, which is great if you already know what you need to add but doesn’t help much if you’re not sure what the options are. Fortunately, underneath the big green Generate Project button (don’t push it yet!), there‘s a hyperlink to Switch to the full version, and clicking it yields a long list of all the possible starter dependencies for Spring Boot for easy selection.

It’s a really, really long list.

Before you finish with Spring Initializr, take a look at what’s available. There’s support for just about every database you can imagine (plus a few you haven’t heard of before), both relational and non-relational, there’s a variety of different Web framework support (depending on whether you want a traditional or reactive style app), there’s support for four different templating engines (for defining views used in a Web app), and there’s some cloud support—including easy Azure support, as well as AWS or GCP.

I can’t explore them all in these pages, so let’s stick with the basics for now: check Web (for basic Web support, which includes JSON), JDBC (so you can make use of a JDBC driver to access relational data) and H2 (which is an embedded database written in Java, frequently used for demos because it requires pretty much zero initialization). Click the Generate Projectbutton, and Spring Initializr sends you a helloworld.zip file containing the scaffolding for this new Web app.

Once it’s finished downloading, explode the ZIP file somewhere on your hard drive and take a look at what’s inside.

Project Contents

To start with, you’ll see a build.gradle file, which, if you’ll recall, is the core build file using the Gradle build tool. It’s actually not that much more complex than the one I showed you earlier, but in truth, you don’t really need to look at it; in addition to masking and hiding a whole bunch of options you don’t need to worry about, it doesn’t list all of the possible things you can do with it. The best way to see that is to use Gradle to list all of the tasks it can find (both explicitly and implicitly defined), which is done by running gradle tasks.

(Notice the presence of the gradle.bat and gradle shell script files? Those are the wrapper scripts I mentioned earlier, which pull down and install Gradle onto your computer if it’s not already present. These should never be modified by hand but should be checked in to source control simply on the grounds that it helps new developers get up-and-running more quickly.)

The gradle tasks output lists about a dozen or so possible options (and that’s not the full list; run gradle tasks --all if you really want to be overwhelmed), but the one you care most about is the one at the very top of the list, called bootRun. (Note that there’s also a bootJar option; that’s different.) The bootRun task is particular to Spring Boot and runs the Spring Boot application locally; in other words, this is our F5 option outside of the IDE.

The rest of this directory is mostly configuration and your principal concern lies elsewhere, in the src directory. Within that, you see an immediate split between main and test; as might be guessed, the test directory is where unit-test code should reside, so that the build can compile and execute—but not include in the final deployment artifact—the test code for this project.

Unit-testing a Java project is generally considered a bare-minimum-hygiene sort of practice, and unit-testing frameworks in Java are similar enough to their .NET cousins that if you’re a unit-test aficionado, you’ll have no problem adjusting; if you aren’t, then you probably wouldn’t be convinced to start here, either. (And you should feel bad. Like, really, really bad.)

Within each of the main and test directories lies one more level of distinction, and that’s the language in question in which the source is written. Because you chose a Java project to be generated, main will have a java subdirectory; had you chosen Groovy or Kotlin (two other languages for the JVM), those directories would have appeared here. In many respects, the Java community has done an excellent job of reconciling different languages to first-class-citizen status on the JVM, and Spring wants to be equally accessible to any of them, even inside the same project.

Sitting next to the Java directory is another one called Resources. In here, you can drop non-code assets, like configuration files, graphics files, or other resources. Spring Initializr has already created two placeholder (empty) directories within resources, one for static assets and another for templates (which are usually views). In the root of the Resources directory, you’ll find an application.properties file, which is the standard base configuration file for this application.

(Another bit of history: Since Java 1.0, Java has had a Properties class, extending the Hashtable class, that knows how to read and write itself from and to disk. It’s been the staple for Java configuration since that time, and by convention, those text files are always suffixed as .properties.)

Keep a virtual thumb on the application.properties file; you’ll be coming back to it when you add a few configuration options later. For now, though, let’s get some code going—just a simple HTTP endpoint that hands back an incrementing counter and says (what else?) "hello" to whomever is invoking the endpoint.

Code

In src/main/java/com/newardassociates/helloworld/HelloworldApplication.java, there’s a main() method that turns right around and asks Spring to execute the application. This is largely a placeholder for when you want to run the Spring app with an embedded HTTP server, as opposed to building the app to run inside of a standalone Web server (such as Tomcat). To keep things simple, run it standalone, but if you ever want to experiment with Tomcat, it’s pretty trivial to get Gradle to produce a WAR file that can be just dropped in to a running Tomcat server and deployed.

You need to define an HTTP endpoint, so in the same directory, create a new file, GreetingController.java, and fill it with the following:

package com.newardassociates.helloworld;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class GreetingController {
    private static final String template =
              "Hello, %s!";
    private final AtomicLong counter =
              new AtomicLong();
    @RequestMapping("/greeting")
    public String greeting(@RequestParam(value="name",
            defaultValue="World") String name) {
        return String.format(
            template, counter.incrementAndGet());
    }
}

Much of this is conceptually similar to ASP.NET MVC (or similar frameworks from Ruby, Python or Node); you use Java annotations (the @-prefixed names) to provide some custom metadata that Spring consumes to know how to map this class against an HTTP endpoint (/greeting), in this case. Rather than holding the counter in a standard int, you protect against concurrency by using the java.util.concurrent.atomic.AtomicLong class, which guarantees thread-safety when incrementing a long value, even when being done simultaneously. (Only one instance of GreetingController is instantiated to process multiple simultaneous requests, so this is of some concern.)

Kick off gradle runBoot and Spring starts listening on port 8080. Note that your terminal window fills with a ton of log messages, many of the form 2018-07-25 00:19:16.800 INFO 3373 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]". This is standard Java logging, and the o.s.w.s. that you see above is a shortened package name. Because Java packages can often nest five or six levels deep, logging frameworks often reduce the first parts of the full package name down to just the first letters. (The reverse-domain-name convention was a good idea for a while, but once it became commonplace to have packages nested eight levels deep, it lost some of its luster.)

The reverse-domain-name convention was a good idea for a while, but once it became commonplace to have packages nested eight levels deep, it lost some of its luster.

If you browse to http://localhost:8080/greeting, you’ll see the generic greeting; if you tack ?name=Fred onto the end of the URL, you’ll see a custom greeting to Fred, and the counter increments on every invocation. Yay!

But this is still pretty trivial, and something that could’ve been pretty easily done with a simple Java servlet. Where does Spring add value?

Data Access: JDBC

As with most frameworks of its type, an application doesn’t really benefit from the power of Spring until it reaches a certain level of complexity; simple things are usually simple to do and don’t require any additional help. Data access—that is, retrieving and storing data in a database—is one area where Spring can help keep the cognitive load lighter, particularly as the application scales up.

As an example, let’s assume that I’m deciding to take my college class with me on a trip to a foreign country, perhaps to a conference like Devoxx Poland (http://www.devoxx.pl, which is a great Java show, and that’s before I even begin to talk about Polish vodka). I obviously need a database! I need to store student names and passport numbers, so that I can make sure that they all have passports and…stuff. (I’ll make sure to send out a change to my privacy policy at the end of the trip.)

For starters, I’ll need a domain class to track a Student; in Spring parlance, this is a bean, and it’s a POJO: Plain Old Java Object. As you can tell from the code in the next snippet, Java lacks several language features that would’ve made this code shorter (like C# auto-generated properties, for example):

package com.newardassociates.helloworld;
public class Student {
    private Long id;
    private String name;
    private String passport;
    public Student() {
        this(0, "", "");
    }
    public Student(String name, String passport) {
        this(0, name, passport);
    }
    public Student(Long id, String name,
                  String passport) {
        this.id = id;
        this.name = name;
        this.passport = passport;
    }
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    public String getName() { return name; }
    public void setName(String name) {
              this.name = name; }
    public String getPassport() { return passport; }
    public void setPassport(String passport) {
        this.passport = passport; }
    @Override
    public String toString() {
        return String.format(
                  "Student [id=%s, name=%s, passport=%s]",
            id, name, passport);
    }
}

Oh, that reminds me. You’ll need a database schema to go along with this. Here’s where Spring starts to earn its keep. Drop a file named schema.sql into src/main/resources, that looks like this:

create table student
(
   id integer not null,
   name varchar(255) not null,
   passport_number varchar(255) not null,
   primary key(id)
);

And then drop another file, data.sql, to prepopulate the database with some values, like this:

insert into student
values(10001,'Amy', 'E1234567');
insert into student
values(10002,'Ruby', 'A1234568');

Now re-run the application with gradle bootRun. Somewhere, in the middle of the log messages, you’ll see that Spring picks up on the two SQL files as resources, and automatically executes them. (Because why else would they be there?) The log messages will look something like this:

2018-07-25 02:47:48.379 INFO 4304 --- [ main] o.s.jdbc.datasource.init.ScriptUtils : Executing SQL script from URL [file:/mnt/d/Projects/ helloworld/build/resources/main/schema.sql]
2018-07-25 02:47:48.388 INFO 4304 --- [ main] o.s.jdbc.datasource.init.ScriptUtils : Executed SQL script from URL [file:/mnt/d/Projects/ helloworld/build/resources/main/schema.sql] in 8 ms.
2018-07-25 02:47:48.390 INFO 4304 --- [ main] o.s.jdbc.datasource.init.ScriptUtils : Executing SQL script from URL [file:/mnt/d/Projects/ helloworld/build/resources/main/data.sql]
2018-07-25 02:47:48.391 INFO 4304 --- [ main] o.s.jdbc.datasource.init.ScriptUtils : Executed SQL script from URL [file:/mnt/d/Projects/ helloworld/build/resources/main/data.sql] in 1 ms.

Of course, a reasonable question to ask at this point is "With what database?!?" Such is the power of the H2 database. It’s an in-memory, mostly-SQL-92 compliant relational database that frequently serves as the database of choice when doing demos and early prototyping.

As a matter of fact, quit the running app, then add the following to the contents of the application.properties file from earlier:

# Enabling H2 Console
spring.h2.console.enabled=true

The # character starts a comment and the line after it sets the spring.h2.console.enabled property to true. As the name implies, this turns on an in-memory console for interacting with the H2 database, which you can reach by pointing the browser to http://localhost:8080/h2-console . Behold! A tiny SQL console for interacting with the in-memory database. However, the console needs to know how to connect to the H2 database (there could be several), so you use the correct form of JDBC URL to describe the in-memory test database: jdbc:h2:mem:testdb.

This is, in all ways, shapes, and forms, a legitimate URL: jdbc is the scheme of the resource described, and will always be present in any JDBC URL, just as http or https is always present in any HTTP URL. The second portion describes which JDBC driver should be used to do the connection, and h2 corresponds to the H2 driver. (Microsoft SQL Server’s driver descriptor is mssql or mssqlserver, MySQL’s is mysql, and so on.) After that, the contents of the URL are entirely driver-specific, and in the case of H2, mem says it’s an in-memory database (as opposed to being written to disk in plain text files), and testdb is the name of the database in question.

If you use the H2 console to connect to jdbc:h2:mem:testdb, it’ll show the STUDENTS table in the left-hand drop-down, which proves not only that you’re connected to the correct database, but also proves that Spring executed the DML in schema.sql from the resources. Nifty.

Accessing the database from the code should be pretty easy, too, right?

Data Access: Repository

In keeping with the Java philosophy that there should never only be one way to accomplish something, Spring offers several different persistence libraries to support whichever approach makes the most sense. Personally, I’m a fan of doing just straight SQL against the database, usually through a class designed to encapsulate details away (the Repository pattern), but this usually suffers from a certain amount of overhead: a Connection object has to be forged out of somewhere, and from there a Statement object has to be created with the SQL in question, then executed, then the results harvested out of the ResultSet that’s returned, and so on. All of this is fraught with the knowledge that the database could (if the network gods are feeling capricious) disappear at any time and therefore you need to handle connection errors. That’s a ton of code to have to write for each SQL statement.

Spring to the rescue! Spring provides a JDBC template class that can handle all of the non-schema-specific parts, so long as I supply the SQL to execute and a class designed to map columns out of the ResultSet into an object instance. Given that this is to fetch and store Student instances, call this class StudentRepository and sit it next to the other Java code, as shown in Listing 1.

Notice the placeholder question marks (?) in the SQL syntax. These are parameterized statements, and they’re your first line of defense against SQL injection attacks. Not optional.

The thrust of the StudentRepository here is mostly providing domain-specific elements for the JdbcTemplate class. A StudentRowMapper understands how to map a SQL ResultSet into a Student object. The Object arrays being instantiated on the fly provide the parameters to the parameterized SQL queries. And so on. All of the rest of the work, dealing with the JDBC API, are buried inside the Spring plumbing, where common-sense defaults (in case of errors) take place to alert developers and clients when things go wrong.

This makes writing the StudentController, which will use the StudentRepository to do all the CRUD work you need, look like Listing 2.

The @Autowired annotation, by the way, tells Spring that it needs to instantiate one of these objects and initialize it as appropriate (from either configuration settings or by using common-sense defaults). And, like most other frameworks of its nature, Spring takes the Student objects handed back from the controller and magically transforms them into a JSON representation suitable for consumption by whatever invoked this HTTP endpoint in the first place.

Voila! You now have a fairly simple CRUD endpoint, wired up against a relational database. Not bad for an afternoon’s work.

Wrapping Up

As I mentioned at the beginning, this is just the very tip of a very large iceberg; the Spring collection of libraries, tools, and frameworks is itself a huge collection of material to wade through, not to mention all of the Java ecosystem. Like the .NET ecosystem, the Java ecosystem is both commercial—Pivotal, the current caretakers of the Spring repositories, being a big player in that space, but obviously also Oracle, Google, and a few other players too—and communal. In fact, in large measure, the open-source world cut its collective teeth on the Java ecosystem, and much of the lessons learned about how to run a large community project were learned the hard way when open source and Java were both coming of age.

Even if Java isn’t something directly in your future, knowing the Java ecosystem provides a tremendous amount of insight and information into .NET and the .NET ecosystem—seeing some of the differences, and seeing some of what’s missing. Case in point: when .NET came out, it introduced the notion of custom attributes, which provide a way for code to provide custom metadata for consumption by a variety of sources (such as ASP.NET frameworks). Having seen custom attributes, and recognizing its usefulness, Java turned around and introduced the same concept, the @-prefixed annotations you saw earlier. The JUnit unit-testing framework then turned around and adopted annotations to indicate methods requiring execution as part of a test suite, which the NUnit framework maintainers saw, liked, and adopted themselves, in turn. Circles within circles, cycles upon cycles, each feeds the other with interesting insights and innovation, and the industry as a whole just keeps getting better.

Circles within circles, cycles upon cycles, each feeds the other with interesting insights and innovation, and the industry as a whole just keeps getting better.

I hope you’ve enjoyed your trip to the Java islands this afternoon, and I hope to see you on a future CODE Magazine flight.