Some time ago I found a website about the Java Nashorn API which allows you to run JavaScript from Java code. I thought about creating a JSON parser in pure Java (without external libraries) which makes use of this API and the JavaScript function JSON.parse()
My goal is to make this parser as fast, resource efficient and easy as possible.
So I would like to know if the following code is efficient compared to JSON libraries and how I could improve it in terms of performance and accuracy.
Code
JSONFile.java
package com.example.json;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class JSONFile {
public static final JSONObject parseFromPath(String path) {
return parseFromString(TextFile.readFromPath(path));
}
public static final JSONObject parseFromResource(String resource) {
return parseFromString(TextFile.readFromResource(resource));
}
public static final JSONObject parseFromURL(String url) {
return parseFromString(TextFile.readFromURL(url));
}
public static final JSONObject parseFromString(String json) {
try {
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.eval(TextFile.readFromResource("/js/jsonparser.js"));
return new JSONObject(((Invocable) engine).invokeFunction("parseJSON", json));
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (ScriptException e) {
e.printStackTrace();
}
return null;
}
}
JSONObject.java
package com.example.json;
import java.util.Map;
public class JSONObject {
private Map<String, Object> map;
@SuppressWarnings("unchecked")
public JSONObject(Object object) {
map = (Map<String, Object>) object;
}
public Object get(String key) {
return map.get(key);
}
public String getString(String key) {
return (String) map.get(key);
}
public boolean getBoolean(String key) {
return (boolean) map.get(key);
}
public int getInteger(String key) {
return (int) map.get(key);
}
public float getFloat(String key) {
return (float) map.get(key);
}
public JSONObject getObject(String key) {
return new JSONObject(map.get(key));
}
public JSONArray getArray(String key) {
return new JSONArray((Object[]) map.get(key));
}
}
JSONArray.java
package com.example.json;
public class JSONArray {
private Object[] array;
public JSONArray(Object[] array) {
this.array = array;
}
public int length() {
return array.length;
}
public Object get(int index) {
return array[index];
}
public String getString(int index) {
return (String) array[index];
}
public boolean getBoolean(int index) {
return (boolean) array[index];
}
public int getInteger(int index) {
return (int) array[index];
}
public float getFloat(int index) {
return (float) array[index];
}
public JSONObject getObject(int index) {
return new JSONObject(array[index]);
}
public JSONArray getArray(int index) {
return new JSONArray((Object[]) array[index]);
}
}
TextFile.java
package com.example.json;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
public class TextFile {
public static final String LINE_SEPARATOR = System.getProperty("line.separator");
public static final String readFromPath(String path) {
try {
return read(Files.newInputStream(Paths.get(path), StandardOpenOption.READ));
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static final String readFromResource(String resource) {
return read(TextFile.class.getResourceAsStream(resource));
}
public static final String readFromURL(String url) {
try {
return read(new URL(url).openStream());
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private static final String read(InputStream is) {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder builder = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) builder.append(line + LINE_SEPARATOR);
reader.close();
System.gc();
return builder.toString().trim();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
/js/sonparser.js
function parseJSON(json) { return convert(JSON.parse(json)); }
function convert(object) {
if (isObject(object)) return toHashMap(object);
if (isArray(object)) return toArray(object);
return object;
}
function toHashMap(object) {
var map = new java.util.HashMap();
for (key in object) map.put(key, convert(object[key]));
return map;
}
function toArray(object) {
var array = Java.to(object, "java.lang.Object[]");
for (var index = 0, len = array.length; index < len; index++) array[index] = convert(array[index]);
return array;
}
function isObject(object) { return Object.prototype.toString.call(object) === "[object Object]"; }
function isArray(object) { return Object.prototype.toString.call(object) === "[object Array]"; }
Example
example.json (Source: http://www.w3schools.com/json/)
{"employees":[
{"firstName":"John", "lastName":"Doe"},
{"firstName":"Anna", "lastName":"Smith"},
{"firstName":"Peter", "lastName":"Jones"}
]}
JSONTest.java
public class JSONTest {
public static void main(String[] args) {
JSONArray employees = JSONFile.parseFromResource("/json/example.json").getArray("employees");
for (int index = 0, len = employees.length(); index < len; index++) {
JSONObject employee = employees.getObject(index);
System.out.println(employee.getString("lastName") + ", " + employee.getString("firstName"));
}
}
}
Result
Doe, John
Smith, Anna
Jones, Peter
I made some heavy changes to the code since the last edit. (Added JSONObject.java & JSONArray.java & TextFile.java and small improvements to JSONFile.java) So now it is much easier to use the code, as seen in the example.
ScriptObjectMirror
\$\endgroup\$