Top community members
All Wiki Articles Create Wiki Article

Have you ever heard about encyclopedia for code?

What about: Wiki for Code project?

* because I've tried to share code and my solutions on different services and it was removed or I was unwelcomed
   - maybe it wasn't good place, but this one is.

if you think you have solution that can help someone, you are welcome to share this solution - Click here

Java - how to create custom json builder?

0 contributions
8 points

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();
	}
}

 

0 contributions

Checkout latest Findings & News:

Checkout latest questions:

Checkout latest wiki articles:

Hey 👋
Would you like to know what we do?
  • Dirask is IT community, where we share coding knowledge and help each other to solve coding problems.
  • We welcome everyone,
    no matter what the experience,
    no matter how basic the question is,
    this community will help you.
Read more