001package gudusoft.gsqlparser.util.json; 002 003import gudusoft.gsqlparser.dlineage.util.BeanUtil; 004 005import java.io.IOException; 006import java.io.Serializable; 007import java.io.Writer; 008import java.lang.reflect.Array; 009import java.text.StringCharacterIterator; 010import java.util.LinkedHashMap; 011import java.util.List; 012import java.util.Map; 013 014@SuppressWarnings("rawtypes") 015public class JSONSerializer implements Serializable { 016 017 private static final long serialVersionUID = -947149613761603468L; 018 019 private boolean ignoreId = false; 020 021 public JSONSerializer(boolean ignoreId) { 022 this.ignoreId = ignoreId; 023 } 024 025 public JSONSerializer() { 026 } 027 028 private void check(Object obj) { 029 if (obj == null || !(obj instanceof LinkedHashMap || obj instanceof List)) { 030 throw new IllegalArgumentException("Invalid JSON structure"); 031 } 032 } 033 034 public String serialize(List list) { 035 check(list); 036 StringBuilder sb = new StringBuilder("["); 037 for (Object element : list) { 038 if (element == null) { 039 continue; // Skip null values 040 } 041 if (element instanceof List) 042 sb.append(serializeList((List) element)); 043 else if (element.getClass().isArray()) 044 sb.append(serializeArray(element)); 045 else if (element instanceof LinkedHashMap) 046 sb.append(serialize(BeanUtil.bean2Map(element))).append(","); 047 else 048 appendValue(sb, element); 049 } 050 String result = sb.toString(); 051 if (result.endsWith(",")) 052 result = result.substring(0, result.length() - 1); 053 return result + "]"; 054 } 055 056 public String serialize(Map map) { 057 check(map); 058 StringBuilder sb = new StringBuilder("{"); 059 for (Object k : map.keySet()) { 060 String key = (String) k; 061 if (ignoreId && ("id".equals(key))) { 062 continue; 063 } 064 Object val = map.get(key); 065 if (val == null) { 066 continue; // Skip null values 067 } 068 if (val instanceof List) 069 sb.append("\"").append(key).append("\":[").append(serializeList((List) val)).append("]").append(","); 070 else if (val.getClass().isArray()) 071 sb.append("\"").append(key).append("\":[").append(serializeArray(val)).append("]").append(","); 072 else if (val instanceof LinkedHashMap) 073 sb.append("\"").append(key).append("\":").append(serialize(BeanUtil.bean2Map(val))).append(","); 074 else 075 appendEntry(sb, key, val); 076 } 077 String result = sb.toString(); 078 if (result.endsWith(",")) 079 result = result.substring(0, result.length() - 1); 080 return result + "}"; 081 } 082 083 public void serialize(Map map, Writer writer) throws IOException { 084 check(map); 085 writer.write("{"); 086 boolean first = true; 087 for (Object k : map.keySet()) { 088 String key = (String) k; 089 if (ignoreId && ("id".equals(key))) { 090 continue; 091 } 092 Object val = map.get(key); 093 if (val == null) { 094 continue; 095 } 096 if (!first) { 097 writer.write(","); 098 } 099 first = false; 100 if (val instanceof List) { 101 writer.write("\"" + key + "\":["); 102 serializeList((List) val, writer); 103 writer.write("]"); 104 } else if (val.getClass().isArray()) { 105 writer.write("\"" + key + "\":["); 106 serializeArray(val, writer); 107 writer.write("]"); 108 } else if (val instanceof LinkedHashMap) { 109 writer.write("\"" + key + "\":"); 110 serialize((Map) BeanUtil.bean2Map(val), writer); 111 } else { 112 appendEntry(writer, key, val); 113 } 114 } 115 writer.write("}"); 116 } 117 118 public void serialize(List list, Writer writer) throws IOException { 119 check(list); 120 writer.write("["); 121 boolean first = true; 122 for (Object element : list) { 123 if (element == null) { 124 continue; 125 } 126 if (!first) { 127 writer.write(","); 128 } 129 first = false; 130 if (element instanceof List) { 131 serializeList((List) element, writer); 132 } else if (element.getClass().isArray()) { 133 serializeArray(element, writer); 134 } else if (element instanceof LinkedHashMap) { 135 serialize((Map) BeanUtil.bean2Map(element), writer); 136 } else { 137 appendValue(writer, element); 138 } 139 } 140 writer.write("]"); 141 } 142 143 private String serializeList(List list) { 144 StringBuilder sb = new StringBuilder(); 145 int n = list.size(); 146 for (int i = 0; i < n; i++) { 147 Object obj = list.get(i); 148 if (obj == null) { 149 continue; // Skip null values 150 } 151 if (obj instanceof String) 152 sb.append("\"").append(escape((String) obj)).append("\""); 153 else 154 sb.append(serialize(BeanUtil.bean2Map(obj))); 155 if (i < n - 1) 156 sb.append(","); 157 } 158 return sb.toString(); 159 } 160 161 private void serializeList(List list, Writer writer) throws IOException { 162 int n = list.size(); 163 for (int i = 0; i < n; i++) { 164 Object obj = list.get(i); 165 if (obj == null) { 166 continue; 167 } 168 if (obj instanceof String) 169 writer.write("\"" + escape((String) obj) + "\""); 170 else 171 serialize((Map) BeanUtil.bean2Map(obj), writer); 172 if (i < n - 1) 173 writer.write(","); 174 } 175 } 176 177 private String serializeArray(Object array) { 178 int n = Array.getLength(array); 179 StringBuilder sb = new StringBuilder(); 180 for (int i = 0; i < n; i++) { 181 Object obj = Array.get(array, i); 182 if (obj == null) { 183 continue; // Skip null values 184 } 185 if (obj instanceof String) 186 sb.append("\"").append(escape((String) obj)).append("\""); 187 else 188 sb.append(serialize(BeanUtil.bean2Map(obj))); 189 if (i < n - 1) 190 sb.append(","); 191 } 192 return sb.toString(); 193 } 194 195 private void serializeArray(Object array, Writer writer) throws IOException { 196 int n = Array.getLength(array); 197 for (int i = 0; i < n; i++) { 198 Object obj = Array.get(array, i); 199 if (obj == null) { 200 continue; 201 } 202 if (obj instanceof String) 203 writer.write("\"" + escape((String) obj) + "\""); 204 else 205 serialize((Map) BeanUtil.bean2Map(obj), writer); 206 if (i < n - 1) 207 writer.write(","); 208 } 209 } 210 211 private void appendEntry(StringBuilder sb, String key, Object val) { 212 boolean quote = false; 213 if (!(val instanceof String || val instanceof Number || val instanceof Boolean)) 214 val = serialize(BeanUtil.bean2Map(val)); 215 else if (val instanceof String) { 216 val = escape((String) val); 217 quote = true; 218 } 219 sb.append("\"").append(key).append("\":").append(quote ? "\"" : "").append(val).append(quote ? "\"" : "") 220 .append(","); 221 } 222 223 private void appendEntry(Writer writer, String key, Object val) throws IOException { 224 if (!(val instanceof String || val instanceof Number || val instanceof Boolean)) { 225 writer.write("\"" + key + "\":"); 226 serialize((Map) BeanUtil.bean2Map(val), writer); 227 } else if (val instanceof String) { 228 writer.write("\"" + key + "\":\"" + escape((String) val) + "\""); 229 } else { 230 writer.write("\"" + key + "\":" + val); 231 } 232 } 233 234 private void appendValue(StringBuilder sb, Object val) { 235 boolean quote = false; 236 if (!(val instanceof String || val instanceof Integer || val instanceof Long || val instanceof Boolean)) 237 val = serialize(BeanUtil.bean2Map(val)); 238 else if (val instanceof String) { 239 val = escape((String) val); 240 quote = true; 241 } 242 sb.append(quote ? "\"" : "").append(val).append(quote ? "\"" : "").append(","); 243 } 244 245 private void appendValue(Writer writer, Object val) throws IOException { 246 if (!(val instanceof String || val instanceof Integer || val instanceof Long || val instanceof Boolean)) { 247 serialize((Map) BeanUtil.bean2Map(val), writer); 248 } else if (val instanceof String) { 249 writer.write("\"" + escape((String) val) + "\""); 250 } else { 251 writer.write(val.toString()); 252 } 253 } 254 255 private static String escape(String str) { 256 StringBuilder sb = new StringBuilder(); 257 StringCharacterIterator it = new StringCharacterIterator(str); 258 char ch = it.current(); 259 while (ch != StringCharacterIterator.DONE) { 260 switch (ch) { 261 case '"': 262 sb.append("\\\""); 263 break; 264 case '\t': 265 sb.append("\\t"); 266 break; 267 case '\f': 268 sb.append("\\f"); 269 break; 270 case '\n': 271 sb.append("\\n"); 272 break; 273 case '\r': 274 sb.append("\\r"); 275 break; 276 case '\\': 277 sb.append("\\\\"); 278 break; 279 case '/': 280 sb.append("\\/"); 281 break; 282 case '\b': 283 sb.append("\\b"); 284 break; 285 default: 286 sb.append(ch); 287 } 288 ch = it.next(); 289 } 290 return sb.toString(); 291 } 292}