/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.wink.json4j.internal; import java.io.IOException; import java.io.Reader; import org.apache.wink.json4j.JSONArray; import org.apache.wink.json4j.JSONArtifact; import org.apache.wink.json4j.JSONException; import org.apache.wink.json4j.JSONObject; import org.apache.wink.json4j.OrderedJSONObject; /** * Private parser class which handles doing the parsing of the JSON string into tokens. */ public class Parser { private Tokenizer tokenizer; private Token lastToken; private JSONArtifact jArtifact; private boolean firstArtifact = false; /** * Contructor * @param reader The Reader to use when reading in the JSON stream/string. * * @throws JSONException Thrown if an error occurs in tokenizing the JSON string. */ public Parser(Reader reader) throws JSONException { super(); try { this.tokenizer = new Tokenizer(reader, false); } catch (IOException iox) { JSONException jex = new JSONException("Error occurred during input read."); jex.initCause(iox); throw jex; } } /** * Contructor * @param reader The Reader to use when reading in the JSON stream/string. * @param strict Boolean indicating if the parser should parse in strict mode, meaning unqoted strings and comments are not allowed. * * @throws JSONException Thrown if an error occurs in tokenizing the JSON string. */ public Parser(Reader reader, boolean strict) throws JSONException { super(); try { this.tokenizer = new Tokenizer(reader, strict); } catch (IOException iox) { JSONException jex = new JSONException("Error occurred during input read."); jex.initCause(iox); throw jex; } } /** * Method to initiate the parse of the toplevel JSON object, which will in turn parse all child JSON objects contained within. * Same as calling parse(false); * * @throws JSONException Thrown if an IO error occurd during parse of the JSON object(s). */ public JSONObject parse() throws JSONException { return parse(false, (JSONObject)null); } /** * Method to initiate the parse of the toplevel JSON object, which will in turn parse all child JSON objects contained within. * Same as calling parse(false); * * @throws JSONException Thrown if an IO error occurd during parse of the JSON object(s). */ public JSONObject parse(JSONObject jObj) throws JSONException { return parse(false, jObj); } /** * Method to initiate the parse of the toplevel JSON object, which will in turn parse all child JSON objects contained within. * @param ordered Flag to denote if the parse should contruct a JSON object which maintains serialization order of the attributes. * * @throws JSONException Thrown if an IO error occurd during parse of the JSON object(s). */ public JSONObject parse(boolean ordered) throws JSONException { try { lastToken = tokenizer.next(); } catch (IOException iox) { JSONException jex = new JSONException("Error occurred during input read."); jex.initCause(iox); throw jex; } return parseObject(ordered, null); } /** * Method to initiate the parse of the toplevel JSON object, which will in turn parse all child JSON objects contained within. * @param ordered Flag to denote if the parse should contruct a JSON object which maintains serialization order of the attributes. * @param jObj The JSONObjetc to fill out from the parsing. If null, create a new one. * * @throws JSONException Thrown if an IO error occurd during parse of the JSON object(s). */ public JSONObject parse(boolean ordered, JSONObject jObj) throws JSONException { try { lastToken = tokenizer.next(); } catch (IOException iox) { JSONException jex = new JSONException("Error occurred during input read."); jex.initCause(iox); throw jex; } return parseObject(ordered, jObj); } /** * Method to initiate the parse of the toplevel JSON object, which will in turn parse all child JSON objects contained within. * @param jObj The JSONArray to fill out from the parsing. If null, create a new one. * * @throws JSONException Thrown if an IO error occurd during parse of the JSON object(s). */ public JSONArray parse(JSONArray jObj) throws JSONException { return parse(false, jObj); } /** * Method to initiate the parse of the toplevel JSON object, which will in turn parse all child JSON objects contained within. * @param ordered Flag to denote if the parse should contruct for all JSON objects encounted, a JSON object which maintains serialization order of the attributes. * @param jObj The JSONArray to fill out from the parsing. If null, create a new one. * * @throws JSONException Thrown if an IO error occurd during parse of the JSON object(s). */ public JSONArray parse(boolean ordered, JSONArray jObj) throws JSONException { try { lastToken = tokenizer.next(); } catch (IOException iox) { JSONException jex = new JSONException("Error occurred during input read."); jex.initCause(iox); throw jex; } return parseArray(ordered, jObj); } /** * Method to parse a JSON object out of the current JSON string position. * @return JSONObject Returns the parsed out JSON object. * * @throws JSONException Thrown if an IO error occurs during parse, such as a malformed JSON object. */ public JSONObject parseObject() throws JSONException { return parseObject(false, null); } /** * Method to parse a JSON object out of the current JSON string position. * @param ordered Flag to denote if the parse should contruct a JSON object which maintains serialization order of the attributes. * @return JSONObject Returns the parsed out JSON object. * * @throws JSONException Thrown if an IO error occurs during parse, such as a malformed JSON object. */ public JSONObject parseObject(boolean ordered, JSONObject rootObject) throws JSONException { try { JSONObject result = null; if (rootObject != null) { result = rootObject; } else { if (!ordered) { result = new JSONObject(); } else { result = new OrderedJSONObject(); } } if (lastToken != Token.TokenBraceL) throw new JSONException("Expecting '{' " + tokenizer.onLineCol() + " instead, obtained token: '" + lastToken + "'"); lastToken = tokenizer.next(); while (true) { if (lastToken == Token.TokenEOF) throw new JSONException("Unterminated object " + tokenizer.onLineCol()); if (lastToken == Token.TokenBraceR) { lastToken = tokenizer.next(); break; } if (!lastToken.isString()) throw new JSONException("Expecting string key " + tokenizer.onLineCol()); String key = lastToken.getString(); lastToken = tokenizer.next(); if (lastToken != Token.TokenColon) throw new JSONException("Expecting colon " + tokenizer.onLineCol()); lastToken = tokenizer.next(); Object val = parseValue(ordered); result.put(key, val); if (lastToken == Token.TokenComma) { lastToken = tokenizer.next(); } else if (lastToken != Token.TokenBraceR) { throw new JSONException("expecting either ',' or '}' " + tokenizer.onLineCol()); } } return result; } catch (IOException iox) { JSONException jex = new JSONException("Error occurred during object input read."); jex.initCause(iox); throw jex; } } /** * Method to parse out a JSON array from a JSON string * Same as calling parseArray(false, null) * * @throws JSONException Thrown if a parse error occurs, such as a malformed JSON array. */ public JSONArray parseArray() throws JSONException { return parseArray(false, null); } /** * Method to parse out a JSON array from a JSON string * @param ordered Flag to denote if the parse should contruct JSON objects which maintain serialization order of the attributes for all JSONOjects in the array. * *param array An array instance to populate instead of creating a new one. * * @throws JSONException Thrown if a parse error occurs, such as a malformed JSON array. */ public JSONArray parseArray(boolean ordered, JSONArray array) throws JSONException { JSONArray result = null; if(array != null){ result = array; } else { result = new JSONArray(); } try { if (lastToken != Token.TokenBrackL) throw new JSONException("Expecting '[' " + tokenizer.onLineCol()); lastToken = tokenizer.next(); while (true) { if (lastToken == Token.TokenEOF) throw new JSONException("Unterminated array " + tokenizer.onLineCol()); /** * End of the array. */ if (lastToken == Token.TokenBrackR) { lastToken = tokenizer.next(); break; } Object val = parseValue(ordered); result.add(val); if (lastToken == Token.TokenComma) { lastToken = tokenizer.next(); } else if (lastToken != Token.TokenBrackR) { throw new JSONException("expecting either ',' or ']' " + tokenizer.onLineCol()); } } } catch (IOException iox) { JSONException jex = new JSONException("Error occurred during array input read."); jex.initCause(iox); throw jex; } return result; } /** * Method to parse the current JSON property value from the last token. * @return The java object type that represents the JSON value. * * @throws JSONException Thrown if an IO error (read incomplete token) occurs. */ public Object parseValue() throws JSONException { return parseValue(false); } /** * Method to parse the current JSON property value from the last token. * @return The java object type that represents the JSON value. * @param ordered Flag to denote if the parse should contruct JSON objects and arrays which maintain serialization order of the attributes. * * @throws JSONException Thrown if an IO error (read incomplete token) occurs. */ public Object parseValue(boolean ordered) throws JSONException { if (lastToken == Token.TokenEOF) throw new JSONException("Expecting property value " + tokenizer.onLineCol()); try { if (lastToken.isNumber()) { Object result = lastToken.getNumber(); lastToken = tokenizer.next(); return result; } if (lastToken.isString()) { Object result = lastToken.getString(); lastToken = tokenizer.next(); return result; } if (lastToken == Token.TokenFalse) { lastToken = tokenizer.next(); return Boolean.FALSE; } if (lastToken == Token.TokenTrue) { lastToken = tokenizer.next(); return Boolean.TRUE; } if (lastToken == Token.TokenNull) { lastToken = tokenizer.next(); return null; } if (lastToken == Token.TokenBrackL) return parseArray(ordered, null); if (lastToken == Token.TokenBraceL) return parseObject(ordered, null); } catch (IOException iox) { JSONException jex = new JSONException("Error occurred during value input read."); jex.initCause(iox); throw jex; } throw new JSONException("Invalid token " + tokenizer.onLineCol()); } }