001package org.hl7.fhir.dstu3.formats; 002 003/* 004 Copyright (c) 2011+, HL7, Inc. 005 All rights reserved. 006 007 Redistribution and use in source and binary forms, with or without modification, 008 are permitted provided that the following conditions are met: 009 010 * Redistributions of source code must retain the above copyright notice, this 011 list of conditions and the following disclaimer. 012 * Redistributions in binary form must reproduce the above copyright notice, 013 this list of conditions and the following disclaimer in the documentation 014 and/or other materials provided with the distribution. 015 * Neither the name of HL7 nor the names of its contributors may be used to 016 endorse or promote products derived from this software without specific 017 prior written permission. 018 019 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 022 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 023 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 024 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 025 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 026 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 027 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 028 POSSIBILITY OF SUCH DAMAGE. 029 030 */ 031 032 033 034import java.io.IOException; 035import java.io.OutputStreamWriter; 036import java.math.BigDecimal; 037import java.util.ArrayList; 038import java.util.Collections; 039import java.util.List; 040import java.util.Stack; 041 042import com.google.gson.stream.JsonWriter; 043 044public class JsonCreatorCanonical implements JsonCreator { 045 046 public class JsonCanValue { 047 String name; 048 private JsonCanValue(String name) { 049 this.name = name; 050 } 051 } 052 053 private class JsonCanNumberValue extends JsonCanValue { 054 private BigDecimal value; 055 private JsonCanNumberValue(String name, BigDecimal value) { 056 super(name); 057 this.value = value; 058 } 059 } 060 061 private class JsonCanIntegerValue extends JsonCanValue { 062 private Integer value; 063 private JsonCanIntegerValue(String name, Integer value) { 064 super(name); 065 this.value = value; 066 } 067 } 068 069 private class JsonCanBooleanValue extends JsonCanValue { 070 private Boolean value; 071 private JsonCanBooleanValue(String name, Boolean value) { 072 super(name); 073 this.value = value; 074 } 075 } 076 077 private class JsonCanStringValue extends JsonCanValue { 078 private String value; 079 private JsonCanStringValue(String name, String value) { 080 super(name); 081 this.value = value; 082 } 083 } 084 085 private class JsonCanNullValue extends JsonCanValue { 086 private JsonCanNullValue(String name) { 087 super(name); 088 } 089 } 090 091 public class JsonCanObject extends JsonCanValue { 092 093 boolean array; 094 List<JsonCanValue> children = new ArrayList<JsonCanValue>(); 095 096 public JsonCanObject(String name, boolean array) { 097 super(name); 098 this.array = array; 099 } 100 101 public void addProp(JsonCanValue obj) { 102 children.add(obj); 103 } 104 } 105 106 Stack<JsonCanObject> stack; 107 JsonCanObject root; 108 JsonWriter gson; 109 String name; 110 111 public JsonCreatorCanonical(OutputStreamWriter osw) { 112 stack = new Stack<JsonCreatorCanonical.JsonCanObject>(); 113 gson = new JsonWriter(osw); 114 name = null; 115 } 116 117 private String takeName() { 118 String res = name; 119 name = null; 120 return res; 121 } 122 123 @Override 124 public void setIndent(String indent) { 125 if (!indent.equals("")) 126 throw new Error("do not use pretty when canonical is set"); 127 gson.setIndent(indent); 128 } 129 130 @Override 131 public void beginObject() throws IOException { 132 JsonCanObject obj = new JsonCanObject(takeName(), false); 133 if (stack.isEmpty()) 134 root = obj; 135 else 136 stack.peek().addProp(obj); 137 stack.push(obj); 138 } 139 140 @Override 141 public void endObject() throws IOException { 142 stack.pop(); 143 } 144 145 @Override 146 public void nullValue() throws IOException { 147 stack.peek().addProp(new JsonCanNullValue(takeName())); 148 } 149 150 @Override 151 public void name(String name) throws IOException { 152 this.name = name; 153 } 154 155 @Override 156 public void value(String value) throws IOException { 157 stack.peek().addProp(new JsonCanStringValue(takeName(), value)); 158 } 159 160 @Override 161 public void value(Boolean value) throws IOException { 162 stack.peek().addProp(new JsonCanBooleanValue(takeName(), value)); 163 } 164 165 @Override 166 public void value(BigDecimal value) throws IOException { 167 stack.peek().addProp(new JsonCanNumberValue(takeName(), value)); 168 } 169 170 @Override 171 public void value(Integer value) throws IOException { 172 stack.peek().addProp(new JsonCanIntegerValue(takeName(), value)); 173 } 174 175 @Override 176 public void beginArray() throws IOException { 177 JsonCanObject obj = new JsonCanObject(takeName(), true); 178 if (!stack.isEmpty()) 179 stack.peek().addProp(obj); 180 stack.push(obj); 181 182 } 183 184 @Override 185 public void endArray() throws IOException { 186 stack.pop(); 187 } 188 189 @Override 190 public void finish() throws IOException { 191 writeObject(root); 192 } 193 194 private void writeObject(JsonCanObject obj) throws IOException { 195 gson.beginObject(); 196 List<String> names = new ArrayList<String>(); 197 for (JsonCanValue v : obj.children) 198 names.add(v.name); 199 Collections.sort(names); 200 for (String n : names) { 201 gson.name(n); 202 JsonCanValue v = getPropForName(n, obj.children); 203 if (v instanceof JsonCanNumberValue) 204 gson.value(((JsonCanNumberValue) v).value); 205 else if (v instanceof JsonCanIntegerValue) 206 gson.value(((JsonCanIntegerValue) v).value); 207 else if (v instanceof JsonCanBooleanValue) 208 gson.value(((JsonCanBooleanValue) v).value); 209 else if (v instanceof JsonCanStringValue) 210 gson.value(((JsonCanStringValue) v).value); 211 else if (v instanceof JsonCanNullValue) 212 gson.nullValue(); 213 else if (v instanceof JsonCanObject) { 214 JsonCanObject o = (JsonCanObject) v; 215 if (o.array) 216 writeArray(o); 217 else 218 writeObject(o); 219 } else 220 throw new Error("not possible"); 221 } 222 gson.endObject(); 223 } 224 225 private JsonCanValue getPropForName(String name, List<JsonCanValue> children) { 226 for (JsonCanValue child : children) 227 if (child.name.equals(name)) 228 return child; 229 return null; 230 } 231 232 private void writeArray(JsonCanObject arr) throws IOException { 233 gson.beginArray(); 234 for (JsonCanValue v : arr.children) { 235 if (v instanceof JsonCanNumberValue) 236 gson.value(((JsonCanNumberValue) v).value); 237 else if (v instanceof JsonCanIntegerValue) 238 gson.value(((JsonCanIntegerValue) v).value); 239 else if (v instanceof JsonCanBooleanValue) 240 gson.value(((JsonCanBooleanValue) v).value); 241 else if (v instanceof JsonCanStringValue) 242 gson.value(((JsonCanStringValue) v).value); 243 else if (v instanceof JsonCanNullValue) 244 gson.nullValue(); 245 else if (v instanceof JsonCanObject) { 246 JsonCanObject o = (JsonCanObject) v; 247 if (o.array) 248 writeArray(o); 249 else 250 writeObject(o); 251 } else 252 throw new Error("not possible"); 253 } 254 gson.endArray(); 255 } 256 257 @Override 258 public void link(String href) { 259 // not used 260 } 261 262 263}