package com.jayway.jsonassert.impl; import com.jayway.jsonassert.InvalidPathException; import com.jayway.jsonassert.JSONReader; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; import java.io.IOException; import java.io.Reader; import java.util.LinkedList; import java.util.List; import java.util.Map; import static org.apache.commons.lang.Validate.notNull; /** * User: kalle stenflo * Date: 1/20/11 * Time: 4:27 PM */ public class JSONReaderImpl implements JSONReader { private static final JSONParser JSON_PARSER = new JSONParser(); private Object root; private String currentPath; public static synchronized JSONReader parse(Reader reader) throws java.text.ParseException, IOException { try { return new JSONReaderImpl(JSON_PARSER.parse(reader)); } catch (IOException e) { throw e; } catch (ParseException e) { throw new java.text.ParseException(e.getMessage(), e.getPosition()); } } public static synchronized JSONReader parse(String jsonDoc) throws java.text.ParseException { try { return new JSONReaderImpl(JSON_PARSER.parse(jsonDoc)); } catch (ParseException e) { throw new java.text.ParseException(e.getMessage(), e.getPosition()); } } private JSONReaderImpl(Object root) { notNull(root, "root object can not be null"); this.root = root; } /** * {@inheritDoc} */ public boolean hasJsonPath(String path) { boolean contains = true; try { get(path); } catch (InvalidPathException e) { contains = false; } return contains; } /** * {@inheritDoc} */ public boolean isNull(String path) { return (null == get(path)); } /** * {@inheritDoc} */ public Object get(String path) { return getByPath(Object.class, path); } /** * {@inheritDoc} */ public String getString(String path) { return getByPath(String.class, path); } /** * {@inheritDoc} */ public Long getLong(String path) { return getByPath(Long.class, path); } /** * {@inheritDoc} */ public Double getDouble(String path) { return getByPath(Double.class, path); } /** * {@inheritDoc} */ public Boolean getBoolean(String path) { return getByPath(Boolean.class, path); } /** * {@inheritDoc} */ public List getList(String path) { return getByPath(List.class, path); } /** * {@inheritDoc} */ public Map getMap(String path) { return getByPath(Map.class, path); } //------------------------------------------------------------ // // private methods // //------------------------------------------------------------ private T getByPath(Class clazz, String stringPath) { currentPath = ""; Object current = this.root; JSONPath path = new JSONPath(stringPath); while (path.hasMoreFragments()) { JSONPathFragment fragment = path.nextFragment(); currentPath = fragment.appendToPath(currentPath); if (fragment.isArrayIndex()) { current = toArray(current).get(fragment.getArrayIndex()); } else if (fragment.isArrayWildcard()) { current = getContainerValue(current, path.nextFragment()); } else { current = getContainerValue(current, fragment); } } return clazz.cast(current); } private JSONArray toArray(Object array) { return (JSONArray) array; } private JSONObject toDocument(Object document) { return (JSONObject) document; } /** * Extracts a field from a given container. If the given container * is an Array the field specified represents a field in the objects * contained in the array. Values from all instances of this field * will be returned in a List * * @param container a json document or array * @param fragment the field to extract from the document alt. the documents contained in the array * @return a single field value or a List of fields */ private Object getContainerValue(Object container, JSONPathFragment fragment) { Object result; if (container instanceof JSONArray) { List list = new LinkedList(); for (Object doc : toArray(container)) { list.add(getContainerValue(doc, fragment)); } result = list; } else if (container instanceof JSONObject) { JSONObject document = toDocument(container); if (!document.containsKey(fragment.value())) { throw new InvalidPathException("Invalid path element: " + currentPath + " <=="); } result = document.get(fragment.value()); } else { throw new InvalidPathException("Invalid path element: " + currentPath + " <=="); } return result; } }