DukeScript is primarily optimized for designing client side responsive
applications in Java and HTML,
however libraries in its core are built with the goal of
making Java/JavaScript interoperability easier. One of the essential concepts
in JavaScript is JSON. Thus it is no surprise, DukeScript makes processing
JSON from Java really smooth.
Where is My JSON?
First of all we need to obtain a JSON file. One of the free JSON services is the
GitHub REST API, so let’s use it. The following command lists all
repositories for a github account (actually the Jersey JAX-RS
developers account):
The ouput of this query has the following format. Save it into a file and let’s design
a type-safe way to parse such a file with the help of DukeScript:
Setting the Project Up
Let’s get started following the same way we start with regular HTML UI based
DukeScript application. Follow the getting started
tutorial if you are OK with using NetBeans. If
you want to stay on command line, you can use:
Once our application is generated, we can start modifying the sample
application to avoid displaying the UI, but rather parse our JSON file. Let’s remove:
src/main/webapp/pages/index.html - no UI definitions
src/main/java/your/pkg/DataModel.java - no UI model
src/test - we don’t need tests for this simple sample
The next step is to change dependencies in our pom.xml - the sample project
can parse JSON inside of a running browser, but we want to do it in Java.
Luckily there is a JAR that can handle that. Just include it on runtime
classpath and it will handle all the parsing for us. Add the following dependency:
In addition to that let’s clean the Main.java so it is ready for our parsing
code and looks like:
Now we have an empty skeletal application what we can use to do the parsing,
which can be verified by executing ‘mvn clean install’ - the project should
built without any issues.
Parsing JSON Files
We are ready to start the parsing. There is the net.java.html.json.Models class
in the core DukeScript API and it contains two overloaded variants of
the method parse. One method can parse a single JSON object, the second can parse
a JSON array of multiple JSON objects.
Given the fact that the file we obtained from GitHub lists
an array of repositories, we should use the more complicated variant. Here is the
code:
As part of the setup we get the parsing context. Then we open the JSON file
we want to parse. We allocate an array to hold the results and then ask the
parse method to do the parsing and fill the list.
Then we print the whole array to output
and also access the first element in the array in a type-safe way and obtain
its id property. Here is the output from the execution of the above program:
Now one important question: How does the code know there is an id property
in the JSON?
Defining the Model
DukeScript core APIs support a type-safe way of accessing JSON structures.
Moreover, in order to avoid writing tons of boiler-plate code,
we describe the JSON structure using annotations
and generate the rest with the help of annotation processors. As such the
RepositoryInfo class is defined by:
The above definition generates the RepositoryInfo class with a single integer
property id and code to unmarshall JSON into instances of that class. The
RepositoryInfo class also defines a reasonable toString() method - hence
the whole list of such objects can be dumped into output in JSON format.
What to do when you want to parse other JSON properties? Take a look at
the format of the downloaded JSON response file
and add a new property definition! For example there
is the name property which seems to be of type String. Just change the definition
to:
Just by adding a single line, a getter getName() is added to the
RepositoryInfo info class and you can use it in Java code:
The output when running the modified program is now:
And we can continue adding as many properties into our @Model definition
as we need. For example one named private of type boolean. And so on, and
so on, until we can access enough information via type-safe Java getters.
The remaining, not listed, properties are silently ignored.
Parsing Nested Objects
We can see that the JSON format contains a nested object named owner. How can we
parse such a structure in a type-safe way? Just define yet another model definition
for it:
With the above definition one can call getOwner().getLogin() to obtain the
login information from a nested object. In addition to that, one can also
access an array of values by specifying @Property(array = true, ...) when
defining the JSON structure we want to access from Java. Here is the final
code of our class:
Here is the final output:
Parsing JSON in a type-safe way in Java has never been easier!
Appendix: Setting the Context
The last thing to mention is the way to setup our parsing context.
It is a bit magical, but as it is done just once, when setting up the classpath
of the whole application, it can be hidden, for example, in the following method:
What does it do? Well it uses the ‘magic string’ “tyrus” to request the Java
implementation of JSON parser
which is provided by the ‘ko-ws-tyrus’ module
(that is the reason why we added a dependency on this module in our pom.xml).
This is exactly the kind of configuration done by Jersey Faces
to register proper entity convertors, so one can use the classes
generated by the @Model annotation inside of Jersey’s @GET, etc. methods
just by including the appropriate JAR on the Jersey application classpath.