1313import java .util .List ;
1414import java .util .Map ;
1515import java .util .Map .Entry ;
16+ import java .util .function .Consumer ;
1617import java .util .Objects ;
1718import java .util .Set ;
19+ import java .util .UUID ;
1820
1921/**
2022 * JSON parser/container.
2729 */
2830public final class JSON implements Comparable <JSON >, Cloneable {
2931
32+ private static final Object UNIQ = new Object ();
33+
3034 @ Override
3135 public Object clone () {
3236 if (isContainer ()) {
@@ -36,11 +40,11 @@ public Object clone() {
3640 }
3741 }
3842
39- public static ObjectBuilder buildObject ( ) {
40- return new ObjectBuilder ();
43+ public static ObjectBuilder object ( Object ... props ) {
44+ return new ObjectBuilder (). put ( props ) ;
4145 }
4246
43- public static ArrayBuilder buildArray () {
47+ public static ArrayBuilder array () {
4448 return new ArrayBuilder ();
4549 }
4650
@@ -64,9 +68,17 @@ public static JSON fromList(List<Object> list) {
6468 return new JSON (ValueType .ARRAY , list );
6569 }
6670
71+ public static JSON fromObject (Object obj ) {
72+ if (obj instanceof JSON ) {
73+ return (JSON ) obj ;
74+ } else {
75+ return new JSON (ValueType .getTypeOf (obj ), obj );
76+ }
77+ }
78+
6779 private static final ValueType [] valueTypes = new ValueType [256 ];
68- private static final int [] hexDigits = new int ['f' + 1 ];
69- private static JSON UNKNOWN = new JSON (ValueType .UNKNOWN , null );
80+ private static final int [] hexDigits = new int ['f' + 1 ];
81+ private static JSON UNKNOWN = new JSON (ValueType .UNKNOWN , null );
7082
7183 static {
7284 for (int i = 0 ; i < valueTypes .length ; ++i ) {
@@ -106,13 +118,13 @@ public static JSON fromList(List<Object> list) {
106118 }
107119 }
108120
109- public final Object value ;
121+ public final Object value ;
110122 public final ValueType type ;
111123
112124 private char [] reusableChars = new char [32 ];
113- private byte [] buf = new byte [0 ];
114- private int head ;
115- private int tail ;
125+ private byte [] buf = new byte [0 ];
126+ private int head ;
127+ private int tail ;
116128
117129 JSON (byte [] buf ) {
118130 this .buf = buf ;
@@ -164,6 +176,10 @@ public boolean isUnknown() {
164176 return type == ValueType .UNKNOWN ;
165177 }
166178
179+ public boolean isNullOrUnknown () {
180+ return type == ValueType .NULL || type == ValueType .UNKNOWN ;
181+ }
182+
167183 public boolean isNull () {
168184 return type == ValueType .NULL ;
169185 }
@@ -192,6 +208,16 @@ public boolean isContainer() {
192208 return type == ValueType .OBJECT || type == ValueType .ARRAY ;
193209 }
194210
211+ public int length () {
212+ if (type == ValueType .ARRAY ) {
213+ return ((List <Object >) value ).size ();
214+ } else if (type == ValueType .OBJECT ) {
215+ return ((Map <String , Object >) value ).size ();
216+ } else {
217+ return 0 ;
218+ }
219+ }
220+
195221 public Builder modify () {
196222 return new Builder (this );
197223 }
@@ -203,6 +229,14 @@ public Set<String> keys() {
203229 return ((Map <String , Object >) value ).keySet ();
204230 }
205231
232+ public String gets (String key ) {
233+ return get (key ).asString ();
234+ }
235+
236+ public String gets (int index ) {
237+ return get (index ).asString ();
238+ }
239+
206240 public JSON get (String key ) {
207241 if (type == ValueType .ARRAY ) {
208242 try {
@@ -269,6 +303,20 @@ public String asString() {
269303 return asStringOr (null );
270304 }
271305
306+ public String [] asStringArray () {
307+ if (type != ValueType .ARRAY ) {
308+ return new String [0 ];
309+ } else {
310+ List <Object > list = (List <Object >) value ;
311+ String [] res = new String [list .size ()];
312+ for (int i = 0 ; i < list .size (); ++i ) {
313+ var v = list .get (i );
314+ res [i ] = v != null ? String .valueOf (v ) : null ;
315+ }
316+ return res ;
317+ }
318+ }
319+
272320 public String asTextOr (String fallbackValue ) {
273321 if (type == ValueType .UNKNOWN ) {
274322 return fallbackValue ;
@@ -278,7 +326,7 @@ public String asTextOr(String fallbackValue) {
278326 }
279327
280328 public String asText () {
281- return asTextOr (null );
329+ return asTextOr ("" );
282330 }
283331
284332 public Boolean asBooleanOr (Boolean fallbackValue ) {
@@ -854,25 +902,25 @@ public static ValueType getTypeOf(Object v) {
854902 }
855903
856904 private static final class NumberChars {
857- char [] chars ;
858- int charsLength ;
905+ char [] chars ;
906+ int charsLength ;
859907 boolean dotFound ;
860908 }
861909
862910 private static final class JsonWriter {
863911 private static final char [] QUOT_CHARS = { '\\' , '"' };
864- private static final char [] BS_CHARS = { '\\' , '\\' };
865- private static final char [] LF_CHARS = { '\\' , 'n' };
866- private static final char [] CR_CHARS = { '\\' , 'r' };
867- private static final char [] TAB_CHARS = { '\\' , 't' };
912+ private static final char [] BS_CHARS = { '\\' , '\\' };
913+ private static final char [] LF_CHARS = { '\\' , 'n' };
914+ private static final char [] CR_CHARS = { '\\' , 'r' };
915+ private static final char [] TAB_CHARS = { '\\' , 't' };
868916
869917 // In JavaScript, U+2028 and U+2029 characters count as line endings and must be
870918 // encoded.
871919 // http://stackoverflow.com/questions/2965293/javascript-parse-error-on-u2028-unicode-character
872920 private static final char [] UNICODE_2028_CHARS = { '\\' , 'u' , '2' , '0' , '2' , '8' };
873921 private static final char [] UNICODE_2029_CHARS = { '\\' , 'u' , '2' , '0' , '2' , '9' };
874- private static final char [] HEX_DIGITS = { '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 'a' , 'b' , 'c' , 'd ' ,
875- 'e' , 'f' };
922+ private static final char [] HEX_DIGITS = { '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 'a' , 'b' , 'c' ,
923+ 'd' , ' e' , 'f' };
876924
877925 private final Writer writer ;
878926
@@ -986,9 +1034,9 @@ static char[] getReplacementChars(char ch) {
9861034 }
9871035
9881036 public static final class Builder {
989- final JSON json ;
1037+ final JSON json ;
9901038 final ObjectBuilder o ;
991- final ArrayBuilder a ;
1039+ final ArrayBuilder a ;
9921040
9931041 Builder (JSON json ) {
9941042 this .json = json ;
@@ -1067,6 +1115,10 @@ public ObjectBuilder put(String key, String val) {
10671115 return getO ().put (key , val );
10681116 }
10691117
1118+ public ObjectBuilder put (String key , JSON val ) {
1119+ return getO ().put (key , val );
1120+ }
1121+
10701122 public ObjectBuilder put (String key , Number val ) {
10711123 return getO ().put (key , val );
10721124 }
@@ -1129,6 +1181,33 @@ public static final class ArrayBuilder {
11291181 this (new ArrayList <>());
11301182 }
11311183
1184+ public ArrayBuilder addAll (String [] all ) {
1185+ if (all != null ) {
1186+ for (var v : all ) {
1187+ add (v );
1188+ }
1189+ }
1190+ return this ;
1191+ }
1192+
1193+ public ArrayBuilder addAll (Number [] all ) {
1194+ if (all != null ) {
1195+ for (var v : all ) {
1196+ add (v );
1197+ }
1198+ }
1199+ return this ;
1200+ }
1201+
1202+ public ArrayBuilder addAll (Boolean [] all ) {
1203+ if (all != null ) {
1204+ for (var v : all ) {
1205+ add (v );
1206+ }
1207+ }
1208+ return this ;
1209+ }
1210+
11321211 public ObjectBuilder addObject () {
11331212 ObjectBuilder b = new ObjectBuilder ();
11341213 value .add (b .value );
@@ -1161,6 +1240,15 @@ public ArrayBuilder addArray(JSON val) {
11611240 return this ;
11621241 }
11631242
1243+ public ArrayBuilder add (JSON val ) {
1244+ if (val != null ) {
1245+ value .add (val .value );
1246+ } else {
1247+ addNull ();
1248+ }
1249+ return this ;
1250+ }
1251+
11641252 public ArrayBuilder add (String val ) {
11651253 value .add (val );
11661254 return this ;
@@ -1230,7 +1318,7 @@ public ObjectBuilder putObject(String key) {
12301318 }
12311319
12321320 public ObjectBuilder putObject (String key , JSON val ) {
1233- if (val .type == ValueType .NULL ) {
1321+ if (val == null || val .type == ValueType .NULL ) {
12341322 return putNull (key );
12351323 }
12361324 if (val .type != ValueType .OBJECT ) {
@@ -1246,6 +1334,12 @@ public ArrayBuilder putArray(String key) {
12461334 return b ;
12471335 }
12481336
1337+ public ObjectBuilder putArray (String key , Consumer <ArrayBuilder > c ) {
1338+ ArrayBuilder b = new ArrayBuilder ();
1339+ c .accept (b );
1340+ return this ;
1341+ }
1342+
12491343 public ObjectBuilder putArray (String key , JSON val ) {
12501344 if (val .type == ValueType .NULL ) {
12511345 return putNull (key );
@@ -1257,6 +1351,15 @@ public ObjectBuilder putArray(String key, JSON val) {
12571351 return this ;
12581352 }
12591353
1354+ public ObjectBuilder put (String key , JSON val ) {
1355+ if (val != null ) {
1356+ value .put (key , val .value );
1357+ } else {
1358+ value .put (key , null );
1359+ }
1360+ return this ;
1361+ }
1362+
12601363 public ObjectBuilder put (String key , String val ) {
12611364 value .put (key , val );
12621365 return this ;
@@ -1272,6 +1375,39 @@ public ObjectBuilder put(String key, Boolean val) {
12721375 return this ;
12731376 }
12741377
1378+ public ObjectBuilder put (String key , UUID val ) {
1379+ if (val == null ) {
1380+ putNull (key );
1381+ } else {
1382+ put (key , val .toString ());
1383+ }
1384+ return this ;
1385+ }
1386+
1387+ public ObjectBuilder put (String key , Object o ) {
1388+ if (o instanceof JSON ) {
1389+ put (key , (JSON ) o );
1390+ } else if (o instanceof UUID ) {
1391+ value .put (key , o .toString ());
1392+ } else {
1393+ value .put (key , o );
1394+ }
1395+ return this ;
1396+ }
1397+
1398+ public ObjectBuilder put (Object ... a ) {
1399+ Object key = UNIQ ;
1400+ for (var v : a ) {
1401+ if (key != UNIQ ) {
1402+ put (String .valueOf (key ), v );
1403+ key = UNIQ ;
1404+ } else {
1405+ key = v ;
1406+ }
1407+ }
1408+ return this ;
1409+ }
1410+
12751411 public ObjectBuilder putNull (String key ) {
12761412 value .put (key , null );
12771413 return this ;
0 commit comments