class JSONUtil {

    private static void applyFunctorToJsonRecursively(Object jsonElem, String jsonElemKey, Functor functor)  {
        try {
            if (jsonElem == null)
                return;

            if (jsonElem instanceof JSONArray) {
                JSONArray jsonArray = (JSONArray) jsonElem;
                for (int j = 0; j < jsonArray.length(); ++j) {
                    Object elem = jsonArray.get(j);
                    if (elem instanceof JSONObject)
                        applyFunctorToJsonRecursively(elem, null, functor);
                    else if (elem instanceof JSONArray)
                        applyFunctorToJsonRecursively(elem, jsonElemKey, functor);
                    else {
                        Object procVal = functor.call(jsonElemKey, elem.toString());        //case: key:[val1, val2]
                        if (procVal != null)
                            jsonArray.put(j, procVal);
                    }
                }
            }
            else if (jsonElem instanceof JSONObject) {
                JSONObject jsonObject = (JSONObject) jsonElem;
                for (Iterator<String> iter = jsonObject.keys(); iter.hasNext(); ) {
                    String childElemKey = iter.next();
                    Object childElemVal = jsonObject.get(childElemKey);
                    if (childElemVal instanceof JSONObject || childElemVal instanceof JSONArray)
                        applyFunctorToJsonRecursively(childElemVal, childElemKey, functor);
                    else {
                        Object procVal = functor.call(childElemKey, childElemVal.toString());
                        if (procVal != null)
                            ((JSONObject) jsonElem).put(childElemKey, procVal);
                    }
                }
            }
            else
                return;
        }
        catch (JSONException je) {
            throw new RuntimeException("Exception during applying functor to JSON.", je);
        }
    }

    private  JSONUtil();

}