Languages
[Edit]
EN

Java - how to create custom json builder?

8 points
Created by:
JustMike
3491

In Java it is very easy to create own JSON builder. This article shows how to create it.

1. Simple custom JSON builder example

Presented source code consist of:

  • Program.java file that contains simple usage example of json builder,
  • JsonBuilder.java file that contains common json builder logic,
  • ArrayJsonBuilder.java file that contains array json builder logic,
  • ObjectJsonBuilder.java file that contains object json builder logic,
  • Encoder.java file that is used to escapse dangerous characters inside strings.

 

Program.java file:

package com.dirask.json;

public class Program {
    public static void main(String[] args) {
        ObjectJsonBuilder studentBuilder = new ObjectJsonBuilder();

        studentBuilder.addNumber("id", 1000);
        studentBuilder.addString("name", "John");
        studentBuilder.addNumber("age", 25);
        studentBuilder.addBoolean("isStudent", true);

        ArrayJsonBuilder todosBuilder = studentBuilder.createArray("todos");

        ObjectJsonBuilder todo1 = todosBuilder.createObject();
        todo1.addNumber("priority", 5);
        todo1.addString("name", "Go to classes");

        ObjectJsonBuilder todo2 = todosBuilder.createObject();
        todo2.addNumber("priority", 1);
        todo2.addString("name", "Go to party");

        ObjectJsonBuilder todo3 = todosBuilder.createObject();
        todo3.addNumber("priority", 4);
        todo3.addString("name", "Go to lecture");

        System.out.println(studentBuilder.extractJson());


        ArrayJsonBuilder fruitsBuilder = new ArrayJsonBuilder();

        fruitsBuilder.addString("Apples");
        fruitsBuilder.addString("Grapes");
        fruitsBuilder.addString("Bananas");

        System.out.println(fruitsBuilder.extractJson());
    }
}

Output:

{
   "id":1000,
   "name":"John",
   "age":25,
   "isStudent":true,
   "todos":[
      {"priority":5,"name":"Go to classes"},
      {"priority":1,"name":"Go to party"},
      {"priority":4,"name":"Go to lecture"}
   ]
}

["Apples","Grapes","Bananas"]

 

JsonBuilder.java file:

package com.dirask.json;

public abstract class JsonBuilder {
    private boolean empty = true;
    private boolean locked = false;

    private StringBuilder builder;
    private JsonBuilder entity = null; // keeps reference to sub-json builder

    private Locker parentLocker;
    private Locker localLocker;

    private String json = null;

    public JsonBuilder() {
        this.builder = new StringBuilder();

        this.parentLocker = null;
        this.localLocker = this.createLocker();
    }

    protected JsonBuilder(StringBuilder builder, Locker locker) {
        this.builder = builder;

        this.parentLocker = locker;
        this.localLocker = this.createLocker();

        locker.lock();
    }

    protected Locker createLocker() {
        Locker locker = new Locker() {
            @Override
            public void lock() {
                locked = true;
            }

            @Override
            public void unlock() {
                locked = false;
            }
        };

        return locker;
    }

    public boolean isLocked() {
        return this.locked;
    }

    public boolean isEmpty() {
        return this.empty;
    }

    protected void appendText(String text) {
        this.builder.append(text);
    }

    protected void cleanupEntity() {
        if (this.entity == null)
            return;

        this.entity.cleanupEntity();
        this.entity.finaliseJson();

        this.entity = null;
    }

    protected void appendSeparator() {
        if (this.empty)
            this.empty = false;

        else
            this.builder.append(",");
    }

    protected ArrayJsonBuilder createArray() {
        ArrayJsonBuilder entity = new ArrayJsonBuilder(this.builder, this.localLocker);
        this.entity = entity;

        return entity;
    }

    protected ObjectJsonBuilder createObject() {
        ObjectJsonBuilder entity = new ObjectJsonBuilder(this.builder, this.localLocker);
        this.entity = entity;

        return entity;
    }

    protected boolean finaliseJson() {
        if (this.locked)
            return false;

        this.locked = true;

        if (this.parentLocker != null)
            this.parentLocker.unlock();

        return true;
    }

    public String extractJson() {
        if (this.json == null && this.parentLocker == null) {
            this.cleanupEntity();
            this.finaliseJson();

            this.json = this.builder.toString();
        }

        return this.json;
    }

    protected interface Locker {
        void lock();

        void unlock();
    }
}

ArrayJsonBuilder.java file:

package com.dirask.json;

public class ArrayJsonBuilder extends JsonBuilder {
	public ArrayJsonBuilder() {
		this.appendText("[");
	}

	protected ArrayJsonBuilder(StringBuilder builder, Locker locker) {
		super(builder, locker);

		builder.append("[");
	}

	private boolean addValue(Object value) {
		super.cleanupEntity();

		if (super.isLocked())
			return false;

		super.appendSeparator();
		super.appendText(value == null ? "null" : value.toString());

		return true;
	}

	public boolean addBoolean(Boolean value) {
		return this.addValue(value);
	}

	public boolean addNumber(Number value) {
		return this.addValue(value);
	}

	public boolean addString(String value) {
		super.cleanupEntity();

		if (super.isLocked())
			return false;

		super.appendSeparator();

		if (value == null)
			super.appendText("null");

		else {
			super.appendText("\"");
			super.appendText(Encoder.encodeText(value));
			super.appendText("\"");
		}

		return true;
	}

	public boolean addJson(JsonBuilder value) {
		return this.addValue(value.extractJson());
	}

	@Override
	public ArrayJsonBuilder createArray() {
		super.cleanupEntity();

		if (super.isLocked())
			return null;

		super.appendSeparator();

		return super.createArray();
	}

	@Override
	public ObjectJsonBuilder createObject() {
		super.cleanupEntity();

		if (super.isLocked())
			return null;

		super.appendSeparator();

		return super.createObject();
	}

	@Override
	protected boolean finaliseJson() {
		if (super.finaliseJson()) {
			super.appendText("]");

			return true;
		}

		return false;
	}
}

ObjectJsonBuilder.java file:

package com.dirask.json;

public class ObjectJsonBuilder extends JsonBuilder {
	public ObjectJsonBuilder() {
		this.appendText("{");
	}

	protected ObjectJsonBuilder(StringBuilder builder, Locker locker) {
		super(builder, locker);

		builder.append("{");
	}

	private boolean addValue(String name, Object value) {
		super.cleanupEntity();

		if (super.isLocked())
			return false;

		super.appendSeparator();

		super.appendText("\"");
		super.appendText(name);
		super.appendText("\":");
		super.appendText(value == null ? "null" : value.toString());

		return true;
	}

	public boolean addBoolean(String name, Boolean value) {
		return this.addValue(name, value);
	}

	public boolean addNumber(String name, Number value) {
		return this.addValue(name, value);
	}

	public boolean addString(String name, String value) {
		super.cleanupEntity();

		if (super.isLocked())
			return false;

		super.appendSeparator();

		super.appendText("\"");
		super.appendText(name);

		if (value == null)
			super.appendText("\":null");

		else {
			super.appendText("\":\"");
			super.appendText(Encoder.encodeText(value));
			super.appendText("\"");
		}

		return true;
	}

	public boolean addBuilder(String name, JsonBuilder value) {
		return this.addValue(name, value.extractJson());
	}

	public ArrayJsonBuilder createArray(String name) {
		super.cleanupEntity();

		if (super.isLocked())
			return null;

		super.appendSeparator();

		super.appendText("\"");
		super.appendText(name);
		super.appendText("\":");

		return super.createArray();
	}

	public ObjectJsonBuilder createObject(String name) {
		super.cleanupEntity();

		if (super.isLocked())
			return null;

		super.appendSeparator();

		super.appendText("\"");
		super.appendText(name);
		super.appendText("\":");

		return super.createObject();
	}

	@Override
	protected boolean finaliseJson() {
		if (super.finaliseJson()) {
			super.appendText("}");

			return true;
		}

		return false;
	}
}

Encoder.java file:

package com.dirask.json;

public class Encoder {
	private static String createHexString(int value) {
		String text = Integer.toHexString(value);

		if (value < 0x10)
			return "{0" + text.toUpperCase() + "}";

		return "{" + text.toUpperCase() + "}";
	}

	public static String encodeText(String text) {
		int length = text.length();

		if (length == 0)
			return new String();

		StringBuilder builder = new StringBuilder(length);

		for (int i = 0; i < length; ++i) {
			char tmp = text.charAt(i);

			switch (tmp) {
				case 0x00: // \0 - NULL
				case 0x01:
				case 0x02:
				case 0x03:
				case 0x04:
				case 0x05:
				case 0x06:
				case 0x07:
				case 0x08:
					builder.append(createHexString(tmp));
					continue;

				case 0x09: // \t - TABULATOR
					builder.append("\\t");
					continue;

				case 0x0A: // \n - NEW LINE
					builder.append("\\n");
					continue;

				case 0x0B:
				case 0x0C:
					builder.append(createHexString(tmp));
					continue;

				case 0x0D: // \r - CARRIAGE RETURN
					builder.append("\\r");
					continue;

				case 0x0E:
				case 0x0F:
				case 0x10:
				case 0x11:
				case 0x12:
				case 0x13:
				case 0x14:
				case 0x15:
				case 0x16:
				case 0x17:
				case 0x18:
				case 0x19:
				case 0x1A:
				case 0x1B:
				case 0x1C:
				case 0x1D:
				case 0x1E:
				case 0x1F:
					builder.append(createHexString(tmp));
					continue;

					// allowed characters

				case 0x22: // " - DOUBLE QUOTATION MARK
					builder.append("\\\"");
					continue;

					// allowed characters

				case 0x5C: // \ - BACK SLASH
					builder.append("\\\\");
					continue;

					// allowed characters

				default:
					builder.append(tmp);
			}
		}

		return builder.toString();
	}
}

 

Hey 👋
Would you like to know what we do?
  • Dirask is a friendly IT community for learners, professionals and hobbyists to share their knowledge and help each other in extraordinary easy way.
  • We welcome everyone,
    no matter what the experience,
    no matter how basic the question is,
    this community will help you.