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    }