/** * 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 * <p/> * http://www.apache.org/licenses/LICENSE-2.0 * <p/> * 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.ambari.view.hive20.resources.uploads.parsers.json; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; import org.apache.ambari.view.hive20.resources.uploads.parsers.EndOfDocumentException; import org.apache.ambari.view.hive20.resources.uploads.parsers.RowMapIterator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.LinkedHashMap; /** * iterates over the JsonReader and reads creates row data * assumes the array of json objects. * eg : [ { "col1Name" : "value-1-1", "col2Name" : "value-1-2"}, { "col1Name" : "value-2-1", "col2Name" : "value-2-2"}] */ class JSONIterator implements RowMapIterator { protected final static Logger LOG = LoggerFactory.getLogger(JSONIterator.class); private LinkedHashMap<String, String> nextObject = null; private LinkedHashMap<String, String> readNextObject(JsonReader reader) throws IOException, EndOfDocumentException { LinkedHashMap<String, String> row = new LinkedHashMap<>(); boolean objectStarted = false; boolean shouldBeName = false; String currentName = null; while (true) { JsonToken token = reader.peek(); switch (token) { case BEGIN_ARRAY: throw new IllegalArgumentException("Row data cannot have an array."); case END_ARRAY: throw new EndOfDocumentException("End of Json Array document."); case BEGIN_OBJECT: if (objectStarted == true) { throw new IllegalArgumentException("Nested objects not supported."); } if (shouldBeName == true) { throw new IllegalArgumentException("name expected, got begin_object"); } objectStarted = true; shouldBeName = true; reader.beginObject(); break; case END_OBJECT: if (shouldBeName == false) { throw new IllegalArgumentException("value expected, got end_object"); } reader.endObject(); return row; case NAME: if (shouldBeName == false) { throw new IllegalArgumentException("name not expected at this point."); } shouldBeName = false; currentName = reader.nextName(); break; case NUMBER: case STRING: if (shouldBeName == true) { throw new IllegalArgumentException("value not expected at this point."); } String n = reader.nextString(); row.put(currentName, n); shouldBeName = true; break; case BOOLEAN: if (shouldBeName == true) { throw new IllegalArgumentException("value not expected at this point."); } String b = String.valueOf(reader.nextBoolean()); row.put(currentName, b); shouldBeName = true; break; case NULL: if (shouldBeName == true) { throw new IllegalArgumentException("value not expected at this point."); } reader.nextNull(); row.put(currentName, ""); shouldBeName = true; break; case END_DOCUMENT: return row; default: throw new IllegalArgumentException("Illegal token detected inside json: token : " + token.toString()); } } } private JsonReader reader; public JSONIterator(JsonReader reader) throws IOException { this.reader = reader; // test the start of array JsonToken jt = reader.peek(); if (jt != JsonToken.BEGIN_ARRAY) { throw new IllegalArgumentException("Expected the whole document to contain a single JsonArray."); } reader.beginArray(); // read the start of array try { nextObject = readNextObject(this.reader); } catch (EndOfDocumentException e) { } } @Override public boolean hasNext() { return null != nextObject; } public LinkedHashMap<String, String> peek() { return nextObject; } @Override public LinkedHashMap<String, String> next() { LinkedHashMap<String, String> currObject = nextObject; try { nextObject = readNextObject(this.reader); } catch (EndOfDocumentException e) { LOG.debug("End of Json document reached with next character ending the JSON Array."); nextObject = null; } catch (Exception e){ // for any other exception throw error right away throw new IllegalArgumentException(e); } return currObject; } @Override public void remove() { // no operation. LOG.info("No operation when remove called on JSONIterator."); } }