$npx -y skills add AdamBien/airails --skill zjsonUse JSON in zero-dependency Java by copying the org.json source (JSONObject, JSONArray, JSONTokener) directly into the project instead of adding a Maven/Gradle dependency. Use when adding JSON parsing or generation to a Java CLI script, zb project, or any project that must stay d
| 1 | # zjson — JSON via Source Copy |
| 2 | |
| 3 | Add JSON parsing and generation to a Java project by copying the `org.json` source files in — no Maven or Gradle dependency. |
| 4 | |
| 5 | ## What is zjson |
| 6 | |
| 7 | A Java 25, zero-dependency fork of the `org.json` reference implementation, trimmed to three classes: |
| 8 | |
| 9 | - `JSONObject` — JSON object: key/value map with typed accessors |
| 10 | - `JSONArray` — JSON array: ordered values, `Iterable<Object>` |
| 11 | - `JSONTokener` — the parser both classes delegate to |
| 12 | |
| 13 | - Package: `org.json` |
| 14 | - Source: https://github.com/AdamBien/z-JSON-java (`src/main/java/org/json`) |
| 15 | - Requires: Java 21+ (developed against Java 25) |
| 16 | |
| 17 | Not included in this fork: `JSONStringer`, `JSONWriter`, XML/CDL/HTTP/Cookie conversion. Use `JSONObject` and `JSONArray` for building output. |
| 18 | |
| 19 | ## Source Integration |
| 20 | |
| 21 | Copy the `org/json` package into the project's source root — keep the `package org.json;` declarations unchanged. Unlike single-class utilities, the package is not repackaged; `org.json` stays as-is and is imported with `import org.json.*;`. |
| 22 | |
| 23 | Copy the three files from GitHub, preserving the `org/json` path. This is the canonical method — it needs only `curl` and works on any machine, with no local checkout or extra tooling: |
| 24 | |
| 25 | ```bash |
| 26 | for f in JSONObject JSONArray JSONTokener; do |
| 27 | curl -sf "https://raw.githubusercontent.com/AdamBien/z-JSON-java/main/src/main/java/org/json/$f.java" \ |
| 28 | -o "src/main/java/org/json/$f.java" --create-dirs |
| 29 | done |
| 30 | ``` |
| 31 | |
| 32 | For a single-file zb/CLI project whose source root is the project root, drop the `src/main/java/` prefix and copy into `org/json/` directly. After copying, build normally (e.g. `/zb`). The three files compile alongside application code with no further configuration. |
| 33 | |
| 34 | Optional local shortcut: if a `z-JSON-java` checkout and the `zjsoncp` script are present on the machine, running `zjsoncp` from the source root copies the same `org/json` package locally. This is a convenience only — the `curl` method above is the portable default. |
| 35 | |
| 36 | ## API |
| 37 | |
| 38 | ### Parsing |
| 39 | |
| 40 | ```java |
| 41 | import org.json.*; |
| 42 | |
| 43 | JSONObject obj = new JSONObject(""" |
| 44 | {"name":"Duke","age":29,"tags":["java","jvm"],"active":true} |
| 45 | """); |
| 46 | |
| 47 | String name = obj.getString("name"); // "Duke" |
| 48 | int age = obj.getInt("age"); // 29 |
| 49 | boolean active = obj.getBoolean("active"); // true |
| 50 | JSONArray tags = obj.getJSONArray("tags"); // ["java","jvm"] |
| 51 | |
| 52 | JSONArray arr = new JSONArray("[1,2,3]"); |
| 53 | int first = arr.getInt(0); // 1 |
| 54 | ``` |
| 55 | |
| 56 | ### Building |
| 57 | |
| 58 | `put` returns the same instance, so calls chain. Nest `JSONObject` and `JSONArray` freely: |
| 59 | |
| 60 | ```java |
| 61 | JSONObject speaker = new JSONObject() |
| 62 | .put("name", "Duke") |
| 63 | .put("age", 29) |
| 64 | .put("active", true) |
| 65 | .put("tags", new JSONArray().put("java").put("jvm")) |
| 66 | .put("address", new JSONObject().put("city", "Helsinki")); |
| 67 | |
| 68 | String compact = speaker.toString(); // single line |
| 69 | String pretty = speaker.toString(2); // indented by 2 spaces |
| 70 | ``` |
| 71 | |
| 72 | ### Typed Accessors |
| 73 | |
| 74 | `get*` throws `JSONException` when the key/index is missing or the type mismatches. `opt*` returns `null`/`0`/`false` or a supplied default instead of throwing — prefer `opt*` with a default for optional fields. |
| 75 | |
| 76 | | `JSONObject` (by `String` key) | `JSONArray` (by `int` index) | Returns | |
| 77 | |---|---|---| |
| 78 | | `get(key)` / `opt(key)` | `get(i)` / `opt(i)` | `Object` | |
| 79 | | `getString` / `optString(key[, def])` | `getString` / `optString(i[, def])` | `String` | |
| 80 | | `getInt` / `optInt(key[, def])` | `getInt` / `optInt(i[, def])` | `int` | |
| 81 | | `getLong` / `optLong` | `getLong` / `optLong` | `long` | |
| 82 | | `getDouble` / `optDouble` | `getDouble` / `optDouble` | `double` | |
| 83 | | `getBoolean` / `optBoolean` | `getBoolean` / `optBoolean` | `boolean` | |
| 84 | | `getJSONObject` / `optJSONObject` | `getJSONObject` / `optJSONObject` | `JSONObject` | |
| 85 | | `getJSONArray` / `optJSONArray` | `getJSONArray` / `optJSONArray` | `JSONArray` | |
| 86 | |
| 87 | ### Inspection & Conversion |
| 88 | |
| 89 | ```java |
| 90 | boolean has = obj.has("name"); |
| 91 | Set<String> keys = obj.keySet(); |
| 92 | int size = arr.length(); |
| 93 | |
| 94 | Map<String, Object> map = obj.toMap(); // deep, nested JSON → Map/List |
| 95 | List<Object> list = arr.toList(); // deep, nested JSON → List/Map |
| 96 | |
| 97 | for (Object value : arr) { // JSONArray is Iterable |
| 98 | // ... |
| 99 | } |
| 100 | ``` |
| 101 | |
| 102 | ### Constructors |
| 103 | |
| 104 | ```java |
| 105 | new JSONObject(); // empty |
| 106 | new JSONObject(String json); // parse |
| 107 | new JSONObject(Map<?,?> map); // from a Java Map |
| 108 | |
| 109 | new JSONArray(); // empty |
| 110 | new JSONArray(Str |