JSON Notes


metadata

There is little in the way of standards for JSON. It lacks all the namespace features of XML. It lacks the ability to serialize Java objects effectively for transport or "marshalling" from one place to another. Some make use of the '@' as a convention to indicate metadata. For instance, the following suggests the JSON describes a Java object.

    {
        "@class" : "org.acme.data.Employee",
        "name" : " Bill Findlay",
        "id" : 4096283
    }

Or, the metadata reference can be used to hook up a foreign key in a database to another table:

    {
        "name" : "Bill Findlay",
        "id" : 4096283
        "address" : "@addrtable",
        "telephone" : "801 555-1212"
    }

...whereas addrtable is:

    {
        ...
        {
            "id" : 1234567,
            "billing" : "40561 Jack the Ripper Boulevard, Los Angeles, CA 90640",
            "shipping" : "40561 Jack the Ripper Boulevard, Los Angeles, CA 90640",
        },
        {
            "id" : 4096283,
            "billing" : "1313 Mockingbird Lane, Mockingbird Heights, CA 90310",
            "shipping" : "PO Box 666, Lancaster, CA, 94532"
        }
        ...
    }

Pretty-printing

Got a string containing a stream of unformatted JSON? Need to turn:

    {"resultCode":0,"resultDescription":"Success","typeName":"iwsUserExistsResult",\
        "hostName":"https:\/\/acme","acctOid":10000132001,"acctType":"FUL"}

into:

    {
        "resultCode":0,
        "resultDescription":"Success",
        "typeName":"iwsUserExistsResult",
        "hostName":"https:\/\/acme",
        "acctOid":10000132001,
        "acctType":"FUL"
    }

?

/**
 * This pretty-prints a JSON payload returned from the server. It's pretty dang simple and not
 * much good for super-duper stuff, but what we expect back isn't complex anyway. Vastly improves
 * over having to squint.
 *
 * @param source the returned payload (JSON).
 * @param tabWidth width in spaces of the tab used to display hierarchy.
 * @return string containing the payload interspersed with new lines and spaces for indentation.
 */
static final String prettyPrint( String source, int tabWidth )
{
    StringBuffer    sb       = new StringBuffer();
    String          tab      = "    ";
    int             len      = source.length();
    int             level    = 0;           // magnitude of hierarchy
    boolean         inString = false;       // don't do hierarchy while between quotes!

    if( tabWidth != 4 )
    {
        StringBuffer t = new StringBuffer();

        for( int tw = 0; tw < tabWidth; tw++ )
            t.append( ' ' );

        tab = t.toString();
    }

    for( int index = 0 ; index < len; index++ )
    {
        char    ch = source.charAt( index );

        switch( ch )
        {
            case '\n' :
                break;
            case '"' :
                if( inString )
                    inString = false;
                else
                    inString = true;
                sb.append( ch );
                break;
            case '{' : case '[' :
                if( inString )
                {
                    sb.append( ch );
                    break;
                }

                level++;
                sb.append( ch );
                sb.append( '\n' );
                for( int l = 0; l < level; l++ )
                    sb.append( tab );
                break;
            case '}' : case ']' :
                if( inString )
                {
                    sb.append( ch );
                    break;
                }

                level--;
                sb.append( '\n' );
                for( int l = 0; l < level; l++ )
                    sb.append( tab );
                sb.append( ch );
                break;
            case ',' :
                if( inString )
                {
                    sb.append( ch );
                    break;
                }

                sb.append( ",\n" );
                for( int l = 0; l < level; l++ )
                    sb.append( tab );
                break;
            default :
                sb.append( ch );
                break;
        }
    }

    return sb.toString();
}

Jackson examples

Jackson is the JSON serializer/deserializer of choice. Here are some tiny examples, modified from our friend at mkyong. The following JARs were used to do this:

There are two ways of using Jackson to serialize...

User test

POJO has accessors (getters and setters) that are consumed by Jackson.

User.java:
package com.etretatlogiciels.examples;

import java.util.List;
import java.util.ArrayList;

public class User
{
    private int            age      = 29;
    private String         name     = "mkyong";
    private List< String > messages = new ArrayList< String >()
    {
        {
            add( "msg 1" );
            add( "msg 2" );
            add( "msg 3" );
        }
    };

    // in order for UserTest to work, these accessors must be present...
    public int getAge() { return age; }
    public void setAge( int age ) { this.age = age; }
    public String getName() { return name; }
    public void setName( String name ) { this.name = name; }
    public List< String > getMessages() { return messages; }
    public void setMessages( List< String > messages ) { this.messages = messages; }
}
UserTest.java:
package com.etretatlogiciels.examples;

import java.io.IOException;

import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;

public class UserTest
{
    public static void main( String[] args )
    {
        User         user   = new User();
        ObjectMapper mapper = new ObjectMapper();

        try
        {
            // convert user object to JSON string and display to console...
            System.out.println( mapper.defaultPrettyPrintingWriter().writeValueAsString( user ) );
        }
        catch( JsonGenerationException e )
        {
            e.printStackTrace();
        }
        catch( JsonMappingException e )
        {
            e.printStackTrace();
        }
        catch( IOException e )
        {
            e.printStackTrace();
        }
    }
}

Output:

    {
      "age" : 29,
      "name" : "mkyong",
      "messages" : [ "msg 1", "msg 2", "msg 3" ]
    }

Customer test

POJO has no accessors, but annotations instruct Jackson to use the field directly and not to use fields that are null.

Customer.java:
package com.etretatlogiciels.examples;

import org.codehaus.jackson.annotate.JsonAutoDetect;
import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility;
import org.codehaus.jackson.map.annotate.JsonSerialize;

@JsonSerialize(  include            = JsonSerialize.Inclusion.NON_NULL )
@JsonAutoDetect( fieldVisibility    = Visibility.ANY,
             getterVisibility   = Visibility.NONE,
             isGetterVisibility = Visibility.NONE,
             setterVisibility   = Visibility.NONE )
public class Customer
{
    String  name;
    Integer id;
}
CustomerTest.java:
package com.etretatlogiciels.examples;

import java.io.IOException;

import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;

public class CustomerTest
{
    public static void main( String[] args )
    {
        Customer     customer = new Customer();
        ObjectMapper mapper   = new ObjectMapper();

        try
        {
            customer.name = "mkyong";
            customer.id   = 99;
            System.out.println( mapper.defaultPrettyPrintingWriter().writeValueAsString( customer ) );

            customer.name = "Jack-and-the-Beanstalk";
            customer.id   = null;
            System.out.println( mapper.defaultPrettyPrintingWriter().writeValueAsString( customer ) );
        }
        catch( JsonGenerationException e )
        {
            e.printStackTrace();
        }
        catch( JsonMappingException e )
        {
            e.printStackTrace();
        }
        catch( IOException e )
        {
            e.printStackTrace();
        }
    }
}

Output:

    {
      "name" : "mkyong",
      "id" : 99
    }
    {
      "name" : "Jack-and-the-Beanstalk"
    }

Annotations

@JsonSerialize

include = JsonSerialize.Inclusion.NON_NULL, don't serialize any fields in this POJO that are null

@JsonAutoDetect

fieldVisibility = Visibility.ANY, sees any field in POJO
getterVisibility = Visibility.ANY, don't use (serialize results from) this POJO's getters
siGetterVisibility = Visibility.ANY, don't use this POJO's "is" getters
setterVisibility = Visibility.ANY, don't use this POJO's setters