001 package net.sourceforge.javajson; 002 003 import java.util.HashMap; 004 import java.util.Map; 005 import java.util.regex.Pattern; 006 007 public class JsonValue { 008 private static Map<Character, String> escapeMap = new HashMap<Character, String>(); 009 static { 010 escapeMap.put('\\', "\\\\"); 011 escapeMap.put('\b', "\\b"); 012 escapeMap.put('\f', "\\f"); 013 escapeMap.put('\n', "\\n"); 014 escapeMap.put('\r', "\\r"); 015 escapeMap.put('\t', "\\t"); 016 escapeMap.put('\"', "\\\""); 017 escapeMap.put('\'', "\\\'"); 018 } 019 020 private JsonNativeType nativeType; 021 022 private Boolean boolVal; 023 024 private Double doubleVal; 025 026 private Float floatVal; 027 028 private JsonArray jsonArray; 029 030 private JsonObject jsonObject; 031 032 private Long longVal; 033 034 private String stringVal; 035 036 public JsonValue() { 037 setNull(); 038 } 039 040 public JsonValue(boolean val) { 041 setBoolean(val); 042 } 043 044 public JsonValue(double val) { 045 setDouble(val); 046 } 047 048 public JsonValue(float val) { 049 setFloat(val); 050 } 051 052 public JsonValue(int val) { 053 setInt(val); 054 } 055 056 public JsonValue(JsonArray val) { 057 setJsonArray(val); 058 } 059 060 public JsonValue(JsonObject val) { 061 setJsonObject(val); 062 } 063 064 public JsonValue(long val) { 065 setLong(val); 066 } 067 068 public JsonValue(String val) { 069 setString(val); 070 } 071 072 public JsonValue(Object val) { 073 if (val == null) 074 setNull(); 075 else if (val instanceof Float) 076 setFloat(((Float) val).floatValue()); 077 else if (val instanceof Double) 078 setDouble(((Double) val).doubleValue()); 079 else if (val instanceof Integer) 080 setInt(((Integer) val).intValue()); 081 else if (val instanceof Long) 082 setLong(((Long) val).longValue()); 083 else if (val instanceof Boolean) 084 setBoolean(((Boolean) val).booleanValue()); 085 else if (val instanceof String) 086 setString((String) val); 087 else if (val instanceof JsonObject) 088 setJsonObject((JsonObject) val); 089 else if (val instanceof JsonArray) 090 setJsonArray((JsonArray) val); 091 else 092 throw new ClassCastException("Unrecognized class"); 093 } 094 095 static public String byteToHex(byte b) { 096 char hexDigit[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 097 'a', 'b', 'c', 'd', 'e', 'f' }; 098 char[] array = { hexDigit[(b >> 4) & 0x0f], hexDigit[b & 0x0f] }; 099 return new String(array); 100 } 101 102 static public String charToEscaped(char c) { 103 byte hiByte = (byte) (c >>> 8); 104 byte loByte = (byte) (c & 0xff); 105 if (hiByte == 0) // if hi byte is 0, then assume not unicode 106 return String.valueOf(c); 107 else 108 return "\\u" + byteToHex(hiByte) + byteToHex(loByte); 109 } 110 111 public boolean getBoolean() { 112 if (boolVal != null) 113 return boolVal.booleanValue(); 114 else if (stringVal != null) 115 return "true".equals(stringVal); 116 else 117 return false; 118 } 119 120 public double getDouble() { 121 if (doubleVal != null) 122 return doubleVal.doubleValue(); 123 else if (longVal != null) 124 return longVal.doubleValue(); 125 else if (stringVal != null) 126 return Double.parseDouble(stringVal); 127 else 128 return 0; 129 } 130 131 public float getFloat() { 132 if (floatVal != null) 133 return floatVal.floatValue(); 134 else if (doubleVal != null) 135 return doubleVal.floatValue(); 136 else if (longVal != null) 137 return longVal.floatValue(); 138 else if (stringVal != null) 139 return Float.parseFloat(stringVal); 140 else 141 return 0f; 142 } 143 144 public int getInt() { 145 return (int) getLong(); 146 } 147 148 public JsonArray getJsonArray() { 149 if (jsonArray != null) 150 return jsonArray; 151 else 152 return null; 153 } 154 155 public JsonObject getJsonObject() { 156 if (jsonObject != null) 157 return jsonObject; 158 else 159 return null; 160 } 161 162 public long getLong() { 163 if (doubleVal != null) 164 return doubleVal.longValue(); 165 else if (longVal != null) 166 return longVal.longValue(); 167 // else if (stringVal != null) 168 // return Long.parseLong(stringVal); 169 else 170 return 0; 171 } 172 173 public String getString() { 174 if (doubleVal != null) 175 return doubleVal.toString(); 176 else if (longVal != null) 177 return longVal.toString(); 178 else if (stringVal != null) 179 return stringVal; 180 else 181 return null; 182 } 183 184 /** 185 * Returns the class of the value being used. For example, if setFloat or 186 * setDouble were used, Double.class is returned. If setInt or setLong is 187 * used, Long.class is returned. 188 * @deprecated User getNativeType instead 189 */ 190 @SuppressWarnings("unchecked") 191 public Class getValueClass() { 192 if (doubleVal != null) 193 return Double.class; 194 else if (longVal != null) 195 return Long.class; 196 else if (jsonArray != null) 197 return JsonArray.class; 198 else if (jsonObject != null) 199 return JsonObject.class; 200 else 201 return null; 202 } 203 204 public JsonNativeType getNativeType() { 205 return this.nativeType; 206 } 207 208 /** 209 * Checks if the value is a boolean 210 * 211 * @return 212 */ 213 public boolean isBoolean() { 214 return nativeType == JsonNativeType.BOOLEAN; 215 } 216 217 /** 218 * Checks if the value can be safely converted to this type without losing 219 * data. This is true of any type of number 220 * 221 * @return 222 */ 223 public boolean isDouble() { 224 return nativeType == JsonNativeType.LONG 225 || nativeType == JsonNativeType.INTEGER 226 || nativeType == JsonNativeType.FLOAT 227 || nativeType == JsonNativeType.DOUBLE; 228 } 229 230 /** 231 * Checks if the value can be safely converted to this type without losing. 232 * It returns the same as isDouble as long as the value is not out of range 233 * TODO: check out of range errors 234 * 235 * @return 236 */ 237 public boolean isFloat() { 238 return isDouble(); 239 } 240 241 /** 242 * Checks if the value can be safely converted to this type without losing 243 * data. It returns the same as isLong as long as the value is not out of 244 * range TODO: check out of range errors 245 * 246 * @return 247 */ 248 public boolean isInt() { 249 boolean ret = isLong(); 250 if (ret) { 251 // check if in range 252 long l = getLong(); 253 if (l < Integer.MIN_VALUE || l > Integer.MAX_VALUE) 254 ret = false; 255 } 256 return ret; 257 } 258 259 public boolean isJsonArray() { 260 return (jsonArray != null); 261 } 262 263 public boolean isJsonObject() { 264 return (jsonObject != null); 265 } 266 267 /** 268 * Checks if the value can be safely converted to this type without losing 269 * data 270 * 271 * @return 272 */ 273 public boolean isLong() { 274 return nativeType == JsonNativeType.LONG 275 || nativeType == JsonNativeType.INTEGER; 276 } 277 278 public boolean isNull() { 279 return nativeType == JsonNativeType.NULL; 280 } 281 282 /** 283 * Checks if the type of this value is similar to that of another value. 284 * 285 * @param obj 286 * @return 287 */ 288 public boolean isSimilar(JsonValue obj) { 289 if (obj.nativeType != nativeType) 290 return false; 291 if (nativeType == JsonNativeType.JSON_OBJECT) 292 return jsonObject.isSimilar(obj.jsonObject); 293 else if (nativeType == JsonNativeType.JSON_ARRAY) 294 return jsonArray.isSimilar(obj.jsonArray); 295 else 296 return true; 297 } 298 299 /** 300 * Returns true if the value is a number, boolean or string 301 */ 302 public boolean isString() { 303 return !isNull() && !isJsonArray() && !isJsonObject(); 304 } 305 306 public void setBoolean(boolean b) { 307 setNull(); 308 nativeType = JsonNativeType.BOOLEAN; 309 boolVal = b ? Boolean.TRUE : Boolean.FALSE; 310 } 311 312 public void setDouble(double d) { 313 setNull(); 314 nativeType = JsonNativeType.DOUBLE; 315 doubleVal = new Double(d); 316 } 317 318 public void setFloat(float f) { 319 setNull(); 320 floatVal = new Float(f); 321 nativeType = JsonNativeType.FLOAT; 322 } 323 324 public void setInt(int i) { 325 setLong(i); 326 nativeType = JsonNativeType.INTEGER; 327 } 328 329 public void setJsonArray(JsonArray array) { 330 setNull(); 331 if (array != null) { 332 nativeType = JsonNativeType.JSON_ARRAY; 333 jsonArray = array; 334 } 335 } 336 337 public void setJsonObject(JsonObject object) { 338 setNull(); 339 if (object != null) { 340 nativeType = JsonNativeType.JSON_OBJECT; 341 jsonObject = object; 342 } 343 } 344 345 public void setLong(long l) { 346 setNull(); 347 nativeType = JsonNativeType.LONG; 348 longVal = new Long(l); 349 } 350 351 /** Just sets the value to null */ 352 protected void setNull() { 353 nativeType = JsonNativeType.NULL; 354 boolVal = null; 355 doubleVal = null; 356 floatVal = null; 357 longVal = null; 358 jsonArray = null; 359 jsonObject = null; 360 stringVal = null; 361 } 362 363 public void setString(String s) { 364 setNull(); 365 366 if (s != null) { 367 // check if its a long or double 368 if (Pattern.matches("-?\\d+", s)) 369 setLong(Long.parseLong(s)); 370 else if (Pattern.matches("-?\\d*\\.\\d*", s)) 371 setDouble(Double.parseDouble(s)); 372 stringVal = s; 373 nativeType = JsonNativeType.STRING; 374 } 375 } 376 377 /** 378 * Escapes strings for toString 379 * 380 * @param str 381 * @return 382 */ 383 public static String escape(String str) { 384 StringBuffer sb = new StringBuffer(); 385 for (int i = 0; i < str.length(); i++) { 386 char c = str.charAt(i); 387 if (escapeMap.containsKey(c)) { 388 sb.append(escapeMap.get(c)); 389 } else { 390 // sb.append(c); 391 sb.append(charToEscaped(c)); 392 } 393 } 394 return sb.toString(); 395 } 396 397 @Override 398 public String toString() { 399 if (nativeType == JsonNativeType.BOOLEAN) 400 return boolVal ? "true" : "false"; 401 else if (nativeType == JsonNativeType.LONG 402 || nativeType == JsonNativeType.INTEGER) 403 return longVal.toString(); 404 else if (nativeType == JsonNativeType.DOUBLE) 405 return doubleVal.toString(); 406 else if (nativeType == JsonNativeType.FLOAT) 407 return floatVal.toString(); 408 else if (nativeType == JsonNativeType.JSON_OBJECT) 409 return jsonObject.toString(); 410 else if (nativeType == JsonNativeType.JSON_ARRAY) 411 return jsonArray.toString(); 412 if (nativeType == JsonNativeType.STRING) 413 return "\"" + JsonValue.escape(stringVal) + "\""; 414 else 415 return "null"; 416 } 417 418 protected String toString(int spacing, int margin) { 419 StringBuffer sb = new StringBuffer(); 420 if (this.isJsonObject()) 421 sb.append(jsonObject.toString(spacing, margin)); 422 else if (this.isJsonArray()) 423 sb.append(jsonArray.toString(spacing, margin)); 424 else 425 sb.append(toString()); 426 return sb.toString(); 427 } 428 429 }