Coverage Report - org.seasar.teeda.ajax.JSONSerializer
 
Classes in this File Line Coverage Branch Coverage Complexity
JSONSerializer
90%
225/251
80%
137/171
5.25
 
 1  
 /*
 2  
  * Copyright 2004-2011 the Seasar Foundation and the Others.
 3  
  *
 4  
  * Licensed under the Apache License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  *     http://www.apache.org/licenses/LICENSE-2.0
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 13  
  * either express or implied. See the License for the specific language
 14  
  * governing permissions and limitations under the License.
 15  
  */
 16  
 package org.seasar.teeda.ajax;
 17  
 
 18  
 import java.lang.reflect.Array;
 19  
 import java.util.ArrayList;
 20  
 import java.util.Collection;
 21  
 import java.util.HashMap;
 22  
 import java.util.Iterator;
 23  
 import java.util.List;
 24  
 import java.util.Map;
 25  
 
 26  
 import org.seasar.framework.beans.BeanDesc;
 27  
 import org.seasar.framework.beans.PropertyDesc;
 28  
 import org.seasar.framework.beans.factory.BeanDescFactory;
 29  
 
 30  
 /**
 31  
  * JSON形式の文字列を解析します。
 32  
  * <p>
 33  
  * このクラスはTeeda以外でも使えるようにSeasar2に移植されました。
 34  
  * 今後はSeasar2のJSONSerializerを使用してください。
 35  
  * </p>
 36  
  * 
 37  
  * @author mopemope
 38  
  * @deprecated
 39  
  * @see org.seasar.framework.util.JSONSerializer
 40  
  */
 41  0
 public class JSONSerializer {
 42  
     private static final String COMMA = ",";
 43  
 
 44  
     private static final String COLON = ":";
 45  
 
 46  
     private static final String SINGLE_QUOTE = "'";
 47  
 
 48  
     private static final String DOUBLE_QUOTE = "\"";
 49  
 
 50  
     private static final String NULL_STRING = "null";
 51  
 
 52  
     private static final String TRUE_STRING = "true";
 53  
 
 54  
     private static final String FALSE_STRING = "false";
 55  
 
 56  
     private static final String START_BRACKET = "[";
 57  
 
 58  
     private static final String END_BRACKET = "]";
 59  
 
 60  
     private static final String START_BRACE = "{";
 61  
 
 62  
     private static final String END_BRACE = "}";
 63  
 
 64  
     /**
 65  
      * ObjectをJSONにシリアライズします。
 66  
      * 
 67  
      * @param o
 68  
      *            シリアライズ対象{@link java.lang.Object}
 69  
      * @return JSON形式の文字列
 70  
      */
 71  
     public static String serialize(Object o) {
 72  39
         StringBuffer buf = new StringBuffer(100);
 73  39
         appendSerializeObject(buf, o);
 74  37
         return buf.toString();
 75  
     }
 76  
 
 77  
     /**
 78  
      * 指定したバッファにJSONシリアライズした結果を追加します。
 79  
      * 
 80  
      * @param buf
 81  
      *            {@link java.lang.StringBuffer}
 82  
      * @param o
 83  
      *            シリアライズ対象{@link java.lang.Object}
 84  
      */
 85  
     public static void appendSerializeObject(StringBuffer buf, Object o) {
 86  146
         if (o == null) {
 87  13
             buf.append(JSONSerializer.NULL_STRING);
 88  133
         } else if (o instanceof String) {
 89  27
             buf.append(quote((String) o));
 90  106
         } else if (o instanceof Float) {
 91  2
             appendSerializeFloat(buf, (Float) o);
 92  104
         } else if (o instanceof Double) {
 93  9
             appendSerializeDouble(buf, (Double) o);
 94  95
         } else if (o instanceof Number) {
 95  27
             buf.append(o.toString());
 96  68
         } else if (o instanceof Boolean) {
 97  9
             appendSerializeBoolean(buf, (Boolean) o);
 98  59
         } else if (o instanceof Collection) {
 99  3
             appendSerializeArray(buf, ((Collection) o).toArray());
 100  56
         } else if (o instanceof Object[]) {
 101  16
             appendSerializeArray(buf, (Object[]) o);
 102  40
         } else if (o instanceof Map) {
 103  16
             appendSerializeMap(buf, (Map) o);
 104  24
         } else if (o.getClass().isArray()) {
 105  9
             appendSerializeObjectArray(buf, o);
 106  
         } else {
 107  15
             appendSerializeBean(buf, o);
 108  
         }
 109  144
     }
 110  
 
 111  
     /**
 112  
      * 指定したバッファにJSONシリアライズした結果を追加します。
 113  
      * 
 114  
      * @param buf
 115  
      *            {@link java.lang.StringBuffer}
 116  
      * @param f
 117  
      *            シリアライズ対象{@link java.lang.Float}
 118  
      */
 119  
     public static void appendSerializeFloat(StringBuffer buf, Float f) {
 120  2
         if (f.isNaN() || f.isInfinite()) {
 121  1
             throw new IllegalArgumentException(f.toString());
 122  
         }
 123  1
         buf.append(f.toString());
 124  1
     }
 125  
 
 126  
     /**
 127  
      * 指定したバッファにJSONシリアライズした結果を追加します。
 128  
      * 
 129  
      * @param buf
 130  
      *            {@link java.lang.StringBuffer}
 131  
      * @param d
 132  
      *            シリアライズ対象{@link java.lang.Double}
 133  
      */
 134  
     public static void appendSerializeDouble(StringBuffer buf, Double d) {
 135  9
         if (d.isNaN() || d.isInfinite()) {
 136  1
             throw new IllegalArgumentException(d.toString());
 137  
         }
 138  8
         buf.append(d.toString());
 139  8
     }
 140  
 
 141  
     /**
 142  
      * 指定したバッファにJSONシリアライズした結果を追加します。
 143  
      * 
 144  
      * @param buf
 145  
      *            {@link java.lang.StringBuffer}
 146  
      * @param b
 147  
      *            シリアライズ対象{@link java.lang.Boolean}
 148  
      */
 149  
     public static void appendSerializeBoolean(StringBuffer buf, Boolean b) {
 150  9
         if (Boolean.TRUE.equals(b)) {
 151  6
             buf.append(JSONSerializer.TRUE_STRING);
 152  
         } else {
 153  3
             buf.append(JSONSerializer.FALSE_STRING);
 154  
         }
 155  9
     }
 156  
 
 157  
     /**
 158  
      * 指定したバッファにJSONシリアライズした結果を追加します。
 159  
      * 
 160  
      * @param buf
 161  
      *            {@link java.lang.StringBuffer}
 162  
      * @param array
 163  
      *            シリアライズ対象{@link java.lang.Object}配列
 164  
      */
 165  
     public static void appendSerializeArray(StringBuffer buf, Object[] array) {
 166  19
         int length = array.length;
 167  19
         buf.append(JSONSerializer.START_BRACKET);
 168  59
         for (int i = 0; i < length; ++i) {
 169  40
             appendSerializeObject(buf, array[i]);
 170  40
             buf.append(JSONSerializer.COMMA);
 171  
         }
 172  19
         if (length > 0) {
 173  17
             buf.setLength(buf.length() - 1);
 174  
         }
 175  19
         buf.append(JSONSerializer.END_BRACKET);
 176  19
     }
 177  
 
 178  
     /**
 179  
      * 指定したバッファにJSONシリアライズした結果を追加します。
 180  
      * 
 181  
      * @param buf
 182  
      *            {@link java.lang.StringBuffer}
 183  
      * @param map
 184  
      *            シリアライズ対象{@link java.util.Map}
 185  
      */
 186  
     public static void appendSerializeMap(StringBuffer buf, Map map) {
 187  16
         buf.append(JSONSerializer.START_BRACE);
 188  16
         for (Iterator i = map.keySet().iterator(); i.hasNext();) {
 189  18
             String key = (String) i.next();
 190  18
             buf.append(quote(key) + JSONSerializer.COLON);
 191  18
             appendSerializeObject(buf, map.get(key));
 192  18
             buf.append(JSONSerializer.COMMA);
 193  
         }
 194  16
         if (map.size() > 0) {
 195  14
             buf.setLength(buf.length() - 1);
 196  
         }
 197  16
         buf.append(JSONSerializer.END_BRACE);
 198  16
     }
 199  
 
 200  
     /**
 201  
      * 指定したバッファにJSONシリアライズした結果を追加します。
 202  
      * 
 203  
      * @param buf
 204  
      *            {@link java.lang.StringBuffer}
 205  
      * @param bean
 206  
      *            シリアライズ対象{@link java.lang.Object}
 207  
      */
 208  
     public static void appendSerializeBean(StringBuffer buf, Object bean) {
 209  15
         buf.append(JSONSerializer.START_BRACE);
 210  15
         BeanDesc beanDesc = BeanDescFactory.getBeanDesc(bean.getClass());
 211  43
         for (int i = 0; i < beanDesc.getPropertyDescSize(); ++i) {
 212  28
             PropertyDesc pd = beanDesc.getPropertyDesc(i);
 213  28
             buf.append(pd.getPropertyName() + JSONSerializer.COLON);
 214  28
             appendSerializeObject(buf, pd.getValue(bean));
 215  28
             buf.append(JSONSerializer.COMMA);
 216  
         }
 217  15
         if (beanDesc.getPropertyDescSize() > 0) {
 218  15
             buf.setLength(buf.length() - 1);
 219  
         }
 220  15
         buf.append(JSONSerializer.END_BRACE);
 221  15
     }
 222  
 
 223  
     /**
 224  
      * 指定したバッファにJSONシリアライズした結果を追加します。
 225  
      * 
 226  
      * @param buf
 227  
      *            {@link java.lang.StringBuffer}
 228  
      * @param o
 229  
      *            シリアライズ対象{@link java.lang.Object}
 230  
      */
 231  
     public static void appendSerializeObjectArray(StringBuffer buf, Object o) {
 232  9
         int length = Array.getLength(o);
 233  9
         buf.append(JSONSerializer.START_BRACKET);
 234  30
         for (int i = 0; i < length; i++) {
 235  21
             Object value = Array.get(o, i);
 236  21
             appendSerializeObject(buf, value);
 237  21
             buf.append(JSONSerializer.COMMA);
 238  
         }
 239  9
         if (length > 0) {
 240  9
             buf.setLength(buf.length() - 1);
 241  
         }
 242  9
         buf.append(JSONSerializer.END_BRACKET);
 243  9
     }
 244  
 
 245  
     /**
 246  
      * 文字列を引用付で囲みます。
 247  
      * 
 248  
      * @param str
 249  
      *            対象の文字列
 250  
      * @return 引用付で囲まれた{@link java.lang.String}
 251  
      */
 252  
     public static String quote(String str) {
 253  52
         if (str == null || str.length() == 0) {
 254  0
             return "\"\"";
 255  
         }
 256  52
         char current = 0;
 257  52
         int len = str.length();
 258  52
         StringBuffer sb = new StringBuffer(len + 4);
 259  52
         sb.append('"');
 260  216
         for (int i = 0; i < len; ++i) {
 261  164
             current = str.charAt(i);
 262  164
             switch (current) {
 263  
             case '\\':
 264  
             case '/':
 265  
             case '"':
 266  4
                 sb.append('\\');
 267  4
                 sb.append(current);
 268  4
                 break;
 269  
             case '\b':
 270  0
                 sb.append("\\b");
 271  0
                 break;
 272  
             case '\t':
 273  1
                 sb.append("\\t");
 274  1
                 break;
 275  
             case '\n':
 276  1
                 sb.append("\\n");
 277  1
                 break;
 278  
             case '\f':
 279  0
                 sb.append("\\f");
 280  0
                 break;
 281  
             case '\r':
 282  0
                 sb.append("\\r");
 283  0
                 break;
 284  
             default:
 285  158
                 if (current < ' ') {
 286  1
                     String t = "000" + Integer.toHexString(current);
 287  1
                     sb.append("\\u" + t.substring(t.length() - 4));
 288  
                 } else {
 289  157
                     sb.append(current);
 290  
                 }
 291  
             }
 292  
         }
 293  52
         sb.append('"');
 294  52
         return sb.toString();
 295  
     }
 296  
 
 297  
     /**
 298  
      * 指定した文字列がJSONのObject形式か判断します。
 299  
      * 
 300  
      * @param str
 301  
      *            対象の文字列
 302  
      * @return JSONのObject形式であればtrue、そうでなければfalse
 303  
      */
 304  
     public static boolean isObject(String str) {
 305  58
         return str.startsWith(JSONSerializer.START_BRACE) &&
 306  
                 str.endsWith(JSONSerializer.END_BRACE);
 307  
     }
 308  
 
 309  
     /**
 310  
      * 指定した文字列がJSONのArray形式か判断します。
 311  
      * 
 312  
      * @param str
 313  
      *            対象の文字列
 314  
      * @return JSONのArray形式であればtrue、そうでなければfalse
 315  
      */
 316  
     public static boolean isArray(String str) {
 317  54
         return str.startsWith(JSONSerializer.START_BRACKET) &&
 318  
                 str.endsWith(JSONSerializer.END_BRACKET);
 319  
     }
 320  
 
 321  
     /**
 322  
      * 指定した文字列がJSONのString形式か判断します。
 323  
      * 
 324  
      * @param str
 325  
      *            対象の文字列
 326  
      * @return JSONのString形式であればtrue、そうでなければfalse
 327  
      */
 328  
     public static boolean isString(String str) {
 329  74
         return (str.startsWith(JSONSerializer.SINGLE_QUOTE) &&
 330  
                 str.endsWith(JSONSerializer.SINGLE_QUOTE) || str
 331  
                 .startsWith(JSONSerializer.DOUBLE_QUOTE) &&
 332  
                 str.endsWith(JSONSerializer.DOUBLE_QUOTE));
 333  
     }
 334  
 
 335  
     /**
 336  
      * 指定したJSON文字列を評価します。
 337  
      * 
 338  
      * @param str
 339  
      *            対象の文字列
 340  
      * @return 評価された{@link javac.lang.Object}
 341  
      */
 342  
     public static Object eval(String str) {
 343  4
         if (JSONSerializer.isObject(str)) {
 344  4
             return JSONSerializer.evalMap(str);
 345  0
         } else if (JSONSerializer.isArray(str)) {
 346  0
             return JSONSerializer.evalArray(str);
 347  0
         } else if (JSONSerializer.isString(str)) {
 348  0
             return JSONSerializer.evalString(str);
 349  
         } else {
 350  0
             return JSONSerializer.evalInt(str);
 351  
         }
 352  
     }
 353  
 
 354  
     /**
 355  
      * 指定したJSON文字列を評価します。
 356  
      * 
 357  
      * @param str
 358  
      *            対象の文字列
 359  
      * @return 評価された{@link javac.util.Map}
 360  
      */
 361  
     public static Map evalMap(String str) {
 362  28
         Map map = new HashMap();
 363  28
         StringBuffer buf = new StringBuffer();
 364  28
         String key = null;
 365  28
         String value = null;
 366  28
         boolean valueParse = false;
 367  28
         boolean isListedData = false;
 368  28
         boolean isMappedData = false;
 369  371
         for (int i = 0; i < str.length(); i++) {
 370  343
             char c = str.charAt(i);
 371  343
             switch (c) {
 372  
             case '{':
 373  35
                 if (valueParse) {
 374  7
                     String sub = str.substring(i, str.length() - 1);
 375  7
                     int count = 0;
 376  215
                     for (int j = 0; j < sub.length(); ++j) {
 377  215
                         char sc = sub.charAt(j);
 378  215
                         if (sc == '{') {
 379  11
                             count++;
 380  11
                             continue;
 381  
                         }
 382  204
                         if (sc == '}' && count > 1) {
 383  4
                             count--;
 384  200
                         } else if (sc == '}' && count == 1) {
 385  7
                             String mapStr = sub.substring(0, j + 1);
 386  7
                             Map submap = JSONSerializer.evalMap(mapStr);
 387  7
                             map.put(key, submap);
 388  7
                             i = i + j;
 389  7
                             isMappedData = true;
 390  7
                             break;
 391  
                         }
 392  
                     }
 393  
                 }
 394  
                 break;
 395  
             case '}':
 396  28
                 break;
 397  
             case '[':
 398  14
                 if (valueParse) {
 399  14
                     String sub = str.substring(i, str.length() - 1);
 400  14
                     int count = 0;
 401  414
                     for (int j = 0; j < sub.length(); ++j) {
 402  414
                         char sc = sub.charAt(j);
 403  414
                         if (sc == '[') {
 404  24
                             count++;
 405  24
                             continue;
 406  
                         }
 407  390
                         if (sc == ']' && count > 1) {
 408  10
                             count--;
 409  380
                         } else if (sc == ']' && count == 1) {
 410  14
                             String arrayStr = sub.substring(0, j + 1);
 411  14
                             List list = JSONSerializer.evalArray(arrayStr);
 412  14
                             map.put(key, list);
 413  14
                             i = i + j;
 414  14
                             isListedData = true;
 415  14
                             break;
 416  
                         }
 417  
                     }
 418  
                 }
 419  
                 break;
 420  
             case ']':
 421  0
                 break;
 422  
             case ':':
 423  32
                 key = JSONSerializer.evalString(buf.toString().trim());
 424  32
                 valueParse = true;
 425  32
                 buf = new StringBuffer();
 426  32
                 isListedData = false;
 427  32
                 isMappedData = false;
 428  32
                 break;
 429  
             case ',':
 430  4
                 if (!isListedData && !isMappedData) {
 431  0
                     value = buf.toString().trim();
 432  0
                     valueParse = false;
 433  0
                     buf = new StringBuffer();
 434  0
                     evalAndAddMap(key, value, map);
 435  
                 }
 436  4
                 isListedData = false;
 437  4
                 isMappedData = false;
 438  4
                 break;
 439  
             default:
 440  230
                 buf.append(c);
 441  
                 break;
 442  
             }
 443  
         }
 444  28
         if (buf.length() > 0) {
 445  11
             value = buf.toString().trim();
 446  
         }
 447  28
         if (value != null) {
 448  11
             evalAndAddMap(key, value, map);
 449  
         }
 450  28
         return map;
 451  
     }
 452  
 
 453  
     /**
 454  
      * 指定したJSON文字列を評価します。
 455  
      * 
 456  
      * @param str
 457  
      *            対象の文字列
 458  
      * @return 評価された{@link javac.util.List}
 459  
      */
 460  
     public static List evalArray(String str) {
 461  20
         List list = new ArrayList();
 462  20
         StringBuffer buf = new StringBuffer();
 463  20
         String value = null;
 464  20
         boolean isMappedData = false;
 465  224
         for (int i = 1; i < str.length() - 1; i++) {
 466  204
             char c = str.charAt(i);
 467  204
             switch (c) {
 468  
             case '{':
 469  11
                 String sub = str.substring(i, str.length() - 1);
 470  11
                 int count = 0;
 471  309
                 for (int j = 0; j < sub.length(); ++j) {
 472  309
                     char sc = sub.charAt(j);
 473  309
                     if (sc == '{') {
 474  13
                         count++;
 475  13
                         continue;
 476  
                     }
 477  296
                     if (sc == '}' && count > 1) {
 478  2
                         count--;
 479  294
                     } else if (sc == '}' && count == 1) {
 480  11
                         String mapStr = sub.substring(0, j + 1);
 481  11
                         Map map = JSONSerializer.evalMap(mapStr);
 482  11
                         list.add(map);
 483  11
                         i = i + j;
 484  11
                         isMappedData = true;
 485  11
                         break;
 486  
                     }
 487  
                 }
 488  11
                 break;
 489  
             case '}':
 490  0
                 break;
 491  
             case '[':
 492  1
                 buf.append(c);
 493  1
                 break;
 494  
             case ']':
 495  1
                 buf.append(c);
 496  1
                 break;
 497  
             case ':':
 498  0
                 break;
 499  
             case ',':
 500  30
                 if (!isMappedData) {
 501  25
                     value = buf.toString().trim();
 502  25
                     buf = new StringBuffer();
 503  25
                     JSONSerializer.evalAndAddList(value, list);
 504  
                 }
 505  30
                 isMappedData = false;
 506  30
                 break;
 507  
             default:
 508  161
                 buf.append(c);
 509  
                 break;
 510  
             }
 511  
         }
 512  20
         if (buf.length() > 0) {
 513  15
             value = buf.toString().trim();
 514  
         }
 515  20
         if (value != null) {
 516  15
             JSONSerializer.evalAndAddList(value, list);
 517  
         }
 518  20
         return list;
 519  
     }
 520  
 
 521  
     private static void evalAndAddList(String value, List list) {
 522  40
         if (JSONSerializer.isObject(value)) {
 523  0
             list.add(JSONSerializer.evalMap(value));
 524  40
         } else if (JSONSerializer.isArray(value)) {
 525  0
             list.add(JSONSerializer.evalArray(value));
 526  
         } else {
 527  40
             Integer intValue = evalInt(value);
 528  40
             if (intValue != null) {
 529  10
                 list.add(intValue);
 530  
             } else {
 531  30
                 list.add(JSONSerializer.evalString(value));
 532  
             }
 533  
         }
 534  40
     }
 535  
 
 536  
     private static void evalAndAddMap(String key, String value, Map map) {
 537  11
         if (JSONSerializer.isObject(value)) {
 538  0
             Map v = JSONSerializer.evalMap(value);
 539  0
             map.put(key, v);
 540  11
         } else if (JSONSerializer.isArray(value)) {
 541  0
             List list = JSONSerializer.evalArray(value);
 542  0
             map.put(key, list);
 543  
         } else {
 544  11
             Integer intValue = evalInt(value);
 545  11
             if (intValue != null) {
 546  2
                 map.put(key, intValue);
 547  
             } else {
 548  9
                 map.put(key, JSONSerializer.evalString(value));
 549  
             }
 550  
         }
 551  11
     }
 552  
 
 553  
     /**
 554  
      * 指定したJSON文字列を評価します。
 555  
      * 
 556  
      * @param str
 557  
      *            対象の文字列
 558  
      * @return 評価された{@link javac.lang.String}
 559  
      */
 560  
     public static String evalString(String str) {
 561  71
         if (JSONSerializer.isString(str)) {
 562  64
             return str.substring(1, str.length() - 1);
 563  
         }
 564  7
         return str;
 565  
     }
 566  
 
 567  
     /**
 568  
      * 指定したJSON文字列を評価します。
 569  
      * 
 570  
      * @param str
 571  
      *            対象の文字列
 572  
      * @return 評価された{@link javac.lang.Integer}
 573  
      */
 574  
     public static Integer evalInt(String str) {
 575  
         try {
 576  51
             int i = Integer.parseInt(str);
 577  12
             return new Integer(i);
 578  39
         } catch (NumberFormatException e) {
 579  39
             return null;
 580  
         }
 581  
     }
 582  
 
 583  
 }