{"id":17920097,"url":"https://github.com/vsch/boxed-json","last_synced_at":"2025-03-24T00:32:10.817Z","repository":{"id":57729477,"uuid":"123162806","full_name":"vsch/boxed-json","owner":"vsch","description":"Java Library for easy examination and modification of JSON values","archived":false,"fork":false,"pushed_at":"2022-01-04T17:31:21.000Z","size":79,"stargazers_count":3,"open_issues_count":1,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2023-12-19T11:25:09.513Z","etag":null,"topics":["json","json-data","json-library","json-parser"],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vsch.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-02-27T17:18:16.000Z","updated_at":"2022-01-04T17:31:24.000Z","dependencies_parsed_at":"2022-09-10T22:22:57.051Z","dependency_job_id":null,"html_url":"https://github.com/vsch/boxed-json","commit_stats":null,"previous_names":[],"tags_count":21,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vsch%2Fboxed-json","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vsch%2Fboxed-json/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vsch%2Fboxed-json/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vsch%2Fboxed-json/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vsch","download_url":"https://codeload.github.com/vsch/boxed-json/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221926465,"owners_count":16902873,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["json","json-data","json-library","json-parser"],"created_at":"2024-10-28T20:21:09.921Z","updated_at":"2024-10-28T20:21:10.454Z","avatar_url":"https://github.com/vsch.png","language":"Java","readme":"# Boxed Json Library\n\nThis library is for easy extraction of values from JSON with manipulation of the same JSON\nstructure without having to create a copy. All `JsonValue` types as publicly constructable and\nextensible.\n\nThis Library is based on the [GlassFish Open Source Reference Implementation], it is released\nunder the same dual license as the original [GlassFish License], which is duplicated in this\nrepository [LICENSE].\n\n[![Build status](https://travis-ci.org/vsch/boxed-json.svg?branch=master)](https://travis-ci.org/vsch/boxed-json)\n[![Maven Central status](https://img.shields.io/maven-central/v/com.vladsch.boxed-json/boxed-json.svg)](https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.vladsch.boxed-json%22)\u003c!-- @IGNORE PREVIOUS: anchor --\u003e\n\n### Requirements\n\n* Java 8 or above\n* The project is on Maven: `com.vladsch.boxed-json`\n* dependencies:\n  * `org.glassfish:javax.json`\n  * `org.jetbrains.annotations`\n\n### Quick Start\n\nFor Maven:\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.vladsch.boxed-json\u003c/groupId\u003e\n    \u003cartifactId\u003eboxed-json\u003c/artifactId\u003e\n    \u003cversion\u003eLATEST\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n## Easy Access and Modifications\n\nJson objects created by this library do not throw exceptions and succeed all operations while\nkeeping track of the first error and propagating it through all subsequent access/modification\nmethods. It is perfectly valid to access a value nested in a `JsonObject` without checking for\nexistence or type of intervening values, only testing at the end if the value is valid. This\neliminates all the nested `if` blocks.\n\nAny value can be accessed via the `eval(String path)` method.\n\n```java\nBoxedJsObject jsReply = BoxedJson.from(\"{\"method\":\"Runtime.consoleAPICalled\",\"params\":{\"type\":\"warning\",\"args\":[{\"type\":\"string\",\"value\":\"warning\"}],\"executionContextId\":30,\"timestamp\":1519047166210.763,\"stackTrace\":{\"callFrames\":[{\"functionName\":\"\",\"scriptId\":\"684\",\"url\":\"\",\"lineNumber\":0,\"columnNumber\":8}]}}}\");\nBoxedJsNumber jsExecutionContextId = jsReply.evalJsNumber(\"params.executionContextId\");\nBoxedJsString jsFirstArgType = jsReply.evalJsString(\"params.args[0].type\");\nBoxedJsString jsFirstFunction = jsReply.evalJsString(\"params.stackTrace.callFrames[0].functionName\");\nif (jsExecutionContextId.isValid() \u0026\u0026 jsFirstArgType.isValid() \u0026\u0026 jsFirstFunction.isValid()) {\n    // change functionName if it is blank to unknown\n    if (jsFirstFunction.getString().isEmpty()) {\n        jsReply.evalSet(\"params.stackTrace.callFrames[0].functionName\", \"unknown\");\n    }\n}\n```\n\nIn the above code it is not necessary to test `jsReply` for validity because its invalid status\nis propagated to all values derived from it.\n\nJSON in the above code is prettified here:\n\n```json\n{\n  \"method\": \"Runtime.consoleAPICalled\",\n  \"params\": {\n    \"type\": \"warning\",\n    \"args\": [\n      {\n        \"type\": \"string\",\n        \"value\": \"warning\"\n      }\n    ],\n    \"executionContextId\": 30,\n    \"timestamp\": 1519047166210.763,\n    \"stackTrace\": {\n      \"callFrames\": [\n        {\n          \"functionName\": \"\",\n          \"scriptId\": \"684\",\n          \"url\": \"\",\n          \"lineNumber\": 0,\n          \"columnNumber\": 8\n        }\n      ]\n    }\n  }\n}\n```\n\n## How To Use\n\nThere are two main sets of classes `Mutable` and `Boxed`, the former implements mutable JSON\narrays and objects, while the latter wraps any `JsonValue` and provides easy, no exception\naccess with a lot of helper methods.\n\nConverting a `JsonValue.NULL` to anything but a literal, will result in a `BoxedJsValue` which\nwill test true for `.hadNull()` for any subsequent operation results. Similarly, performing an\ninvalid conversion like accessing a literal or an object as an array, will produce a value which\nwill test true for `hadInvalid()`. Accessing a non-existent element will do the same for\n`hadMissing()`. All of these can be converted to `.asLiteral()`, `.asString()`, `.asNumber()`,\n`.asArray()` and `.asObject()`.\n\nThat said, all `BoxedJs...` classes will return valid `JsonValues` for all conversions via\n`.asJs...()` with the caveat that if the conversion is not valid then results of all operations\nwill always be some form of an error `JsonValue` boxed class.\n\n`BoxedJson` and its various classes are used for easy hacking. boxed JSON classes provide an\n`eval(\"path\")` and `evalSet('path', value)` functions are implemented for fast access to nested\nelements. The path consists of concatenated parts of object field and array index syntax:\n\n* `.field` - object field\n* `[10]` - array index, for `evalSet`, an empty `[]` index means add to the end of array (like\n  Php).\n\nAll of the boxed classes can be converted to other `JsonValue` types, and if this results in an\ninvalid operation, the error will carry over for all further operations. So it is possible to\nextract a value, convert to array, get a value at an index, convert to object and extract a\nfield, convert to `JsonNumber`. Only at the end checking if all the operations succeeded by\n`.isValid()`. If any of the intervening operations were invalid then the result will be invalid.\nUnless you are expecting more invalid JSON input, this method results in faster code than having\nto check for validity at every step only to have it succeed.\n\nFor example, to get the `frameId` value from\n`{\"method\":\"Page.frameStartedLoading\",\"params\":{\"frameId\":\"0.1\"}}` and if it exists perform some\noperation:\n\n```java\nimport com.vladsch.boxed.json.*;\n\nclass Test {\n    static void main(String[] args) {\n        BoxedJsValue json = BoxedJson.objectFrom(\"{\\\"method\\\":\\\"Page.frameStartedLoading\\\",\\\"params\\\":{\\\"frameId\\\":\\\"0.1\\\"}}\");\n\n        BoxedJsString frameId = json.eval(\"params.frameId\").asJsString();\n        if (frameId.isValid() \u0026\u0026 frameId.getString().equals(\"0.1\")) {\n            // add an array of positions to params and change frameId\n            MutableJsObject jsObject = new MutableJsObject();\n            jsObject.put(\"x\", 100);\n            jsObject.put(\"y\", 5);\n            json.evalSet(\"params.positions[]\", jsObject);\n            json.evalSet(\"params.frameId\", \"1.0\");\n        }\n        \n        String jsonText = json.toString(); // {\"method\":\"Page.frameStartedLoading\",\"params\":{\"frameId\":\"1.0\",\"positions\":[{\"x\":100,\"y\":5}]}}\n    }\n}\n\n```\n\n`evalSet` will walk the json with the given path and set the final target to the value provided.\nIf the requested intermediate value is missing, it will be created. Arrays will only be created\nif the index part is empty `[]` or refers to 1 past the last element, 0-based index.\n\nAny errors encountered will result in no modifications being performed. Check the returned value\nfor validity with `.isValid()`. When chaining `evalSet()` operations all operations after the\nfirst failure will fail because the return value is will be an invalid JSON value.\n\n`BoxedJson` class provides static methods for convenient conversions via `of()` to convert\n`JsonValue` instances and common Java types: `int`, `long`, `BigInteger`, `double`,\n`BigDecimal`, `String`, `boolean`. Use `from()` to read the json from `String`, `Reader`,\n`InputStream`.\n\nThe resulting json will be a mutable boxed instance which can be modified. For the `of()` If the\npassed in value is already based on the `MutableJson` classes then this instance will be reused.\nIf you want a new mutable copy you have to explicitly created it via the\n`MutableJson.copyOf(JsonValue)` to get a deep copy of the `JsonValue`.\n\nIf you only want a boxed wrapper of original `JsonValue` GlassFish library implementations use\nthe `boxedOf` or `boxedFrom` methods instead.\n\nOne caveat to keep in mind is that the mutable classes will convert their contained JSON values\nto mutable on access. Which means that if the value is already mutable, it will be returned\nunmodified. If you make changes to the contents of this returned value, then the parent\ncontainer's copy will reflect these changes. If you don't want the parent container's value to\nbe modified, then before making any modifications to it, you need to make a deep copy via\n`MutableJson.copyOf()` or `BoxedJson.copyOf()`.\n\n## Why another JSON Java library\n\nI needed to hack on Google Chrome Dev Tools WebSocket protocol to make JavaFX WebView debugging\nwork for evaluating console expressions. This meant I needed to get and modify JSON messages\nbetween chrome dev tools and the WebView debugger.\n\nNot only is it a pain to get the parts you want because all invalid operations result in class\ncast exceptions or other exception hell. The resulting code to handle exceptions and validate\noperations trying to avoid them, seemed like the purpose of my program. Real goal was a small\nblip against the background of housekeeping noise.\n\nTo make it even less pleasant to deal with JSON, the GlassFish library seems to be designed for\nsoftware development in a locked-down, high security prison environment. None of the value\nclasses are exposed, classes and constructors are package private. Even static methods to create\nvalues are package private. If you think this makes for great re-usable design, you must be an\nAda programmer at heart.\n\nReplacing a value meant recreating the whole json with the parts you need replaced.\n\nWriting a JSON library was not on my radar but it was either this or spend a ton of time writing\nvalidation if statements and debugging exceptions or worse, resort to using regex to replace\nvalues. This was more fun and the result was worth the effort.\n\n## What's Missing\n\nTests!\n\nI moved these classes out of my [Markdown Navigator] plugin for JetBrains IDEs into a separate\nmodule. Unfortunately, the tests I have for it are in [Kotlin] which is much more compact and\nconvenient. I have not gotten around to porting them to Java. [IntelliJ IDEA] has a single click\nJava to Kotlin conversion but no reverse option. So it has to be a manual effort.\n\n[GlassFish License]: https://javaee.github.io/glassfish/LICENSE\n[GlassFish Open Source Reference Implementation]: https://javaee.github.io/glassfish/\n[IntelliJ IDEA]: http://www.jetbrains.com/idea\n[Kotlin]: https://kotlinlang.org\n[LICENSE]: LICENSE.md\n[Markdown Navigator]: http://vladsch.com/product/markdown-navigator\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvsch%2Fboxed-json","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvsch%2Fboxed-json","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvsch%2Fboxed-json/lists"}