1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package net.sf.json.util;
18
19 import java.math.BigDecimal;
20 import java.math.BigInteger;
21 import java.util.Collection;
22 import java.util.HashMap;
23 import java.util.Iterator;
24 import java.util.List;
25 import java.util.Map;
26
27 import net.sf.ezmorph.MorphUtils;
28 import net.sf.ezmorph.MorpherRegistry;
29 import net.sf.ezmorph.bean.MorphDynaBean;
30 import net.sf.ezmorph.bean.MorphDynaClass;
31 import net.sf.json.JSON;
32 import net.sf.json.JSONArray;
33 import net.sf.json.JSONException;
34 import net.sf.json.JSONFunction;
35 import net.sf.json.JSONNull;
36 import net.sf.json.JSONObject;
37 import net.sf.json.JSONString;
38 import net.sf.json.JsonConfig;
39 import net.sf.json.regexp.RegexpUtils;
40
41 import org.apache.commons.beanutils.DynaBean;
42
43
44
45
46
47
48
49 public final class JSONUtils {
50
51 public static final String DOUBLE_QUOTE = "\"";
52
53 public static final String SINGLE_QUOTE = "'";
54
55 private static final String FUNCTION_BODY_PATTERN = "^function[ ]?\\(.*?\\)[ \n\t]*\\{(.*?)\\}$";
56 private static final String FUNCTION_HEADER_PATTERN = "^function[ ]?\\(.*?\\)$";
57 private static final String FUNCTION_PARAMS_PATTERN = "^function[ ]?\\((.*?)\\).*";
58 private static final String FUNCTION_PATTERN = "^function[ ]?\\(.*?\\)[ \n\t]*\\{.*?\\}$";
59 private static final String FUNCTION_PREFIX = "function";
60
61 private static final MorpherRegistry morpherRegistry = new MorpherRegistry();
62
63 static{
64
65 MorphUtils.registerStandardMorphers( morpherRegistry );
66 }
67
68
69
70
71
72
73
74 public static String convertToJavaIdentifier( String key ) {
75 return convertToJavaIdentifier( key, new JsonConfig() );
76 }
77
78
79
80
81
82
83
84 public static String convertToJavaIdentifier( String key, JsonConfig jsonConfig ) {
85 try{
86 return jsonConfig.getJavaIdentifierTransformer()
87 .transformToJavaIdentifier( key );
88 }catch( JSONException jsone ){
89 throw jsone;
90 }catch( Exception e ){
91 throw new JSONException( e );
92 }
93 }
94
95
96
97
98
99
100
101
102 public static String doubleToString( double d ) {
103 if( Double.isInfinite( d ) || Double.isNaN( d ) ){
104 return "null";
105 }
106
107
108
109 String s = Double.toString( d );
110 if( s.indexOf( '.' ) > 0 && s.indexOf( 'e' ) < 0 && s.indexOf( 'E' ) < 0 ){
111 while( s.endsWith( "0" ) ){
112 s = s.substring( 0, s.length() - 1 );
113 }
114 if( s.endsWith( "." ) ){
115 s = s.substring( 0, s.length() - 1 );
116 }
117 }
118 return s;
119 }
120
121
122
123
124 public static String getFunctionBody( String function ) {
125 return RegexpUtils.getMatcher( FUNCTION_BODY_PATTERN, true ).getGroupIfMatches( function, 1 );
126 }
127
128
129
130
131 public static String getFunctionParams( String function ) {
132 return RegexpUtils.getMatcher( FUNCTION_PARAMS_PATTERN, true ).getGroupIfMatches( function, 1 );
133 }
134
135
136
137
138 public static Class getInnerComponentType( Class type ) {
139 if( !type.isArray() ){
140 return type;
141 }
142 return getInnerComponentType( type.getComponentType() );
143 }
144
145
146
147
148 public static MorpherRegistry getMorpherRegistry() {
149 return morpherRegistry;
150 }
151
152
153
154
155 public static Map getProperties( JSONObject jsonObject ) {
156 Map properties = new HashMap();
157 for( Iterator keys = jsonObject.keys(); keys.hasNext(); ){
158 String key = (String) keys.next();
159
160
161
162
163 properties.put( key, getTypeClass( jsonObject.get( key ) ) );
164 }
165 return properties;
166 }
167
168
169
170
171
172 public static Class getTypeClass( Object obj ) {
173 if( isNull( obj ) ){
174 return Object.class;
175 }else if( isArray( obj ) ){
176 return List.class;
177 }else if( isFunction( obj ) ){
178 return JSONFunction.class;
179 }else if( isBoolean( obj ) ){
180 return Boolean.class;
181 }else if( isNumber( obj ) ){
182 Number n = (Number) obj;
183 if( isInteger( n ) ){
184 return Integer.class;
185 }else if( isLong( n ) ){
186 return Long.class;
187 }else if( isFloat( n ) ){
188 return Float.class;
189 }else if( isBigInteger( n ) ){
190 return BigInteger.class;
191 }else if( isBigDecimal( n ) ){
192 return BigDecimal.class;
193 }else if( isDouble( n ) ){
194 return Double.class;
195 }else{
196 throw new JSONException( "Unsupported type" );
197 }
198 }else if( isString( obj ) ){
199 return String.class;
200 }else if( isObject( obj ) ){
201 return Object.class;
202 }else{
203 throw new JSONException( "Unsupported type" );
204 }
205 }
206
207
208
209
210
211
212
213
214 public static int hashCode( Object value ) {
215 if( value == null ){
216 return JSONNull.getInstance()
217 .hashCode();
218 }else if( value instanceof JSON || value instanceof String || value instanceof JSONFunction ){
219 return value.hashCode();
220 }else{
221 return String.valueOf( value )
222 .hashCode();
223 }
224 }
225
226
227
228
229 public static boolean isArray( Class clazz ) {
230 return clazz != null
231 && (clazz.isArray() || Collection.class.isAssignableFrom( clazz ) || (JSONArray.class.isAssignableFrom( clazz )));
232 }
233
234
235
236
237 public static boolean isArray( Object obj ) {
238 if( (obj != null && obj.getClass()
239 .isArray()) || (obj instanceof Collection) || (obj instanceof JSONArray) ){
240 return true;
241 }
242 return false;
243 }
244
245
246
247
248 public static boolean isBoolean( Class clazz ) {
249 return clazz != null
250 && (Boolean.TYPE.isAssignableFrom( clazz ) || Boolean.class.isAssignableFrom( clazz ));
251 }
252
253
254
255
256 public static boolean isBoolean( Object obj ) {
257 if( (obj instanceof Boolean) || (obj != null && obj.getClass() == Boolean.TYPE) ){
258 return true;
259 }
260 return false;
261 }
262
263
264
265
266 public static boolean isDouble( Class clazz ) {
267 return clazz != null
268 && (Double.TYPE.isAssignableFrom( clazz ) || Double.class.isAssignableFrom( clazz ));
269 }
270
271
272
273
274
275
276 public static boolean isFunction( Object obj ) {
277 if( obj instanceof String ){
278 String str = (String) obj;
279 return str.startsWith( FUNCTION_PREFIX ) && RegexpUtils.getMatcher( FUNCTION_PATTERN, true ).matches( str );
280 }
281 if( obj instanceof JSONFunction ){
282 return true;
283 }
284 return false;
285 }
286
287
288
289
290
291 public static boolean isFunctionHeader( Object obj ) {
292 if( obj instanceof String ){
293 String str = (String) obj;
294 return str.startsWith( FUNCTION_PREFIX ) && RegexpUtils.getMatcher( FUNCTION_HEADER_PATTERN, true ).matches( str );
295 }
296 return false;
297 }
298
299
300
301
302 public static boolean isJavaIdentifier( String str ) {
303 if( str.length() == 0 || !Character.isJavaIdentifierStart( str.charAt( 0 ) ) ){
304 return false;
305 }
306 for( int i = 1; i < str.length(); i++ ){
307 if( !Character.isJavaIdentifierPart( str.charAt( i ) ) ){
308 return false;
309 }
310 }
311 return true;
312 }
313
314
315
316
317 public static boolean isNull( Object obj ) {
318 if( obj instanceof JSONObject ){
319 return ((JSONObject) obj).isNullObject();
320 }
321 return JSONNull.getInstance()
322 .equals( obj );
323 }
324
325
326
327
328 public static boolean isNumber( Class clazz ) {
329 return clazz != null
330 && (Byte.TYPE.isAssignableFrom( clazz ) || Short.TYPE.isAssignableFrom( clazz )
331 || Integer.TYPE.isAssignableFrom( clazz ) || Long.TYPE.isAssignableFrom( clazz )
332 || Float.TYPE.isAssignableFrom( clazz ) || Double.TYPE.isAssignableFrom( clazz ) || Number.class.isAssignableFrom( clazz ));
333 }
334
335
336
337
338 public static boolean isNumber( Object obj ) {
339 if( (obj != null && obj.getClass() == Byte.TYPE)
340 || (obj != null && obj.getClass() == Short.TYPE)
341 || (obj != null && obj.getClass() == Integer.TYPE)
342 || (obj != null && obj.getClass() == Long.TYPE)
343 || (obj != null && obj.getClass() == Float.TYPE)
344 || (obj != null && obj.getClass() == Double.TYPE) ){
345 return true;
346 }
347
348 return obj instanceof Number;
349 }
350
351
352
353
354 public static boolean isObject( Object obj ) {
355 return !isNumber( obj ) && !isString( obj ) && !isBoolean( obj ) && !isArray( obj )
356 && !isFunction( obj ) || isNull( obj );
357 }
358
359
360
361
362 public static boolean isString( Class clazz ) {
363 return clazz != null
364 && (String.class.isAssignableFrom( clazz ) || (Character.TYPE.isAssignableFrom( clazz ) || Character.class.isAssignableFrom( clazz )));
365 }
366
367
368
369
370 public static boolean isString( Object obj ) {
371 if( (obj instanceof String)
372 || (obj instanceof Character)
373 || (obj != null && (obj.getClass() == Character.TYPE || String.class.isAssignableFrom( obj.getClass() ))) ){
374 return true;
375 }
376 return false;
377 }
378
379
380
381
382
383
384
385
386
387
388 public static boolean mayBeJSON( String string ) {
389 return string != null
390 && ("null".equals( string )
391 || (string.startsWith( "[" ) && string.endsWith( "]" )) || (string.startsWith( "{" ) && string.endsWith( "}" )));
392 }
393
394
395
396
397
398
399 public static DynaBean newDynaBean( JSONObject jsonObject ) {
400 return newDynaBean( jsonObject, new JsonConfig() );
401 }
402
403
404
405
406
407
408 public static DynaBean newDynaBean( JSONObject jsonObject, JsonConfig jsonConfig ) {
409 Map props = getProperties( jsonObject );
410 for( Iterator entries = props.entrySet()
411 .iterator(); entries.hasNext(); ){
412 Map.Entry entry = (Map.Entry) entries.next();
413 String key = (String) entry.getKey();
414 if( !JSONUtils.isJavaIdentifier( key ) ){
415 String parsedKey = JSONUtils.convertToJavaIdentifier( key, jsonConfig );
416 if( parsedKey.compareTo( key ) != 0 ){
417 props.put( parsedKey, props.remove( key ) );
418 }
419 }
420 }
421 MorphDynaClass dynaClass = new MorphDynaClass( props );
422 MorphDynaBean dynaBean = null;
423 try{
424 dynaBean = (MorphDynaBean) dynaClass.newInstance();
425 dynaBean.setDynaBeanClass( dynaClass );
426 }catch( Exception e ){
427 throw new JSONException( e );
428 }
429 return dynaBean;
430 }
431
432
433
434
435
436
437
438
439 public static String numberToString( Number n ) {
440 if( n == null ){
441 throw new JSONException( "Null pointer" );
442 }
443 testValidity( n );
444
445
446
447 String s = n.toString();
448 if( s.indexOf( '.' ) > 0 && s.indexOf( 'e' ) < 0 && s.indexOf( 'E' ) < 0 ){
449 while( s.endsWith( "0" ) ){
450 s = s.substring( 0, s.length() - 1 );
451 }
452 if( s.endsWith( "." ) ){
453 s = s.substring( 0, s.length() - 1 );
454 }
455 }
456 return s;
457 }
458
459
460
461
462
463
464
465
466
467
468
469
470
471 public static String quote( String string ) {
472 if( isFunction( string ) ) {
473 return string;
474 }
475 if( string == null || string.length() == 0 ) {
476 return "\"\"";
477 }
478
479 char b;
480 char c = 0;
481 int i;
482 int len = string.length();
483 StringBuffer sb = new StringBuffer( len * 2 );
484 String t;
485 char[] chars = string.toCharArray();
486 char[] buffer = new char[1030];
487 int bufferIndex = 0;
488 sb.append( '"' );
489 for( i = 0; i < len; i += 1 ) {
490 if( bufferIndex > 1024 ) {
491 sb.append( buffer, 0, bufferIndex );
492 bufferIndex = 0;
493 }
494 b = c;
495 c = chars[i];
496 switch( c ) {
497 case '\\':
498 case '"':
499 buffer[bufferIndex++] = '\\';
500 buffer[bufferIndex++] = c;
501 break;
502 case '/':
503 if( b == '<' ) {
504 buffer[bufferIndex++] = '\\';
505 }
506 buffer[bufferIndex++] = c;
507 break;
508 default:
509 if( c < ' ' ) {
510 switch( c ) {
511 case '\b':
512 buffer[bufferIndex++] = '\\';
513 buffer[bufferIndex++] = 'b';
514 break;
515 case '\t':
516 buffer[bufferIndex++] = '\\';
517 buffer[bufferIndex++] = 't';
518 break;
519 case '\n':
520 buffer[bufferIndex++] = '\\';
521 buffer[bufferIndex++] = 'n';
522 break;
523 case '\f':
524 buffer[bufferIndex++] = '\\';
525 buffer[bufferIndex++] = 'f';
526 break;
527 case '\r':
528 buffer[bufferIndex++] = '\\';
529 buffer[bufferIndex++] = 'r';
530 break;
531 default:
532 t = "000" + Integer.toHexString( c );
533 int tLength = t.length();
534 buffer[bufferIndex++] = '\\';
535 buffer[bufferIndex++] = 'u';
536 buffer[bufferIndex++] = t.charAt( tLength - 4 );
537 buffer[bufferIndex++] = t.charAt( tLength - 3 );
538 buffer[bufferIndex++] = t.charAt( tLength - 2 );
539 buffer[bufferIndex++] = t.charAt( tLength - 1 );
540 }
541 } else {
542 buffer[bufferIndex++] = c;
543 }
544 }
545 }
546 sb.append( buffer, 0, bufferIndex );
547 sb.append( '"' );
548 return sb.toString();
549 }
550
551
552
553
554 public static String stripQuotes( String input ) {
555 if( input.length() < 2 ){
556 return input;
557 }else if( input.startsWith( SINGLE_QUOTE ) && input.endsWith( SINGLE_QUOTE ) ){
558 return input.substring( 1, input.length() - 1 );
559 }else if( input.startsWith( DOUBLE_QUOTE ) && input.endsWith( DOUBLE_QUOTE ) ){
560 return input.substring( 1, input.length() - 1 );
561 }else{
562 return input;
563 }
564 }
565
566
567
568
569 public static boolean hasQuotes( String input ) {
570 if( input == null || input.length() < 2 ){
571 return false;
572 }
573 return input.startsWith( SINGLE_QUOTE ) && input.endsWith( SINGLE_QUOTE ) ||
574 input.startsWith( DOUBLE_QUOTE ) && input.endsWith( DOUBLE_QUOTE );
575 }
576
577 public static boolean isJsonKeyword( String input, JsonConfig jsonConfig ) {
578 if( input == null ){
579 return false;
580 }
581 return "null".equals( input ) ||
582 "true".equals( input ) ||
583 "false".equals( input ) ||
584 (jsonConfig.isJavascriptCompliant() && "undefined".equals( input ));
585 }
586
587
588
589
590
591
592
593 public static void testValidity( Object o ) {
594 if( o != null ){
595 if( o instanceof Double ){
596 if( ((Double) o).isInfinite() || ((Double) o).isNaN() ){
597 throw new JSONException( "JSON does not allow non-finite numbers" );
598 }
599 }else if( o instanceof Float ){
600 if( ((Float) o).isInfinite() || ((Float) o).isNaN() ){
601 throw new JSONException( "JSON does not allow non-finite numbers." );
602 }
603 }else if( o instanceof BigDecimal || o instanceof BigInteger ){
604
605 return;
606 }
607 }
608 }
609
610
611
612
613
614
615
616 public static Number transformNumber( Number input ) {
617 if( input instanceof Float ){
618 return new Double( input.toString() );
619 }else if( input instanceof Short ){
620 return new Integer( input.intValue() );
621 }else if( input instanceof Byte ){
622 return new Integer( input.intValue() );
623 }else if( input instanceof Long ){
624 Long max = new Long( Integer.MAX_VALUE );
625 if( input.longValue() <= max.longValue() && input.longValue() >= Integer.MIN_VALUE ){
626 return new Integer( input.intValue() );
627 }
628 }
629
630 return input;
631 }
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648 public static String valueToString( Object value ) {
649 if( value == null || isNull( value ) ){
650 return "null";
651 }
652 if( value instanceof JSONFunction ){
653 return ((JSONFunction) value).toString();
654 }
655 if( value instanceof JSONString ){
656 Object o;
657 try{
658 o = ((JSONString) value).toJSONString();
659 }catch( Exception e ){
660 throw new JSONException( e );
661 }
662 if( o instanceof String ){
663 return (String) o;
664 }
665 throw new JSONException( "Bad value from toJSONString: " + o );
666 }
667 if( value instanceof Number ){
668 return numberToString( (Number) value );
669 }
670 if( value instanceof Boolean || value instanceof JSONObject || value instanceof JSONArray ){
671 return value.toString();
672 }
673 return quote( value.toString() );
674 }
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690 public static String valueToString( Object value, int indentFactor, int indent ) {
691 if( value == null || isNull( value ) ){
692 return "null";
693 }
694 if( value instanceof JSONFunction ){
695 return ((JSONFunction) value).toString();
696 }
697 if( value instanceof JSONString ){
698 return ((JSONString) value).toJSONString();
699 }
700 if( value instanceof Number ){
701 return numberToString( (Number) value );
702 }
703 if( value instanceof Boolean ){
704 return value.toString();
705 }
706 if( value instanceof JSONObject ){
707 return ((JSONObject) value).toString( indentFactor, indent );
708 }
709 if( value instanceof JSONArray ){
710 return ((JSONArray) value).toString( indentFactor, indent );
711 }
712 return quote( value.toString() );
713 }
714
715
716
717
718
719
720
721 private static boolean isBigDecimal( Number n ) {
722 if( n instanceof BigDecimal ){
723 return true;
724 }
725 try{
726 new BigDecimal( String.valueOf( n ) );
727 return true;
728 }catch( NumberFormatException e ){
729 return false;
730 }
731 }
732
733
734
735
736
737
738
739 private static boolean isBigInteger( Number n ) {
740 if( n instanceof BigInteger ){
741 return true;
742 }
743 try{
744 new BigInteger( String.valueOf( n ) );
745 return true;
746 }catch( NumberFormatException e ){
747 return false;
748 }
749 }
750
751
752
753
754
755
756
757 private static boolean isDouble( Number n ) {
758 if( n instanceof Double ){
759 return true;
760 }
761 try{
762 double d = Double.parseDouble( String.valueOf( n ) );
763 return !Double.isInfinite( d );
764 }catch( NumberFormatException e ){
765 return false;
766 }
767 }
768
769
770
771
772
773
774
775 private static boolean isFloat( Number n ) {
776 if( n instanceof Float ){
777 return true;
778 }
779 try{
780 float f = Float.parseFloat( String.valueOf( n ) );
781 return !Float.isInfinite( f );
782 }catch( NumberFormatException e ){
783 return false;
784 }
785 }
786
787
788
789
790
791
792
793 private static boolean isInteger( Number n ) {
794 if( n instanceof Integer ){
795 return true;
796 }
797 try{
798 Integer.parseInt( String.valueOf( n ) );
799 return true;
800 }catch( NumberFormatException e ){
801 return false;
802 }
803 }
804
805
806
807
808
809
810
811 private static boolean isLong( Number n ) {
812 if( n instanceof Long ){
813 return true;
814 }
815 try{
816 Long.parseLong( String.valueOf( n ) );
817 return true;
818 }catch( NumberFormatException e ){
819 return false;
820 }
821 }
822
823 private JSONUtils() {
824 super();
825 }
826 }