Serialisation: JSON

Java

APIs

There is a standard Java API for managing JSON, described at Java API for JSON Processing: An Introduction to JSON . Unfortunately, there doesn't appear to be any tool to convert a JSON schema to this particular API. So we won't use it.

There is a JSON Schema to POJO (Plain Old Java) at jsonschema2pojo Paste in the schema, choose the package name and class name, set the source to JSON Schema aand the target to Java, and for convenience, turn on "Generate builder methods". To be able to print the resuoltant Java classes, it may be convenient to also turn on the "toString" option. (Note: the tool doesn't like tabs in the schema file, replace any with spaces). It should look like the figure:

One option concerns Annotations. There is a a specific set of annotations convenient for JSON from Jackson. Annotations in general are discussed in Java Annotations, while the Jackson annotations are discussed in Serialization. The annotations concern the strings that are used in serializing to JSON the Java objects. Without annotations the class name is used, but this can be altered by annotations. If you like that kind of stuff, you can use it. I'm happy enough with plain old Java.

Applying this to the JSON example schema given earlier results in three classes: Email.java, Name.java and Person.java in directory person. Each class has methods to get/set fileds, but also has "builder" methods withXYZ() for each field. This allows a Name object to be created for example, by


Name name = new Name()
	        .withPersonal("Jan")
	        .withFamily("Newmarch");
  

Jackson API

The generated classes are compatable with the Jackson JSON API. The primary class ObjectMapper is described at Jackson ObjectMapper . This has methods to create Java objects from JSON strings given by strings, file contents, readers and streams. It can also write a Java object as a JSON string as a byte array, a string or to a stream.

Jar files for this API are hosted on the Maven site JSON Libraries. The relevant libraries are com.fasterxml.jackson.core , com.fasterxml.jackson.databind and com.fasterxml.jackson.core At the time of writing, the latest version of each is 2.11.0. From each page, select the latest version and download the corresponding jar file.

If you have turned on the option of generating a toString() method, you will also need the Apache jar file org-apache-commons-lang.jar

JSON client

The JSON client creates a Person Java object from the schema-generated files, and sends the JSON string as UTF-8 bytes on an output stream. It also prints to stdout the string JSON form for checking on the client side. It is PersonClientJSON.java:


import person.*;
import java.util.List;
import java.util.Vector;
import java.io.*;
import java.net.*;
import com.fasterxml.jackson.databind.ObjectMapper;

public class PersonClientJSON {

    public static final int SERVER_PORT = 2002;
 
    public static void main(String[] args) {
	
	if (args.length != 1) {
            System.err.println("Usage: Client address");
            System.exit(1);
        }

	Name name = new Name()
	    .withPersonal("Jan")
	    .withFamily("Newmarch");
	
	Email email1 = new Email()
	    .withKind("private")
	    .withAddress("jan@newmarch.name");
	
	Email email2 = new Email()
	    .withKind("work")
	    .withAddress("j.newmarch@boxhill.edu.au");
	
	List<Email> allEmails = new Vector<Email>();
	allEmails.add(email1);
	allEmails.add(email2);

	Person person = new Person()
	    .withName(name)
	    .withEmail(allEmails);


	InetAddress address = null;
        try {
            address = InetAddress.getByName(args[0]);
        } catch(UnknownHostException e) {
            e.printStackTrace();
            System.exit(2);
        }

        Socket sock = null;
        try {
            sock = new Socket(address, SERVER_PORT);
	    System.out.println("Connected");
        } catch(IOException e) {
            e.printStackTrace();
            System.exit(3);
        }

        OutputStream out = null;
        try {
            out = sock.getOutputStream();
        } catch(IOException e) {
            e.printStackTrace();
            System.exit(5);
        }

	try {
	    ObjectMapper mapper = new ObjectMapper();
	    String str = mapper.writeValueAsString(person);
	    System.out.println("JSON is " + str);

	    mapper.writeValue(out, person);
	} catch(Exception e) {
	    System.err.println(e);
	}
    }
}

To build the client,


      javac -cp jackson-databind-2.11.0.jar:jackson-core-2.11.0.jar:jackson-annotations-2.11.0.jar:org-apache-commons-lang.jar:org-apache-commons-lang.jar person/*java PersonClientJSON.java
  
and to run it,

      java -cp .:jackson-databind-2.11.0.jar:jackson-core-2.11.0.jar:jackson-annotations-2.11.0.jar:org-apache-commons-lang.jar  PersonClientJSON localhost
  

JSON server

The JSON server listens for a client connection, and then asks the ObjectMapper to readValue() from the socket's input stream. It then prints the resultant Person to stdout. Using the Apache string builder, it will look something like


      Person is person.Person@35bbe5e8[name=person.Name@2c8d66b2[personal=Jan,family=Newmarch],email=[person.Email@5a39699c[kind=private,address=jan@newmarch.name], person.Email@3cb5cdba[kind=work,address=j.newmarch@boxhill.edu.au]]]
  
(with obvious changes in the addresses when you run it).

The server is PersonServer.java:


import person.*;
import java.util.Arrays;
import java.io.*;
import java.net.*;
import com.fasterxml.jackson.databind.ObjectMapper;

public class PersonServer {

    public static final int SERVER_PORT = 2002;
 
    public static void main(String[] args){
	
	ServerSocket s = null;
        try {
            s = new ServerSocket(SERVER_PORT);
        } catch(IOException e) {
            System.out.println(e);
            System.exit(1);
        }
        while (true) {
            Socket incoming = null;
            try {
                incoming = s.accept();
                System.out.println("Connected");
            } catch(IOException e) {
                System.out.println(e);
                continue;
            }

            handleSocket(incoming);
        }
    }

    public static void handleSocket(Socket incoming) {
        InputStream in;
	
	try {
	    in = incoming.getInputStream();
        }  catch(IOException e) {
            System.err.println(e.toString());
            return;
        }

	try {
	    ObjectMapper mapper = new ObjectMapper();

	    Person person = mapper.readValue(in, Person.class);
	    System.out.println("Person is " + person.toString());
	} catch(Exception e) {
	    System.err.println(e);
	}
    }
}

To compile the server,


      javac -cp jackson-databind-2.11.0.jar:jackson-core-2.11.0.jar:jackson-annotations-2.11.0.jar:org-apache-commons-lang.jar person/*java PersonServer.java
  
and to run it,

      java -cp .:jackson-databind-2.11.0.jar:jackson-core-2.11.0.jar:jackson-annotations-2.11.0.jar:org-apache-commons-lang.jar  PersonServer
  


Copyright © Jan Newmarch, jan@newmarch.name
Creative Commons License
" Network Programming using Java, Go, Python, Rust, JavaScript and Julia" by Jan Newmarch is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License .
Based on a work at https://jan.newmarch.name/NetworkProgramming/ .

If you like this book, please contribute using PayPal