001package org.hl7.fhir.r4.formats; 002 003import java.io.IOException; 004import java.io.OutputStreamWriter; 005import java.math.BigDecimal; 006import java.util.ArrayList; 007import java.util.Collections; 008import java.util.List; 009import java.util.Stack; 010 011import com.google.gson.stream.JsonWriter; 012 013public class JsonCreatorCanonical implements JsonCreator { 014 015 public class JsonCanValue { 016 String name; 017 private JsonCanValue(String name) { 018 this.name = name; 019 } 020 } 021 022 private class JsonCanNumberValue extends JsonCanValue { 023 private BigDecimal value; 024 private JsonCanNumberValue(String name, BigDecimal value) { 025 super(name); 026 this.value = value; 027 } 028 } 029 030 private class JsonCanIntegerValue extends JsonCanValue { 031 private Integer value; 032 private JsonCanIntegerValue(String name, Integer value) { 033 super(name); 034 this.value = value; 035 } 036 } 037 038 private class JsonCanBooleanValue extends JsonCanValue { 039 private Boolean value; 040 private JsonCanBooleanValue(String name, Boolean value) { 041 super(name); 042 this.value = value; 043 } 044 } 045 046 private class JsonCanStringValue extends JsonCanValue { 047 private String value; 048 private JsonCanStringValue(String name, String value) { 049 super(name); 050 this.value = value; 051 } 052 } 053 054 private class JsonCanNullValue extends JsonCanValue { 055 private JsonCanNullValue(String name) { 056 super(name); 057 } 058 } 059 060 public class JsonCanObject extends JsonCanValue { 061 062 boolean array; 063 List<JsonCanValue> children = new ArrayList<JsonCanValue>(); 064 065 public JsonCanObject(String name, boolean array) { 066 super(name); 067 this.array = array; 068 } 069 070 public void addProp(JsonCanValue obj) { 071 children.add(obj); 072 } 073 } 074 075 Stack<JsonCanObject> stack; 076 JsonCanObject root; 077 JsonWriter gson; 078 String name; 079 080 public JsonCreatorCanonical(OutputStreamWriter osw) { 081 stack = new Stack<JsonCreatorCanonical.JsonCanObject>(); 082 gson = new JsonWriter(osw); 083 name = null; 084 } 085 086 private String takeName() { 087 String res = name; 088 name = null; 089 return res; 090 } 091 092 @Override 093 public void setIndent(String indent) { 094 if (!indent.equals("")) 095 throw new Error("do not use pretty when canonical is set"); 096 gson.setIndent(indent); 097 } 098 099 @Override 100 public void beginObject() throws IOException { 101 JsonCanObject obj = new JsonCanObject(takeName(), false); 102 if (stack.isEmpty()) 103 root = obj; 104 else 105 stack.peek().addProp(obj); 106 stack.push(obj); 107 } 108 109 @Override 110 public void endObject() throws IOException { 111 stack.pop(); 112 } 113 114 @Override 115 public void nullValue() throws IOException { 116 stack.peek().addProp(new JsonCanNullValue(takeName())); 117 } 118 119 @Override 120 public void name(String name) throws IOException { 121 this.name = name; 122 } 123 124 @Override 125 public void value(String value) throws IOException { 126 stack.peek().addProp(new JsonCanStringValue(takeName(), value)); 127 } 128 129 @Override 130 public void value(Boolean value) throws IOException { 131 stack.peek().addProp(new JsonCanBooleanValue(takeName(), value)); 132 } 133 134 @Override 135 public void value(BigDecimal value) throws IOException { 136 stack.peek().addProp(new JsonCanNumberValue(takeName(), value)); 137 } 138 139 @Override 140 public void value(Integer value) throws IOException { 141 stack.peek().addProp(new JsonCanIntegerValue(takeName(), value)); 142 } 143 144 @Override 145 public void beginArray() throws IOException { 146 JsonCanObject obj = new JsonCanObject(takeName(), true); 147 if (!stack.isEmpty()) 148 stack.peek().addProp(obj); 149 stack.push(obj); 150 151 } 152 153 @Override 154 public void endArray() throws IOException { 155 stack.pop(); 156 } 157 158 @Override 159 public void finish() throws IOException { 160 writeObject(root); 161 } 162 163 private void writeObject(JsonCanObject obj) throws IOException { 164 gson.beginObject(); 165 List<String> names = new ArrayList<String>(); 166 for (JsonCanValue v : obj.children) 167 names.add(v.name); 168 Collections.sort(names); 169 for (String n : names) { 170 gson.name(n); 171 JsonCanValue v = getPropForName(n, obj.children); 172 if (v instanceof JsonCanNumberValue) 173 gson.value(((JsonCanNumberValue) v).value); 174 else if (v instanceof JsonCanIntegerValue) 175 gson.value(((JsonCanIntegerValue) v).value); 176 else if (v instanceof JsonCanBooleanValue) 177 gson.value(((JsonCanBooleanValue) v).value); 178 else if (v instanceof JsonCanStringValue) 179 gson.value(((JsonCanStringValue) v).value); 180 else if (v instanceof JsonCanNullValue) 181 gson.nullValue(); 182 else if (v instanceof JsonCanObject) { 183 JsonCanObject o = (JsonCanObject) v; 184 if (o.array) 185 writeArray(o); 186 else 187 writeObject(o); 188 } else 189 throw new Error("not possible"); 190 } 191 gson.endObject(); 192 } 193 194 private JsonCanValue getPropForName(String name, List<JsonCanValue> children) { 195 for (JsonCanValue child : children) 196 if (child.name.equals(name)) 197 return child; 198 return null; 199 } 200 201 private void writeArray(JsonCanObject arr) throws IOException { 202 gson.beginArray(); 203 for (JsonCanValue v : arr.children) { 204 if (v instanceof JsonCanNumberValue) 205 gson.value(((JsonCanNumberValue) v).value); 206 else if (v instanceof JsonCanIntegerValue) 207 gson.value(((JsonCanIntegerValue) v).value); 208 else if (v instanceof JsonCanBooleanValue) 209 gson.value(((JsonCanBooleanValue) v).value); 210 else if (v instanceof JsonCanStringValue) 211 gson.value(((JsonCanStringValue) v).value); 212 else if (v instanceof JsonCanNullValue) 213 gson.nullValue(); 214 else if (v instanceof JsonCanObject) { 215 JsonCanObject o = (JsonCanObject) v; 216 if (o.array) 217 writeArray(o); 218 else 219 writeObject(o); 220 } else 221 throw new Error("not possible"); 222 } 223 gson.endArray(); 224 } 225 226 @Override 227 public void link(String href) { 228 // not used 229 } 230 231 232}