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 }