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 }