001package org.hl7.fhir.dstu2.formats; 002 003/*- 004 * #%L 005 * org.hl7.fhir.dstu2 006 * %% 007 * Copyright (C) 2014 - 2019 Health Level 7 008 * %% 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 * #L% 021 */ 022 023 024import java.io.IOException; 025import java.io.OutputStreamWriter; 026import java.math.BigDecimal; 027import java.util.ArrayList; 028import java.util.Collections; 029import java.util.List; 030import java.util.Stack; 031 032import com.google.gson.stream.JsonWriter; 033 034public class JsonCreatorCanonical implements JsonCreator { 035 036 public class JsonCanValue { 037 String name; 038 private JsonCanValue(String name) { 039 this.name = name; 040 } 041 } 042 043 private class JsonCanNumberValue extends JsonCanValue { 044 private BigDecimal value; 045 private JsonCanNumberValue(String name, BigDecimal value) { 046 super(name); 047 this.value = value; 048 } 049 } 050 051 private class JsonCanIntegerValue extends JsonCanValue { 052 private Integer value; 053 private JsonCanIntegerValue(String name, Integer value) { 054 super(name); 055 this.value = value; 056 } 057 } 058 059 private class JsonCanBooleanValue extends JsonCanValue { 060 private Boolean value; 061 private JsonCanBooleanValue(String name, Boolean value) { 062 super(name); 063 this.value = value; 064 } 065 } 066 067 private class JsonCanStringValue extends JsonCanValue { 068 private String value; 069 private JsonCanStringValue(String name, String value) { 070 super(name); 071 this.value = value; 072 } 073 } 074 075 private class JsonCanNullValue extends JsonCanValue { 076 private JsonCanNullValue(String name) { 077 super(name); 078 } 079 } 080 081 public class JsonCanObject extends JsonCanValue { 082 083 boolean array; 084 List<JsonCanValue> children = new ArrayList<JsonCanValue>(); 085 086 public JsonCanObject(String name, boolean array) { 087 super(name); 088 this.array = array; 089 } 090 091 public void addProp(JsonCanValue obj) { 092 children.add(obj); 093 } 094 } 095 096 Stack<JsonCanObject> stack; 097 JsonCanObject root; 098 JsonWriter gson; 099 String name; 100 101 public JsonCreatorCanonical(OutputStreamWriter osw) { 102 stack = new Stack<JsonCreatorCanonical.JsonCanObject>(); 103 gson = new JsonWriter(osw); 104 name = null; 105 } 106 107 private String takeName() { 108 String res = name; 109 name = null; 110 return res; 111 } 112 113 @Override 114 public void setIndent(String indent) { 115 if (!indent.equals("")) 116 throw new Error("do not use pretty when canonical is set"); 117 gson.setIndent(indent); 118 } 119 120 @Override 121 public void beginObject() throws IOException { 122 JsonCanObject obj = new JsonCanObject(takeName(), false); 123 if (stack.isEmpty()) 124 root = obj; 125 else 126 stack.peek().addProp(obj); 127 stack.push(obj); 128 } 129 130 @Override 131 public void endObject() throws IOException { 132 stack.pop(); 133 } 134 135 @Override 136 public void nullValue() throws IOException { 137 stack.peek().addProp(new JsonCanNullValue(takeName())); 138 } 139 140 @Override 141 public void name(String name) throws IOException { 142 this.name = name; 143 } 144 145 @Override 146 public void value(String value) throws IOException { 147 stack.peek().addProp(new JsonCanStringValue(takeName(), value)); 148 } 149 150 @Override 151 public void value(Boolean value) throws IOException { 152 stack.peek().addProp(new JsonCanBooleanValue(takeName(), value)); 153 } 154 155 @Override 156 public void value(BigDecimal value) throws IOException { 157 stack.peek().addProp(new JsonCanNumberValue(takeName(), value)); 158 } 159 160 @Override 161 public void value(Integer value) throws IOException { 162 stack.peek().addProp(new JsonCanIntegerValue(takeName(), value)); 163 } 164 165 @Override 166 public void beginArray() throws IOException { 167 JsonCanObject obj = new JsonCanObject(takeName(), true); 168 if (!stack.isEmpty()) 169 stack.peek().addProp(obj); 170 stack.push(obj); 171 172 } 173 174 @Override 175 public void endArray() throws IOException { 176 stack.pop(); 177 } 178 179 @Override 180 public void finish() throws IOException { 181 writeObject(root); 182 } 183 184 private void writeObject(JsonCanObject obj) throws IOException { 185 gson.beginObject(); 186 List<String> names = new ArrayList<String>(); 187 for (JsonCanValue v : obj.children) 188 names.add(v.name); 189 Collections.sort(names); 190 for (String n : names) { 191 gson.name(n); 192 JsonCanValue v = getPropForName(n, obj.children); 193 if (v instanceof JsonCanNumberValue) 194 gson.value(((JsonCanNumberValue) v).value); 195 else if (v instanceof JsonCanIntegerValue) 196 gson.value(((JsonCanIntegerValue) v).value); 197 else if (v instanceof JsonCanBooleanValue) 198 gson.value(((JsonCanBooleanValue) v).value); 199 else if (v instanceof JsonCanStringValue) 200 gson.value(((JsonCanStringValue) v).value); 201 else if (v instanceof JsonCanNullValue) 202 gson.nullValue(); 203 else if (v instanceof JsonCanObject) { 204 JsonCanObject o = (JsonCanObject) v; 205 if (o.array) 206 writeArray(o); 207 else 208 writeObject(o); 209 } else 210 throw new Error("not possible"); 211 } 212 gson.endObject(); 213 } 214 215 private JsonCanValue getPropForName(String name, List<JsonCanValue> children) { 216 for (JsonCanValue child : children) 217 if (child.name.equals(name)) 218 return child; 219 return null; 220 } 221 222 private void writeArray(JsonCanObject arr) throws IOException { 223 gson.beginArray(); 224 for (JsonCanValue v : arr.children) { 225 if (v instanceof JsonCanNumberValue) 226 gson.value(((JsonCanNumberValue) v).value); 227 else if (v instanceof JsonCanIntegerValue) 228 gson.value(((JsonCanIntegerValue) v).value); 229 else if (v instanceof JsonCanBooleanValue) 230 gson.value(((JsonCanBooleanValue) v).value); 231 else if (v instanceof JsonCanStringValue) 232 gson.value(((JsonCanStringValue) v).value); 233 else if (v instanceof JsonCanNullValue) 234 gson.nullValue(); 235 else if (v instanceof JsonCanObject) { 236 JsonCanObject o = (JsonCanObject) v; 237 if (o.array) 238 writeArray(o); 239 else 240 writeObject(o); 241 } else 242 throw new Error("not possible"); 243 } 244 gson.endArray(); 245 } 246 247 248}