Java and JSON
Recommended Reading
Java And JSON
So, it turns out that Java and JSON don't interract well without an intermediary product to help with communication. This isn't a surprise, just a fact that applies to many non-JavaScript language. JSON has been in existence since 2002, and has effectively replaced XML as the data format for transferring data on the web. The first generation of web services used XML, but programmers wanted something more efficient to pass data with, and JSON eventually won out. Not only did it work with all languages (like XML), but it was also easily readable my man and machine (and XML often isn't human readable).
Now it is true that Oracle finally released JSR 353, which is the Java API for JSON processing. Unfortunately, they were a bit late with the release, and several other groups came up with their own Java-JSON solutions. All of them work, some better than others, but unfortunately each has their own API, which means there are implementation differences with each group's release. While there are several open source APIs that support communication (GSON (Google), JSON-p, JSON.org and MOXy (Eclipse), we will use the FasterXML/Jackson API from https://github.com/FasterXML for this brief intro as it is a popular solution that works well.
What this API does for us, in marshall ojects to an from JSON to Java. Data binding comverts JSON to plain old Java objects (POJOs) using configrations and annotations. Then it supports generating JSON from configured POJOs in the other direction. It is usefu for serializing and deserializing Java Objects (particularly for web based applications).
Full documentation with tutorials (and more) is available at https://github.com/FasterXML/jackson-docs. This includes a lot of explanation of the annotations used and a nice JavaDocs document for system calls, well, sort of. Turns out, this is the actual html to produce the JavaDocs, not a link to a "working" page of JavaDocs. A little nosing around on the main page, you will find a "Where are the JavaDocs" link, which in turn tells you that the only practical way to get to working JavaDocs is to use the following URL prefix
https://fasterxml.github.io/
Then tack on the package name, the directory "javadoc" and the version. So, for jackson-core version 2.9.9 we would use
https://fasterxml.github.io/jackson-core/javadoc/2.9.9
Yes, somewhat awkward, but it does indeed work, and we will use this later on. Oh, and yes, that is indeed http. Even though the web is going to https, this is one of those rare cases where somebody decided that https really isn't necessary...go figure.
We will primarily be using the DataBind package found at the https://github.com/FasterXML page, with the documentation link shown above on the jackon-docs page. You might notice that FasterXML/jackson has Maven support as well!
Getting and Installing FasterXML/Jackson
You can download what we need from https://github.com/FasterXML. Please note that the ownload page provides JAR files with the necessary libraries, source code and APIs in addition to URLs provided for use with Maven configurations.
We need three library (JAR) files.
Once you download the jar files, place them in the library directories of your project. For something like these JAR files, that you may use in multiple projects, I'd recommend downloading them to a standard intermediate location, then copying them to each project that needs them.
So, now you need to go to the github URL given above and download the latest JAR files. I'll walk through the jackson-core JAR, and you can get the other two yourself.
For jackson-core, we select the link on the main page and then go to the jackson-core page.
You will need to scroll down to look for the following section...
I'm not going to mess wih the Maven option, so we will use the Non-Maven section and go to the Central Maven Repository. Oh, and it seems that they haven't fixed the link to the Central Maven Repository as they still have an https: prefix, and your browser may complain...just manually add the https:// prefix to the link and you should see something like this (note the URL at the top of the page!)
Scroll down and grab the latest version (note that the numbering system is messed up, the latest version might be only half way down as something like 2.13 is listed BEFORE 2.9). When you click on the version you will see another page similar to this:
You can see that the library contain POM files for Maven, source code, javadoc packages, and what we are looking for, the JAR file.
Download it to your intermediate library location. Then do the same for the other two libraries. You should end up with something like this on your local machine.
ObjectMapper
One of the key classes we will be using is the ObjectMapper. This is in the jackson-databind library. So, let's take a look at the javadoc for this at:
https://javadoc.io/doc/com.fasterxml.jackson.core/jackson-databind/latest/index.html
Note that the JavaDoc has a nice explanation as to what the ObjectMapper does, and as with any good JavaDoc, has some use-case example along with the listing of all public and protected attributes and methods.
Now the ObjectMapper class provides the function of converting Java objects to JSON strings and vice versa. Typically, you create an ObjectMapper and then pass in arguments to a read or write method to convert between Java Objects and JSON.
When we take a look at Annotations later on, we can see how we can customize Object Mapping between the Java and JSON objects. You should note that the read/write methods typically throw some common exceptions, most of these are found in the jackson-core JAR.
Annotations
Annotations provide Meta data to control how Java classes map to JSON documents and vice versa. An annotation should be added to either the property in the class or only one of the getter/setter methods on that property. Pick one style and stick with it, if you mix them, you will get unpredictable results. My preference is to put them on the attribute. Some have additional properties that can be set.
And yes, you can look at the detailed JavaDoc on annotations at https://javadoc.io/doc/com.fasterxml.jackson.core/jackson-annotations/latest/index.html
Examples of common annotations are:
We will look at annotations later on in the example code.
Your first Java-JSON program
We will start by creating a simple Java application (not webapp...not yet) to show the functionality of the FasterXML/Jackson library.
If you want to view the completed project, you can find it here at JsonApp.zip rather than creating your own.
Bring up Eclipse and make a new Empty project. I'm going to call this one JsonApp. Click Finish
You should have an empty project at this point
We first want to make a "lib" directory to store copies of the three libraries we just downloaded. Create a new directory and copy the jar files into the "lib" directory.
Now we need to add the three JAR files to the build path for the project. If you right click on the Project Name (JsonApp), you can select the Build Path option which leads you to this sub-menu
Click on Configure Build Path...
We want to "Add JARs.." click on this button and then add the three JARs in the lib directory of this project.
Now we can begin to code our sample application! So, create two classes, Main.java and Person.java. Main will control the program, while Person.java is a Java Beans object that we will use to write to and from JSON strings.
Person is just a simple Java Bean Object. Remember, this means setters, getters, and an empty contructor. I've also added the Eclipse generated toString() and hashCode()/equals() methods as well.
Person looks something like this. (note that I always use the IDE to produce a toString() method and hashCode()/equals() methods out of habit. You usually wan't to do this, particularly the hashCode/equals methods):
Now we need some code in Main.java that will convert this obect to JSON format. We will start out with creating a Java object of Person class in the main() method like so:
Next we will add an ObjectMapper instance, note we need to add the import statement as well
If we now run this application, we see the following results
Note that by default, the ObjectMapper takes the names of the attributes and uses then in the JSON string, followed by the set value for the attribute..
We can easily change this behavior by using a @JsonProperty annotation. Go back to the Person class and add the JsonProperty annotation to the first and last name attributes.
Note that we had to include the com.fasterxml.jackson.annotation.JsonProperty class as well.
If we re-run our application, we see that the default mapping has been changed and the JSON string now has "firstname" instead of "firstName"
This lets you control the mapping between the JSON object and the Java object.
The last thing I'll show is what happens when you preface the age attrbute with @JsonIgnore. In this case the ObjectMapper will ignore the age attribute in the resulting string
So now this code
Produces this output
The age attribute is now no loner included in the JSON string.
Note: if you add an annotation, the IDE may not sense the source code has changed, so you should make sure and resave the file before trying to run the application or you may not see the result of your annotation addition!
Converting JSON to Java
Now that we have converted a Java Object to a JSON, let's go the other direction and take a JSON object (in String form of course) and turn it back to a Java Object.
Our first step is to create a String object representing a JSON class.
Now, note that within that string, we have to provide String markers around the JSON attributes and values. Since this is within a quoted string, we have to escape the double-quote with a backslash, so that the printed represtantation in the System.out.println actually looks like what we want!
Since the integer value is not a string, we don't have to put the quotes around it.
The next step is to create an empty Person oject which we will "load" the JSON data into.
and finally we once again use our mapper Object to now read the value from the inputJson string into the Person object. Note that you have to provide the class object to the mapper so that it knows what type of Object it is reading into.
Ah, but there is a bit more coding to do, as the mapper.readValue() method throws a few exceptions. While you can take the lazy way out and just catch the IOException (your IDE may prompt you just for this), it turns out you can be a little more detailed and catch two other exceptions that occur when converting JSON to Java Objects. The mapper throws two other exceptions which are both sub-classes of IOException.
Both indicate different types of issues, the JsonMappingException indicates it couldn't find an associated attribute to write into, the JsonParseException indicates that the mapper had an issue parsing one of the String values provided to it.
So, in the end the code used to Covert the JSON String to a Java Object looks like this:
If we run the code you should see output like this
While this is still a simple example, it does show the functionality of the json-databind package.