001package org.hl7.fhir.r4.formats; 002 003/*- 004 * #%L 005 * org.hl7.fhir.r4 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 032public class JsonCreatorCanonical implements JsonCreator { 033 034 public class JsonCanValue { 035 String name; 036 private JsonCanValue(String name) { 037 this.name = name; 038 } 039 } 040 041 private class JsonCanNumberValue extends JsonCanValue { 042 private BigDecimal value; 043 private JsonCanNumberValue(String name, BigDecimal value) { 044 super(name); 045 this.value = value; 046 } 047 } 048 049 private class JsonCanPresentedNumberValue extends JsonCanValue { 050 private String value; 051 private JsonCanPresentedNumberValue(String name, String value) { 052 super(name); 053 this.value = value; 054 } 055 } 056 057 private class JsonCanIntegerValue extends JsonCanValue { 058 private Integer value; 059 private JsonCanIntegerValue(String name, Integer value) { 060 super(name); 061 this.value = value; 062 } 063 } 064 065 private class JsonCanBooleanValue extends JsonCanValue { 066 private Boolean value; 067 private JsonCanBooleanValue(String name, Boolean value) { 068 super(name); 069 this.value = value; 070 } 071 } 072 073 private class JsonCanStringValue extends JsonCanValue { 074 private String value; 075 private JsonCanStringValue(String name, String value) { 076 super(name); 077 this.value = value; 078 } 079 } 080 081 private class JsonCanNullValue extends JsonCanValue { 082 private JsonCanNullValue(String name) { 083 super(name); 084 } 085 } 086 087 public class JsonCanObject extends JsonCanValue { 088 089 boolean array; 090 List<JsonCanValue> children = new ArrayList<JsonCanValue>(); 091 092 public JsonCanObject(String name, boolean array) { 093 super(name); 094 this.array = array; 095 } 096 097 public void addProp(JsonCanValue obj) { 098 children.add(obj); 099 } 100 } 101 102 Stack<JsonCanObject> stack; 103 JsonCanObject root; 104 JsonCreatorDirect jj; 105 String name; 106 107 public JsonCreatorCanonical(OutputStreamWriter osw) { 108 stack = new Stack<JsonCreatorCanonical.JsonCanObject>(); 109 jj = new JsonCreatorDirect(osw); 110 name = null; 111 } 112 113 private String takeName() { 114 String res = name; 115 name = null; 116 return res; 117 } 118 119 @Override 120 public void setIndent(String indent) { 121 if (!indent.equals("")) 122 throw new Error("do not use pretty when canonical is set"); 123 jj.setIndent(indent); 124 } 125 126 @Override 127 public void beginObject() throws IOException { 128 JsonCanObject obj = new JsonCanObject(takeName(), false); 129 if (stack.isEmpty()) 130 root = obj; 131 else 132 stack.peek().addProp(obj); 133 stack.push(obj); 134 } 135 136 @Override 137 public void endObject() throws IOException { 138 stack.pop(); 139 } 140 141 @Override 142 public void nullValue() throws IOException { 143 stack.peek().addProp(new JsonCanNullValue(takeName())); 144 } 145 146 @Override 147 public void name(String name) throws IOException { 148 this.name = name; 149 } 150 151 @Override 152 public void value(String value) throws IOException { 153 stack.peek().addProp(new JsonCanStringValue(takeName(), value)); 154 } 155 156 @Override 157 public void value(Boolean value) throws IOException { 158 stack.peek().addProp(new JsonCanBooleanValue(takeName(), value)); 159 } 160 161 @Override 162 public void value(BigDecimal value) throws IOException { 163 stack.peek().addProp(new JsonCanNumberValue(takeName(), value)); 164 } 165 @Override 166 public void valueNum(String value) throws IOException { 167 stack.peek().addProp(new JsonCanPresentedNumberValue(takeName(), value)); 168 } 169 170 171 @Override 172 public void value(Integer value) throws IOException { 173 stack.peek().addProp(new JsonCanIntegerValue(takeName(), value)); 174 } 175 176 @Override 177 public void beginArray() throws IOException { 178 JsonCanObject obj = new JsonCanObject(takeName(), true); 179 if (!stack.isEmpty()) 180 stack.peek().addProp(obj); 181 stack.push(obj); 182 183 } 184 185 @Override 186 public void endArray() throws IOException { 187 stack.pop(); 188 } 189 190 @Override 191 public void finish() throws IOException { 192 writeObject(root); 193 } 194 195 private void writeObject(JsonCanObject obj) throws IOException { 196 jj.beginObject(); 197 List<String> names = new ArrayList<String>(); 198 for (JsonCanValue v : obj.children) 199 names.add(v.name); 200 Collections.sort(names); 201 for (String n : names) { 202 jj.name(n); 203 JsonCanValue v = getPropForName(n, obj.children); 204 if (v instanceof JsonCanNumberValue) 205 jj.value(((JsonCanNumberValue) v).value); 206 else if (v instanceof JsonCanPresentedNumberValue) 207 jj.valueNum(((JsonCanPresentedNumberValue) v).value); 208 else if (v instanceof JsonCanIntegerValue) 209 jj.value(((JsonCanIntegerValue) v).value); 210 else if (v instanceof JsonCanBooleanValue) 211 jj.value(((JsonCanBooleanValue) v).value); 212 else if (v instanceof JsonCanStringValue) 213 jj.value(((JsonCanStringValue) v).value); 214 else if (v instanceof JsonCanNullValue) 215 jj.nullValue(); 216 else if (v instanceof JsonCanObject) { 217 JsonCanObject o = (JsonCanObject) v; 218 if (o.array) 219 writeArray(o); 220 else 221 writeObject(o); 222 } else 223 throw new Error("not possible"); 224 } 225 jj.endObject(); 226 } 227 228 private JsonCanValue getPropForName(String name, List<JsonCanValue> children) { 229 for (JsonCanValue child : children) 230 if (child.name.equals(name)) 231 return child; 232 return null; 233 } 234 235 private void writeArray(JsonCanObject arr) throws IOException { 236 jj.beginArray(); 237 for (JsonCanValue v : arr.children) { 238 if (v instanceof JsonCanNumberValue) 239 jj.value(((JsonCanNumberValue) v).value); 240 else if (v instanceof JsonCanIntegerValue) 241 jj.value(((JsonCanIntegerValue) v).value); 242 else if (v instanceof JsonCanBooleanValue) 243 jj.value(((JsonCanBooleanValue) v).value); 244 else if (v instanceof JsonCanStringValue) 245 jj.value(((JsonCanStringValue) v).value); 246 else if (v instanceof JsonCanNullValue) 247 jj.nullValue(); 248 else if (v instanceof JsonCanObject) { 249 JsonCanObject o = (JsonCanObject) v; 250 if (o.array) 251 writeArray(o); 252 else 253 writeObject(o); 254 } else 255 throw new Error("not possible"); 256 } 257 jj.endArray(); 258 } 259 260 @Override 261 public void link(String href) { 262 // not used 263 } 264 265 266}