package org.hl7.fhir.dstu3.formats; import java.io.IOException; import java.io.OutputStreamWriter; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Stack; import com.google.gson.stream.JsonWriter; public class JsonCreatorCanonical implements JsonCreator { public class JsonCanValue { String name; private JsonCanValue(String name) { this.name = name; } } private class JsonCanNumberValue extends JsonCanValue { private BigDecimal value; private JsonCanNumberValue(String name, BigDecimal value) { super(name); this.value = value; } } private class JsonCanIntegerValue extends JsonCanValue { private Integer value; private JsonCanIntegerValue(String name, Integer value) { super(name); this.value = value; } } private class JsonCanBooleanValue extends JsonCanValue { private Boolean value; private JsonCanBooleanValue(String name, Boolean value) { super(name); this.value = value; } } private class JsonCanStringValue extends JsonCanValue { private String value; private JsonCanStringValue(String name, String value) { super(name); this.value = value; } } private class JsonCanNullValue extends JsonCanValue { private JsonCanNullValue(String name) { super(name); } } public class JsonCanObject extends JsonCanValue { boolean array; List<JsonCanValue> children = new ArrayList<JsonCanValue>(); public JsonCanObject(String name, boolean array) { super(name); this.array = array; } public void addProp(JsonCanValue obj) { children.add(obj); } } Stack<JsonCanObject> stack; JsonCanObject root; JsonWriter gson; String name; public JsonCreatorCanonical(OutputStreamWriter osw) { stack = new Stack<JsonCreatorCanonical.JsonCanObject>(); gson = new JsonWriter(osw); name = null; } private String takeName() { String res = name; name = null; return res; } @Override public void setIndent(String indent) { if (!indent.equals("")) throw new Error("do not use pretty when canonical is set"); gson.setIndent(indent); } @Override public void beginObject() throws IOException { JsonCanObject obj = new JsonCanObject(takeName(), false); if (stack.isEmpty()) root = obj; else stack.peek().addProp(obj); stack.push(obj); } @Override public void endObject() throws IOException { stack.pop(); } @Override public void nullValue() throws IOException { stack.peek().addProp(new JsonCanNullValue(takeName())); } @Override public void name(String name) throws IOException { this.name = name; } @Override public void value(String value) throws IOException { stack.peek().addProp(new JsonCanStringValue(takeName(), value)); } @Override public void value(Boolean value) throws IOException { stack.peek().addProp(new JsonCanBooleanValue(takeName(), value)); } @Override public void value(BigDecimal value) throws IOException { stack.peek().addProp(new JsonCanNumberValue(takeName(), value)); } @Override public void value(Integer value) throws IOException { stack.peek().addProp(new JsonCanIntegerValue(takeName(), value)); } @Override public void beginArray() throws IOException { JsonCanObject obj = new JsonCanObject(takeName(), true); if (!stack.isEmpty()) stack.peek().addProp(obj); stack.push(obj); } @Override public void endArray() throws IOException { stack.pop(); } @Override public void finish() throws IOException { writeObject(root); } private void writeObject(JsonCanObject obj) throws IOException { gson.beginObject(); List<String> names = new ArrayList<String>(); for (JsonCanValue v : obj.children) names.add(v.name); Collections.sort(names); for (String n : names) { gson.name(n); JsonCanValue v = getPropForName(n, obj.children); if (v instanceof JsonCanNumberValue) gson.value(((JsonCanNumberValue) v).value); else if (v instanceof JsonCanIntegerValue) gson.value(((JsonCanIntegerValue) v).value); else if (v instanceof JsonCanBooleanValue) gson.value(((JsonCanBooleanValue) v).value); else if (v instanceof JsonCanStringValue) gson.value(((JsonCanStringValue) v).value); else if (v instanceof JsonCanNullValue) gson.nullValue(); else if (v instanceof JsonCanObject) { JsonCanObject o = (JsonCanObject) v; if (o.array) writeArray(o); else writeObject(o); } else throw new Error("not possible"); } gson.endObject(); } private JsonCanValue getPropForName(String name, List<JsonCanValue> children) { for (JsonCanValue child : children) if (child.name.equals(name)) return child; return null; } private void writeArray(JsonCanObject arr) throws IOException { gson.beginArray(); for (JsonCanValue v : arr.children) { if (v instanceof JsonCanNumberValue) gson.value(((JsonCanNumberValue) v).value); else if (v instanceof JsonCanIntegerValue) gson.value(((JsonCanIntegerValue) v).value); else if (v instanceof JsonCanBooleanValue) gson.value(((JsonCanBooleanValue) v).value); else if (v instanceof JsonCanStringValue) gson.value(((JsonCanStringValue) v).value); else if (v instanceof JsonCanNullValue) gson.nullValue(); else if (v instanceof JsonCanObject) { JsonCanObject o = (JsonCanObject) v; if (o.array) writeArray(o); else writeObject(o); } else throw new Error("not possible"); } gson.endArray(); } @Override public void link(String href) { // not used } }