Mercurial > repos > rliterman > csp2
comparison CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/opt/bbmap-39.01-1/current/json/JsonParser.java @ 68:5028fdace37b
planemo upload commit 2e9511a184a1ca667c7be0c6321a36dc4e3d116d
author | jpayne |
---|---|
date | Tue, 18 Mar 2025 16:23:26 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
67:0e9998148a16 | 68:5028fdace37b |
---|---|
1 package json; | |
2 | |
3 import java.io.PrintStream; | |
4 import java.util.ArrayList; | |
5 | |
6 import structures.ByteBuilder; | |
7 | |
8 /** | |
9 * How to use this class: | |
10 * 1) Create one instance per thread | |
11 * 2) set() some Json text | |
12 * 3) Call either parseJsonObject or parseJsonArray | |
13 * @author Brian Bushnell | |
14 * | |
15 */ | |
16 public class JsonParser { | |
17 | |
18 /*--------------------------------------------------------------*/ | |
19 /*---------------- Initialization ----------------*/ | |
20 /*--------------------------------------------------------------*/ | |
21 | |
22 /** For testing */ | |
23 public static void main(String[] args){ | |
24 String s; | |
25 | |
26 s="{\n" | |
27 +" \"33154\": {\n" | |
28 +" \"name\": \"Opisthokonta\",\n" | |
29 +" \"tax_id\": 33154,\n" | |
30 +" \"level\": \"no rank\",\n" | |
31 +" \"no rank\": {\n" | |
32 +" \"name\": \"Opisthokonta\",\n" | |
33 +" \"tax_id\": 33154\n" | |
34 +" },\n" | |
35 +" \"foo\": {\n" | |
36 +" \"bar\": \"bam\",\n" | |
37 +" \"sam\": \"cram\"\n" | |
38 +" },\n" | |
39 +" \"foo2\": {\n" | |
40 +" \"true\": false\n" | |
41 +" },\n" | |
42 +" \"foo3\": {\n" | |
43 +" \"null\": null\n" | |
44 +" },\n" | |
45 +" \"foo4\": {\n" | |
46 +" \"null\": invalid\n" | |
47 +" },\n" | |
48 +" \"superkingdom\": {\n" | |
49 +" \"name\": \"Eukaryota\",\n" | |
50 +" \"tax_id\": 2759,\n" | |
51 +" \"number1\": 2759,\n" | |
52 +" \"number2\": -2759,\n" | |
53 +" \"number3\": .2759,\n" | |
54 +" \"number4\": 2.759,\n" | |
55 +" \"number5\": -2.759,\n" | |
56 +" \"number6\": -2.759e17,\n" | |
57 +" \"number7\": -2.759e-1,\n" | |
58 +" \"number8\": -2.759E-1,\n" | |
59 +" \"number9\": -2E-1,\n" | |
60 +" \"slash\": \"hello \\\"world\\\"\",\n" | |
61 +" \"slash\": \"hello world\",\n" | |
62 +" \"complex\": [\"hello world\", 1, {\"tax_id\": 2759}, [3, 4, 5]]\n" | |
63 +" }\n" | |
64 +" }\n" | |
65 +"}"; | |
66 | |
67 // s="{\"complex\": [\"a\", 1, {\"b\": 2}, [3, 4, 5]]\n}"; | |
68 | |
69 System.out.println("Original:\n"+s); | |
70 JsonParser jp=new JsonParser(s); | |
71 JsonObject j=jp.parseJsonObject(); | |
72 System.out.println("Original:\n"+s); | |
73 System.out.println("Regenerated:\n"+j); | |
74 | |
75 s="[\"complex\", 1, {\"b\": 2}, [3, 4, 5]]"; | |
76 | |
77 System.out.println("Original:\n"+s); | |
78 jp.set(s.getBytes()); | |
79 Object[] array=jp.parseJsonArray(); | |
80 System.out.println("Original:\n"+s); | |
81 System.out.println("Regenerated:\n"+JsonObject.toString(array)); | |
82 } | |
83 | |
84 /*--------------------------------------------------------------*/ | |
85 /*---------------- Initialization ----------------*/ | |
86 /*--------------------------------------------------------------*/ | |
87 | |
88 public JsonParser(){} | |
89 | |
90 public JsonParser(String s){ | |
91 set(s.getBytes()); | |
92 } | |
93 | |
94 public JsonParser(byte[] s){ | |
95 set(s); | |
96 } | |
97 | |
98 public static JsonObject parseJsonObjectStatic(String s){ | |
99 return new JsonParser(s).parseJsonObject(); | |
100 } | |
101 | |
102 /*--------------------------------------------------------------*/ | |
103 /*---------------- Public Methods ----------------*/ | |
104 /*--------------------------------------------------------------*/ | |
105 | |
106 public JsonParser set(byte[] s){ | |
107 text=s; | |
108 pos=0; | |
109 errorState=false; | |
110 return this; | |
111 } | |
112 | |
113 public JsonObject parseJsonObject(){ | |
114 if(text==null || text.length<1){return null;} | |
115 assert(text[0]=='{') : text[0]+"\n"+new String(text); | |
116 JsonObject o=makeObject(); | |
117 return o; | |
118 } | |
119 | |
120 public Object[] parseJsonArray(){ | |
121 if(text==null || text.length<1){return null;} | |
122 assert(text[0]=='[') : text[0]+"\n"+new String(text); | |
123 Object[] array=makeArray(); | |
124 return array; | |
125 } | |
126 | |
127 public boolean validate(){ | |
128 if(text==null || text.length<1){return true;} | |
129 try { | |
130 if(text[0]=='['){ | |
131 Object[] array=parseJsonArray(); | |
132 return !errorState; | |
133 }else if(text[0]=='{'){ | |
134 JsonObject o=parseJsonObject(); | |
135 return !errorState; | |
136 } | |
137 } catch (Throwable e) {} | |
138 return false; | |
139 } | |
140 | |
141 /*--------------------------------------------------------------*/ | |
142 /*---------------- Private Methods ----------------*/ | |
143 /*--------------------------------------------------------------*/ | |
144 | |
145 /** This handles cases when the value is not surrounded by quotes. */ | |
146 private Object bufferToObject(ByteBuilder bb){ | |
147 String s=bb.toString(); | |
148 bb.clear(); | |
149 final char firstLetter=s.length()>0 ? s.charAt(0) : 0; | |
150 Object value; | |
151 try { | |
152 if(Character.isLetter(firstLetter)){ | |
153 if(verbose){outstream.println("Letter");} | |
154 if(s.equalsIgnoreCase("null")){ | |
155 value=null; | |
156 }else{ | |
157 // value=Boolean.parseBoolean(s); | |
158 value=parseBoolean(s); | |
159 } | |
160 }else{ | |
161 if(verbose){outstream.println("Number");} | |
162 if(s.indexOf('.')>=0 || s.indexOf('e')>=0 || s.indexOf('E')>=0){ | |
163 value=Double.parseDouble(s); | |
164 }else{ | |
165 value=Long.parseLong(s); | |
166 } | |
167 } | |
168 } catch (Exception e) { | |
169 //This handles an incorrectly formatted input file | |
170 errorState=true; | |
171 value=s; | |
172 } | |
173 return value; | |
174 } | |
175 | |
176 /** Not strictly correct, but allows t and f */ | |
177 private static boolean parseBoolean(String s) throws Exception{ | |
178 if(s==null){throw INVALID_JSON;} | |
179 if(s.equalsIgnoreCase("true") || s.equalsIgnoreCase("t")){return true;} | |
180 if(s.equalsIgnoreCase("false") || s.equalsIgnoreCase("f")){return false;} | |
181 throw INVALID_JSON; | |
182 } | |
183 | |
184 /** Create a JsonObject from { to the next } */ | |
185 private JsonObject makeObject(){ | |
186 assert(text[pos]=='{'); | |
187 pos++; | |
188 | |
189 if(verbose){outstream.println("Entering makeObject.");} | |
190 | |
191 JsonObject current=new JsonObject(); | |
192 ByteBuilder bb=new ByteBuilder(); | |
193 boolean quoteMode=false; | |
194 boolean slashMode=false; | |
195 String key=null; | |
196 | |
197 for(; pos<text.length; pos++){ | |
198 final byte b=text[pos]; | |
199 // if(verbose){outstream.println(pos+"=\t"+(char)b); | |
200 | |
201 if(quoteMode){ | |
202 if(slashMode){ | |
203 if(verbose){outstream.println(">SlashModeEnd, buffer="+bb);} | |
204 bb.append(b); | |
205 slashMode=false; | |
206 }else if(b=='"'){ | |
207 if(verbose){outstream.println(">Quote; quote mode="+quoteMode+", key="+key+", buffer="+bb);} | |
208 String s=bb.toString(); | |
209 bb.clear(); | |
210 if(key==null){ | |
211 key=s; | |
212 if(verbose){outstream.println("Set key to \""+key+"\"");} | |
213 }else{ | |
214 current.add(key, s); | |
215 if(verbose){outstream.println("Added \""+key+"\": \""+s+"\"");} | |
216 key=null; | |
217 } | |
218 quoteMode=!quoteMode; | |
219 }else{ | |
220 if(verbose){outstream.println(">QuoteMode, buffer="+bb);} | |
221 if(b=='\\'){ | |
222 if(verbose){outstream.println(">SlashMode, buffer="+bb);} | |
223 slashMode=true; | |
224 } | |
225 bb.append(b); | |
226 } | |
227 }else if(b=='"'){ | |
228 if(verbose){outstream.println(">Quote; quote mode="+quoteMode+", key="+key+", buffer="+bb);} | |
229 quoteMode=!quoteMode; | |
230 }else if(b==','){ | |
231 if(verbose){outstream.println(">Comma; key="+key+", buffer=\""+bb+"\""/*+"\n"+new String(text, 0, pos)*/);} | |
232 if(key!=null){//number or boolean | |
233 final Object value=bufferToObject(bb); | |
234 current.add(key, value); | |
235 key=null; | |
236 if(verbose){outstream.println("Added "+value+"; current=\n"+current+"\n");} | |
237 } | |
238 }else if(b==':'){ | |
239 if(verbose){outstream.println(">Colon");} | |
240 assert(key!=null); | |
241 }else if(b=='{'){ | |
242 if(verbose){outstream.println(">{, key="+key+", A) current object is:\n"+current+"\n");} | |
243 JsonObject j=makeObject(); | |
244 if(key==null){//outermost? | |
245 if(verbose){outstream.println("Returning.");} | |
246 return j; | |
247 }else{ | |
248 current.add(key, j); | |
249 if(verbose){outstream.println("Added new object:\n"+j+"\n");} | |
250 key=null; | |
251 } | |
252 }else if(b=='}'){ | |
253 if(verbose){outstream.println(">}, key="+key+", B) current object is:\n"+current+"\n");} | |
254 if(key!=null){//number or boolean | |
255 final Object value=bufferToObject(bb); | |
256 current.add(key, value); | |
257 key=null; | |
258 if(verbose){outstream.println("Added "+value+"; current=\n"+current+"\n");} | |
259 } | |
260 pos++; | |
261 return current; | |
262 }else if(b=='['){ | |
263 if(verbose){outstream.println(">[, C) current object is:\n"+current+"\n");} | |
264 Object[] array=makeArray(); | |
265 assert(key!=null) : "Should be in makeArray."; | |
266 current.add(key, array); | |
267 key=null; | |
268 assert(bb.length()==0); | |
269 }else if(b==']'){ | |
270 if(verbose){outstream.println(">], D) current object is:\n"+current+"\n");} | |
271 assert(false); | |
272 }else if(b==' ' || b=='\t' || b=='\n' || b=='\r'){ | |
273 if(verbose){outstream.println(">Other");} | |
274 //ignore | |
275 }else{ | |
276 if(verbose){outstream.println(">NormalMode, buffer="+bb);} | |
277 bb.append(b); | |
278 } | |
279 } | |
280 return current; | |
281 } | |
282 | |
283 /** Create an array from [ to the next ] */ | |
284 private Object[] makeArray(){ | |
285 assert(text[pos]=='['); | |
286 pos++; | |
287 | |
288 if(verbose){outstream.println("Entering makeArray.");} | |
289 | |
290 ArrayList<Object> current=new ArrayList<Object>(); | |
291 ByteBuilder bb=new ByteBuilder(); | |
292 boolean quoteMode=false; | |
293 boolean slashMode=false; | |
294 | |
295 for(; pos<text.length; pos++){ | |
296 final byte b=text[pos]; | |
297 | |
298 if(quoteMode){ | |
299 if(slashMode){ | |
300 if(verbose){outstream.println(">SlashModeEnd, buffer="+bb);} | |
301 bb.append(b); | |
302 slashMode=false; | |
303 }else if(b=='"'){ | |
304 if(verbose){outstream.println(">Quote; quote mode="+quoteMode+", buffer="+bb);} | |
305 String s=bb.toString(); | |
306 bb.clear(); | |
307 current.add(s); | |
308 quoteMode=!quoteMode; | |
309 }else{ | |
310 if(verbose){outstream.println(">QuoteMode, buffer="+bb);} | |
311 if(b=='\\'){ | |
312 if(verbose){outstream.println(">SlashMode, buffer="+bb);} | |
313 slashMode=true; | |
314 } | |
315 bb.append(b); | |
316 } | |
317 }else if(b=='"'){ | |
318 if(verbose){outstream.println(">Quote; quote mode="+quoteMode+", buffer="+bb);} | |
319 quoteMode=!quoteMode; | |
320 }else if(b==','){ | |
321 if(verbose){outstream.println(">Comma; buffer=\""+bb+"\"");} | |
322 if(bb.length()>0){ | |
323 final Object value=bufferToObject(bb); | |
324 current.add(value); | |
325 if(verbose){outstream.println("Added "+value+"; current=\n"+current+"\n");} | |
326 } | |
327 }else if(b==':'){ | |
328 if(verbose){outstream.println(">Colon");} | |
329 assert(false); | |
330 }else if(b=='{'){ | |
331 if(verbose){outstream.println(">{, E) current object is:\n"+current+"\n");} | |
332 JsonObject j=makeObject(); | |
333 current.add(j); | |
334 if(verbose){outstream.println("Added new object:\n"+j+"\n");} | |
335 }else if(b=='}'){ | |
336 if(verbose){outstream.println(">}, current array is:\n"+current+"\n");} | |
337 assert(false); | |
338 }else if(b=='['){ | |
339 if(verbose){outstream.println(">[, F) current object is:\n"+current+"\n");} | |
340 Object[] array=makeArray(); | |
341 current.add(array); | |
342 }else if(b==']'){ | |
343 if(verbose){outstream.println(">], G) current object is:\n"+current+"\n");} | |
344 if(bb.length()>0){ | |
345 final Object value=bufferToObject(bb); | |
346 current.add(value); | |
347 if(verbose){outstream.println("Added "+value+"; current=\n"+current+"\n");} | |
348 } | |
349 if(verbose){outstream.println("Returning "+current+"; text="+new String(text, 0, pos));} | |
350 return current.toArray(); | |
351 }else if(b==' ' || b=='\t' || b=='\n' || b=='\r'){ | |
352 if(verbose){outstream.println(">Other");} | |
353 //ignore | |
354 }else{ | |
355 if(verbose){outstream.println(">NormalMode, buffer="+bb);} | |
356 bb.append(b); | |
357 } | |
358 } | |
359 return current.toArray(); | |
360 } | |
361 | |
362 /*--------------------------------------------------------------*/ | |
363 /*---------------- Fields ----------------*/ | |
364 /*--------------------------------------------------------------*/ | |
365 | |
366 byte[] text; | |
367 int pos=0; | |
368 boolean errorState; | |
369 | |
370 /** Always false except when testing */ | |
371 private static final boolean verbose=false; | |
372 private static final PrintStream outstream=System.err; | |
373 private static final Exception INVALID_JSON=new Exception("Invalid Json"); | |
374 | |
375 } |