但發現 Java SE 預設的 API 並沒有 Json Parser ,需要 Java EE 才有預設 Json Parser
json.org 提供讓 Java 的 Json Parser ,但在下對其操作方式有點不明白,因此愚蠢地自己寫一個 Java 的 Json Parser
根據 json.org 定義,Json 的物件稱為 value 共有 7種 可視型態:
- object
- array
- string
- number
- true
- false
- null
建立 JsonValue 的抽象類別
public abstract class JsonValue<T> { private final T value; public JsonValue(T value) { this.value = value; } public T getValue() { return this.value; } }使用 Java 的 Generic 功能讓子類別根據需要改變成不同類別
先處理 string, number, true, false, null
public class JsonString extends JsonValue<String> { public JsonString(String value) { super(value); } }
public abstract class JsonNumber<T extends Number> extends JsonValue<Number> { public JsonNumber(Number value) { super(value); } }
public class JsonInteger extends JsonNumber<Integer> { public JsonInteger(int value) { super(value); } }
public class JsonFloat extends JsonNumber<Float> { public JsonFloat(float value) { super(value); } }借用 Number 的概念
public abstract class JsonBoolean extends JsonValue<Boolean> { public JsonBoolean(Boolean value) { super(value); } }
public class JsonTrue extends JsonBoolean { public JsonTrue() { super(true); } }
public class JsonFalse extends JsonBoolean { public JsonFalse() { super(false); } }
public class JsonNull extends JsonBoolean { public JsonNull() { super(null); } }借用 Boolean 製作 JsonNull 類別
Json array 則是一個 value 的集合,而 array 自己也是集合之一
public class JsonArray extends JsonValue<JsonValue[]> { private ArrayList<JsonValue> values = new ArrayList<>(); public JsonArray() { this(new JsonValue[0]); } public JsonArray(JsonValue[] value) { super(null); this.values.addAll(Arrays.asList(value)); } public void addValue(JsonValue value) { this.values.add(value); } @Override public JsonValue[] getValue() { return this.values.toArray(new JsonValue[this.values.size()]); } public JsonValue getValue(int index) { return this.values.get(index); } }
最後是 Json object
object 由 key 及 value 的配對組成
key 必須是 string ,而 object 自己也是 value 之一
自訂 Json attribute
public class JsonAttribute { private final String key; private final JsonValue value; public JsonAttribute(String key, JsonValue value) { this.key = key; this.value = value; } public String getKey() { return this.key; } public JsonValue getValue() { return this.value; } }
public class JsonObject extends JsonValue<JsonAttribute[]> { private ArrayList<JsonAttribute> values = new ArrayList<>(); public JsonObject() { this(new JsonAttribute[0]); } public JsonObject(JsonAttribute[] value) { super(null); this.values.addAll(Arrays.asList(value)); } public void addValue(JsonAttribute value) { this.values.add(value); } @Override public JsonAttribute[] getValue() { return this.values.toArray(new JsonAttribute[this.values.size()]); } public JsonValue getValue(String key) { for (JsonAttribute value : values) { if (value.getKey().equals(key)) { return value.getValue(); } } return null; } }
由於 JsonArray 及 JsonObject 的結構問題,因此不能直接使用 JsonValue[] 及 JsonAttribute[]
必須額外設定為可擴充的陣列例如 ArrayList ,而傳回的功能亦需要覆寫
定義各種 Json value 後便需要解柝一組字串是否 Json
static Stack<String> extract(String json) throws Exception { json = json.trim(); Stack<Character> bracketPairs = new Stack<>(); Stack<String> strings = new Stack<>(); StringBuilder tempString = new StringBuilder(); boolean openEscape = false; boolean openString = false; int length = json.length(); for (int i = 0; i < length; i++) { char c = json.charAt(i); tempString.append(c); switch (c) { case '{': { if (openString) { openEscape = false; } else { bracketPairs.push(c); strings.push(tempString.toString().trim()); tempString.delete(0, tempString.length()); } } break; case '}': { if (openString) { openEscape = false; } else { if (bracketPairs.peek() == '{') { bracketPairs.pop(); String string = tempString.toString().trim(); int index = string.lastIndexOf('}'); String previous = string.substring(0, index).trim(); if (previous.length() > 0) { strings.push(previous); } strings.push(string.substring(index).trim()); tempString.delete(0, tempString.length()); } else { throw new Exception("Error Message"); } } } break; case '[': { if (openString) { openEscape = false; } else { bracketPairs.push(c); strings.push(tempString.toString().trim()); tempString.delete(0, tempString.length()); } } break; case ']': { if (openString) { openEscape = false; } else { if (bracketPairs.peek() == '[') { bracketPairs.pop(); String string = tempString.toString().trim(); int index = string.lastIndexOf(']'); String previous = string.substring(0, index).trim(); if (previous.length() > 0) { strings.push(previous); } strings.push(string.substring(index).trim()); tempString.delete(0, tempString.length()); } else { throw new Exception("Error Message"); } } } break; case ':': { if (openString) { openEscape = false; } else { strings.push(tempString.toString().trim()); tempString.delete(0, tempString.length()); } } break; case ',': { if (openString) { openEscape = false; } else { String string = tempString.toString().trim(); int index = string.lastIndexOf(','); String previous = string.substring(0, index).trim(); if (previous.length() > 0) { strings.push(previous); } strings.push(string.substring(index).trim()); tempString.delete(0, tempString.length()); } } break; case '"': { if (openString) { if (openEscape) { openEscape = false; } else { strings.push(tempString.toString().trim()); tempString.delete(0, tempString.length()); openString = false; } } else { openString = true; } } break; case '\\': { if (openString) { openEscape = !openEscape; } } break; default: { openEscape = false; } } } if (bracketPairs.empty()) { return strings; } else { throw new Exception("Error Message"); } }extract 只將「{」、「}」、「[」、「]」、「:」、「,」、「"」、 string 、其他資料分割及「\」跳脫字元處理,但不檢查合理性
然後是判斷分割的資料屬於哪一種類型,還是不屬於任何類型的錯誤資料
null, true, false 最簡單
public static JsonNull parseJsonNull(String json) throws Exception { json = json.trim(); if (json.equals("null")) { return new JsonNull(); } else { throw new Exception("Error Message"); } }
public static JsonTrue parseJsonTrue(String json) throws Exception { json = json.trim(); if (json.equals("true")) { return new JsonTrue(); } else { throw new Exception("Error Message"); } }
public static JsonFalse parseJsonFalse(String json) throws Exception { json = json.trim(); if (json.equals("false")) { return new JsonFalse(); } else { throw new Exception("Error Message"); } }number 其實都比較繁複,整數、負數、浮點數、指數,但由於 Java 提供 number parser 的功能,借用 number parser 便可以輕鬆處理
public static JsonNumber parseJsonInteger(String json) throws Exception { json = json.trim(); try { Double value = Double.parseDouble(json); if (value % 1.0 == 0.0) { return new JsonInteger(value.intValue()); } else { throw new Exception("Error Message"); } } catch (Exception ex) { throw new Exception("Error Message"); } }
public static JsonFloat parseJsonFloat(String json) throws Exception { json = json.trim(); try { Double value = Double.parseDouble(json); if (value % 1.0 != 0.0) { return new JsonFloat(value.floatValue()); } else { throw new Exception("Error Message"); } } catch (Exception ex) { throw new Exception("Error Message"); } }若果閣下對數值資料不用區分 integer 或 float ,直接傳回 double 作 JsonNumber 亦可以
string 與剛才的 extract 功能差不多,同樣需要分個字元檢查資料的正確
static final char CHAR_NULL = '\0'; static final char CHAR_BELL = '\7'; static final char CHAR_BACKSPACE = '\b'; static final char CHAR_LINE_FEED = '\n'; static final char CHAR_TAB = '\t'; static final char CHAR_VERTICAL_TAB = '\11'; static final char CHAR_FORM_FEED = '\f'; static final char CHAR_CARRIAGE_RETURN = '\r'; static final char CHAR_ESCAPE = '\27'; public static JsonString parseJsonString(String json) throws Exception { json = json.trim(); if (json.length() < 2 || json.charAt(0) != '"' || json.charAt(json.length() - 1) != '"') { throw new Exception("Error Message"); } json = json.substring(1, json.length() - 1); if (json.contains(Character.toString(CHAR_NULL)) || json.contains(Character.toString(CHAR_BELL)) || json.contains(Character.toString(CHAR_BACKSPACE)) || json.contains(Character.toString(CHAR_LINE_FEED)) || json.contains(Character.toString(CHAR_VERTICAL_TAB)) || json.contains(Character.toString(CHAR_FORM_FEED)) || json.contains(Character.toString(CHAR_CARRIAGE_RETURN)) || json.contains(Character.toString(CHAR_ESCAPE))) { throw new Exception("Error Message"); } StringBuilder tempString = new StringBuilder(); boolean openEscape = false; int length = json.length(); for (int i = 0; i < length; i++) { char c = json.charAt(i); switch (c) { case 'b': { if (openEscape) { int tempLength = tempString.length(); if (tempLength > 0) { tempString.delete(tempLength - 1, tempLength); } else { throw new Exception("Error Message"); } } else { tempString.append(c); } openEscape = false; } break; case 'f': { if (openEscape) { tempString.append('\f'); } else { tempString.append(c); } openEscape = false; } break; case 'n': { if (openEscape) { tempString.append('\n'); } else { tempString.append(c); } openEscape = false; } break; case 'r': { if (openEscape) { tempString.append('\r'); } else { tempString.append(c); } openEscape = false; } break; case 't': { if (openEscape) { tempString.append('\t'); } else { tempString.append(c); } openEscape = false; } break; case 'u': { if (openEscape) { try { String hexString = json.substring(i + 1, i + 5); tempString.append((char) Integer.parseInt(hexString, 16)); i += 4; } catch (Exception ex) { throw new Exception("Error Message"); } } else { tempString.append(c); } openEscape = false; } break; case '"': { if (openEscape) { tempString.append(c); openEscape = false; } else { throw new Exception("Error Message"); } } break; case '\\': { if (openEscape) { tempString.append(c); } openEscape = !openEscape; } break; default: { tempString.append(c); openEscape = false; } } } json = tempString.toString(); return new JsonString(json); }
由於 string, number, true, false, null 為獨立型態,以一個 method 整合處理
static JsonValue parseJsonOther(String string) { JsonValue jsonValue = null; if (jsonValue == null) { try { jsonValue = parseJsonString(string); } catch (Exception ex) { } } if (jsonValue == null) { try { jsonValue = parseJsonFloat(string); } catch (Exception ex) { } } if (jsonValue == null) { try { jsonValue = parseJsonInteger(string); } catch (Exception ex) { } } if (jsonValue == null) { try { jsonValue = parseJsonFalse(string); } catch (Exception ex) { } } if (jsonValue == null) { try { jsonValue = parseJsonTrue(string); } catch (Exception ex) { } } if (jsonValue == null) { try { jsonValue = parseJsonNull(string); } catch (Exception ex) { } } return jsonValue; }
array 為一連串 Json Value 及 , 所組成
- 開啟 array 後,必須為 Json Value 或 ]
- 加入 Json Value 後,必須為 , 或 ]
- , 後,必須為 Json Value
static final int JSON_STATE_OPEN = 0; static final int JSON_STATE_VALUE = JSON_STATE_OPEN + 1; static final int JSON_STATE_COMMA = JSON_STATE_VALUE + 1; static JsonArray parseJsonArray(Stack<String> strings, JsonArray jsonArray) throws Exception { if (strings.size() > 0) { int state = JSON_STATE_OPEN; while (strings.size() > 0) { String string = strings.remove(0); if (string.equals("[")) { if (state == JSON_STATE_OPEN || state == JSON_STATE_COMMA) { jsonArray.addValue(parseJsonArray(strings, new JsonArray())); state = JSON_STATE_VALUE; } else { throw new Exception("Error Message"); } } else if (string.equals("]")) { if (state == JSON_STATE_OPEN || state == JSON_STATE_VALUE) { break; } else { throw new Exception("Error Message"); } } else if (string.equals("{")) { if (state == JSON_STATE_OPEN || state == JSON_STATE_COMMA) { jsonArray.addValue(parseJsonObject(strings, new JsonObject())); state = JSON_STATE_VALUE; } else { throw new Exception("Error Message"); } } else if (string.equals(",")) { if (state == JSON_STATE_VALUE) { state = JSON_STATE_COMMA; } else { throw new Exception("Error Message"); } } else { if (state == JSON_STATE_OPEN || state == JSON_STATE_COMMA) { JsonValue jsonValue = parseJsonOther(string); if (jsonValue == null) { throw new Exception("Error Message"); } else { jsonArray.addValue(jsonValue); state = JSON_STATE_VALUE; } } else { throw new Exception("Error Message"); } } } return jsonArray; } else { return null; } }
object 為一連串 key 、 : 、 Json Value 及 , 所組成
- 開啟 object 後,必須為 key 或 }
- key 後,必須為 :
- : 後,必須為 Json Value
- 加入 Json Value 後,必須為 , 或 }
- , 後,必須為 key
static final int JSON_STATE_OPEN = 0; static final int JSON_STATE_KEY = JSON_STATE_OPEN + 1; static final int JSON_STATE_COLON = JSON_STATE_KEY + 1; static final int JSON_STATE_VALUE = JSON_STATE_COLON + 1; static final int JSON_STATE_COMMA = JSON_STATE_VALUE + 1; static JsonObject parseJsonObject(Stack<String> strings, JsonObject jsonObject) throws Exception { if (strings.size() > 0) { String key = null; int state = JSON_STATE_OPEN; while (strings.size() > 0) { String string = strings.remove(0); if (string.equals("{")) { if (state == JSON_STATE_COLON) { jsonObject.addValue(new JsonAttribute(key, parseJsonObject(strings, new JsonObject()))); state = JSON_STATE_VALUE; } else { throw new Exception("Error Message"); } } else if (string.equals("}")) { if (state == JSON_STATE_OPEN || state == JSON_STATE_VALUE) { break; } else { throw new Exception("Error Message"); } } else if (string.equals("[")) { if (state == JSON_STATE_COLON) { jsonObject.addValue(new JsonAttribute(key, parseJsonArray(strings, new JsonArray()))); state = JSON_STATE_VALUE; } else { throw new Exception("Error Message"); } } else if (string.equals(":")) { if (state == JSON_STATE_KEY) { state = JSON_STATE_COLON; } else { throw new Exception("Error Message"); } } else if (string.equals(",")) { if (state == JSON_STATE_VALUE) { state = JSON_STATE_COMMA; } else { throw new Exception("Error Message"); } } else { if (state == JSON_STATE_OPEN || state == JSON_STATE_COMMA) { try { key = parseJsonString(string).getValue(); state = JSON_STATE_KEY; } catch (Exception ex) { throw new Exception("Error Message"); } } else if (state == JSON_STATE_COLON) { JsonValue jsonValue = parseJsonOther(string); if (jsonValue == null) { throw new Exception("Error Message"); } else { jsonObject.addValue(new JsonAttribute(key, jsonValue)); state = JSON_STATE_VALUE; } } else { throw new Exception("Error Message"); } } } return jsonObject; } else { return null; } }
最後整合所有功能
public static JsonValue parse(String json) throws Exception { Stack<String> strings = extract(json); if (strings.empty()) { throw new Exception("Error Message"); } else { String string = strings.remove(0); if (string.equals("{")) { return parseJsonObject(strings, new JsonObject()); } else if (string.equals("[")) { return parseJsonArray(strings, new JsonArray()); } else { throw new Exception("Error Message"); } } }由於 Json 必須以 { 或 [ 作初始,若字串清單的第一個字串不是 { 或 [ 或為錯誤
另外由於使用了 Stack, ArrayList, Arrays 等類別,因此需要載入 java.util.*
在下以 Json @ Wiki 及 Google Map API Json 格式 檢查正常
以 Json @ Wiki 為例
{ "firstName": "John", "lastName": "Smith", "isAlive": true, "age": 25, "height_cm": 167.6, "address": { "streetAddress": "21 2nd Street", "city": "New York", "state": "NY", "postalCode": "10021-3100" }, "phoneNumbers": [ { "type": "home", "number": "212 555-1234" }, { "type": "office", "number": "646 555-4567" } ], "children": [], "spouse": null }
JsonObject jsonObject = (JsonObject) parse(s); System.out.println(((JsonString) jsonObject.getValue("firstName")).getValue()); System.out.println(((JsonBoolean) jsonObject.getValue("isAlive")).getValue()); System.out.println(((JsonNumber) jsonObject.getValue("age")).getValue()); System.out.println(((JsonNumber) jsonObject.getValue("height_cm")).getValue()); System.out.println(((JsonString) ((JsonObject) jsonObject.getValue("address")).getValue("streetAddress")).getValue()); System.out.println(((JsonString) ((JsonObject) ((JsonArray) jsonObject.getValue("phoneNumbers")).getValue(0)).getValue("type")).getValue()); System.out.println(((JsonBoolean) jsonObject.getValue("spouse")).getValue());輸出成
John true 25 167.6 21 2nd Street home null避免資料發生 ClassCaseException 可以先用 instanceof 來檢查傳回資料能否轉型
同一個 Json object 的 Json attribute 的 key 重覆,會以新的 Json attribute 取代
由於在下使用 ArrayList 作為陣列又忽略了檢查重覆,會發生重覆 Json attribute
其實應該使用 HashMap 會比較適合,讓 Map 自動處理重覆的 key ,而使用 ArrayList 則需要由使用者自行處理
沒有留言 :
張貼留言