/* * Copyright (C) 2015 Google Inc. * * Licensed 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 interactivespaces.util.data.json; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import java.util.List; import java.util.Map; import java.util.Stack; /** * Standard implementation of the JSON Builder. * * @author Keith M. Hughes */ public class StandardJsonBuilder implements JsonBuilder { /** * The root object. */ private Map<String, Object> root = Maps.newHashMap(); /** * A stack of objects as we walk the graph. */ private Stack<Object> nav = new Stack<Object>(); /** * Type of the current object. */ private JsonType currentType; /** * The current object, if it is a map. */ private Map<String, Object> currentObject; /** * The current object, if it is a map. */ private List<Object> currentArray; /** * Construct a new builder. */ public StandardJsonBuilder() { currentObject = root; currentType = JsonType.OBJECT; } @Override public JsonBuilder put(String name, Object value) { if (currentType == JsonType.OBJECT) { currentObject.put(name, value); } else { // Must be an array throw new JsonInteractiveSpacesException("Cannot put named item into an array"); } return this; } @Override public JsonBuilder putAll(Map<String, Object> data) { if (currentType == JsonType.OBJECT) { currentObject.putAll(data); } else { // Must be an array throw new JsonInteractiveSpacesException("Cannot put a map of values into an array"); } return this; } @Override public JsonBuilder put(Object value) { if (currentType == JsonType.ARRAY) { currentArray.add(value); } else { // Must be an object throw new JsonInteractiveSpacesException("Cannot put unnamed item into an object"); } return this; } @Override public JsonBuilder newObject(String name) { if (currentType == JsonType.OBJECT) { Map<String, Object> newObject = Maps.newHashMap(); currentObject.put(name, newObject); nav.push(currentObject); currentObject = newObject; } else { // Must be an array throw new JsonInteractiveSpacesException("Cannot put named item into an array"); } return this; } @Override public JsonBuilder newArray(String name) { if (currentType == JsonType.OBJECT) { List<Object> newObject = Lists.newArrayList(); currentObject.put(name, newObject); nav.push(currentObject); currentArray = newObject; currentType = JsonType.ARRAY; } else { // Must be an array throw new JsonInteractiveSpacesException("Cannot put named item into an array"); } return this; } @Override public JsonBuilder newArray() { if (currentType == JsonType.ARRAY) { List<Object> newObject = Lists.newArrayList(); currentArray.add(newObject); nav.push(currentArray); currentArray = newObject; } else { // Must be an object throw new JsonInteractiveSpacesException("Cannot put unnamed item into an object"); } return this; } @Override public JsonBuilder newObject() { if (currentType == JsonType.ARRAY) { Map<String, Object> newObject = Maps.newHashMap(); currentArray.add(newObject); nav.push(currentArray); currentObject = newObject; currentType = JsonType.OBJECT; } else { // Must be an object throw new JsonInteractiveSpacesException("Cannot put unnamed item into an object"); } return this; } @Override @SuppressWarnings("unchecked") public JsonBuilder up() { if (!nav.isEmpty()) { Object newObject = nav.pop(); if (newObject instanceof Map) { currentArray = null; currentObject = (Map<String, Object>) newObject; currentType = JsonType.OBJECT; } else { currentObject = null; currentArray = (List<Object>) newObject; currentType = JsonType.ARRAY; } } else { throw new JsonInteractiveSpacesException("Cannot move up in builder, nothing left"); } return this; } @Override public Map<String, Object> build() { return root; } @Override public String toString() { return root.toString(); } }