Skip to content

Instantly share code, notes, and snippets.

@cab404
Last active August 29, 2015 14:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cab404/8c9f3639e4046c9b66f4 to your computer and use it in GitHub Desktop.
Save cab404/8c9f3639e4046c9b66f4 to your computer and use it in GitHub Desktop.
JSONTemplate
package com.cab404.jsontemplate;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* Pretty simple but powerful and useful JSON template thingy for org.json library.
* Usage is simple:
* <p/>
* <pre>
*
* JSONTemplate template = new JSONTemplate(
* "{
* 'auth': '%%%',
* 'data': [
* {'section1': '%%%'},
* {'section2': '%%%'}
* ]
* }");
* System.out.println(template.build("test", 12, 23));
*
* > {"data":[{"section1":23},{"section2":12}],"auth":"test"}
* </pre>
* <p/>
* Yeah, just replace changeable parts with %%%, or whatever you want (just change {@link JSONTemplate#REPLACE} in your copy).
* So, that's it.
* <p/>
* The MIT License (MIT)
* <p/>
* Copyright (c) 2014 cab404 (cab404.ru)
* <p/>
* Permission is hereby granted, free of charge, to any person obtaining a copy<br/>
* of this software and associated documentation files (the "Software"), to deal<br/>
* in the Software without restriction, including without limitation the rights<br/>
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell<br/>
* copies of the Software, and to permit persons to whom the Software is<br/>
* furnished to do so, subject to the following conditions:
* <p/>
* The above copyright notice and this permission notice shall be included in<br/>
* all copies or substantial portions of the Software.
* <p/>
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR<br/>
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,<br/>
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE<br/>
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER<br/>
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,<br/>
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN<br/>
* THE SOFTWARE.
* <p/>
* Created at 3:44 on 07-12-2014
*
* @author cab404
*/
public class JSONTemplate {
/**
* Node of a target address.
*/
protected interface JSONAddressNode {
/**
* Retrieves an object this node pointing at.
*
* @param jsonObject from what to retrieve an object.
*/
public Object move(Object jsonObject);
/**
* Sets value of something this node pointing at
*
* @param target where to set a value.
* @param value what to set
*/
public void set(Object target, Object value);
}
/**
* JSONArray index address node
*/
protected static class JSONArrayAddressNode implements JSONAddressNode {
protected final int index;
public JSONArrayAddressNode(int index) {
this.index = index;
}
@Override
public Object move(Object jsonObject) {
try {
return ((JSONArray) jsonObject).get(index);
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
@Override
public void set(Object target, Object value) {
try {
((JSONArray) target).put(index, value);
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
@Override
public String toString() {
return "Array:" + index;
}
}
/**
* JSONObject key address node
*/
protected static class JSONObjectAddressNode implements JSONAddressNode {
protected final String key;
public JSONObjectAddressNode(String key) {
this.key = key;
}
@Override
public Object move(Object jsonObject) {
try {
return ((JSONObject) jsonObject).get(key);
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
@Override
public void set(Object target, Object value) {
try {
((JSONObject) target).put(key, value);
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
@Override
public String toString() {
return "Object:" + key;
}
}
/**
* What do we treat as a candidate for replacement
*/
protected final static String REPLACE = "%%%", SECONDARY = "$?$?$";
protected final JSONObject template_json;
/**
* Addresses to replace indexes
*/
protected final List<List<JSONAddressNode>> targets;
/**
* Creates JSONObject template from a string.
*
* @see JSONTemplate
*/
public JSONTemplate(String template) {
try {
/* Just testing. */
new JSONObject(template);
this.targets = new ArrayList<>();
StringBuilder temp_rebuild = new StringBuilder(template);
int count = 0;
int index, s_index = 0;
/* We are replacing all markers with indexed markers,
* so we won't have problems with order change in JSON */
while ((index = temp_rebuild.indexOf(REPLACE, s_index)) != -1) {
/* Checking if we are in string element. */
char s_char = temp_rebuild.charAt(index - 1);
char e_char = temp_rebuild.charAt(index + REPLACE.length());
/* This might be escape character, so we're checking this too*/
char s_e_char = temp_rebuild.charAt(index - 2);
if (s_char == e_char && (s_char == '"' || s_char == '\'') && s_e_char != '\\') {
temp_rebuild.replace(index, index + REPLACE.length(), SECONDARY + count);
count++;
}
s_index = index + 1;
}
template = temp_rebuild.toString();
for (int i = 0; i < count; i++)
targets.add(null);
recurseThroughObject(new ArrayList<JSONAddressNode>(), template_json = new JSONObject(template));
} catch (JSONException e) {
throw new RuntimeException("Template is not valid json string.", e);
}
}
protected void recurseThroughArray(List<JSONAddressNode> cur_path, JSONArray object) throws JSONException {
for (int key = 0; key < object.length(); key++) {
Object o = object.get(key);
if (o instanceof String)
if (((String) o).startsWith(SECONDARY)) {
int index = Integer.parseInt(((String) o).substring(SECONDARY.length()));
List<JSONAddressNode> copied_path = new ArrayList<>(cur_path);
copied_path.add(new JSONArrayAddressNode(key));
targets.set(index, copied_path);
} else
continue;
if (o instanceof JSONArray) {
List<JSONAddressNode> copied_path = new ArrayList<>(cur_path);
copied_path.add(new JSONArrayAddressNode(key));
recurseThroughArray(copied_path, (JSONArray) o);
}
if (o instanceof JSONObject) {
List<JSONAddressNode> copied_path = new ArrayList<>(cur_path);
copied_path.add(new JSONArrayAddressNode(key));
recurseThroughObject(copied_path, (JSONObject) o);
}
}
}
protected void recurseThroughObject(List<JSONAddressNode> cur_path, JSONObject object) throws JSONException {
JSONArray names = object.names();
ArrayList<String> names_array = new ArrayList<>();
for (int $index = 0; $index < names.length(); $index++) {
names_array.add((String) names.get($index));
}
for (String key : names_array) {
Object o = object.get(key);
if (o instanceof String)
if (((String) o).startsWith(SECONDARY)) {
int index = Integer.parseInt(((String) o).substring(SECONDARY.length()));
List<JSONAddressNode> copied_path = new ArrayList<>(cur_path);
copied_path.add(new JSONObjectAddressNode(key));
targets.set(index, copied_path);
}
if (o instanceof JSONArray) {
List<JSONAddressNode> copied_path = new ArrayList<>(cur_path);
copied_path.add(new JSONObjectAddressNode(key));
recurseThroughArray(copied_path, (JSONArray) o);
}
if (o instanceof JSONObject) {
List<JSONAddressNode> copied_path = new ArrayList<>(cur_path);
copied_path.add(new JSONObjectAddressNode(key));
recurseThroughObject(copied_path, (JSONObject) o);
}
}
}
/**
* Creates deep copy of JSONArray
*/
protected static JSONArray recursiveCloneJsonArray(JSONArray array) throws JSONException {
JSONArray copy = new JSONArray();
for (int i = 0; i < array.length(); i++) {
Object obj = array.opt(i);
if (obj instanceof JSONArray)
copy.put(i, recursiveCloneJsonArray(((JSONArray) obj)));
else if (obj instanceof JSONObject)
copy.put(i, recursiveCloneJsonObject(((JSONObject) obj)));
else
copy.put(i, obj);
}
return copy;
}
/**
* Creates deep copy of JSONObject
*/
protected static JSONObject recursiveCloneJsonObject(JSONObject object) throws JSONException {
JSONObject copy = new JSONObject();
for (String i : getIterable(object.keys())) {
Object obj = object.opt(i);
if (obj instanceof JSONArray)
copy.put(i, recursiveCloneJsonArray(((JSONArray) obj)));
else if (obj instanceof JSONObject)
copy.put(i, recursiveCloneJsonObject(((JSONObject) obj)));
else
copy.put(i, obj);
}
return copy;
}
/**
* Wraps iterator into iterable
*/
protected static <T> Iterable<T> getIterable(final Iterator<T> i) {
return new Iterable<T>() {
@Override public Iterator<T> iterator() {
return i;
}
};
}
/**
* Creates a copy of a template
*/
protected JSONObject obtainTemplateCopy() {
try {
return recursiveCloneJsonObject(template_json);
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
/**
* Builds JSONObject from template and parameters.
*
* @throws java.lang.RuntimeException if numbers of method and template parameters are not matching.
* @see JSONTemplate
*/
public JSONObject build(Object... toApply) {
/* Checking if length of parameter array is matching such in our template */
if (toApply.length != targets.size())
throw new RuntimeException(
"You must supply exactly " +
targets.size() + " object" + (targets.size() == 1 ? "" : "s")
+ " to this template!"
);
JSONObject result = obtainTemplateCopy();
for (int $target = 0; $target < toApply.length; $target++) {
List<JSONAddressNode> address = targets.get($target);
Object current_leaf = result;
/* Going down to out destination */
for (int $deep = 0; $deep < address.size() - 1; $deep++)
current_leaf = address.get($deep).move(current_leaf);
/* Getting last piece of address and setting value it's pointing to given parameter*/
address.get(address.size() - 1).set(current_leaf, toApply[$target]);
}
return result;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment