{"id":22750061,"url":"https://github.com/pwall567/kjson-core","last_synced_at":"2026-03-08T08:33:36.967Z","repository":{"id":57735727,"uuid":"390720614","full_name":"pwall567/kjson-core","owner":"pwall567","description":"JSON Kotlin core functionality","archived":false,"fork":false,"pushed_at":"2025-02-01T11:14:11.000Z","size":2524,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-28T02:05:10.493Z","etag":null,"topics":["json","kotlin"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pwall567.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-07-29T12:43:16.000Z","updated_at":"2025-02-01T11:13:28.000Z","dependencies_parsed_at":"2024-04-01T14:25:38.654Z","dependency_job_id":"1c1581af-92ff-4fda-9d29-769d71866fb3","html_url":"https://github.com/pwall567/kjson-core","commit_stats":null,"previous_names":[],"tags_count":47,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pwall567%2Fkjson-core","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pwall567%2Fkjson-core/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pwall567%2Fkjson-core/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pwall567%2Fkjson-core/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pwall567","download_url":"https://codeload.github.com/pwall567/kjson-core/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248885661,"owners_count":21177627,"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","kotlin"],"created_at":"2024-12-11T04:12:05.400Z","updated_at":"2026-03-08T08:33:36.960Z","avatar_url":"https://github.com/pwall567.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# kjson-core\n\n[![Build Status](https://github.com/pwall567/kjson-core/actions/workflows/build.yml/badge.svg)](https://github.com/pwall567/kjson-core/actions/workflows/build.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Kotlin](https://img.shields.io/static/v1?label=Kotlin\u0026message=v2.0.21\u0026color=7f52ff\u0026logo=kotlin\u0026logoColor=7f52ff)](https://github.com/JetBrains/kotlin/releases/tag/v2.0.21)\n[![Maven Central](https://img.shields.io/maven-central/v/io.kjson/kjson-core?label=Maven%20Central)](https://central.sonatype.com/artifact/io.kjson/kjson-core)\n\nJSON Kotlin core library\n\n## Background\n\nThe input of JSON data generally consists of two main phases:\n1. parsing the input text and converting the human-readable form into an easily navigated internal structure, and\n2. mapping that internal form into pre-existing data types.\nOutput may similarly use an intermediate form, but it is on the input side that the converted form is most useful\n\u0026ndash; it allows, for example, all of the properties of an object to be analysed before the determination of the\nappropriate internal representation for the object.\n\nThere are also many types of JSON processing functions that do not require mapping to a target class \u0026ndash; they simply\nrequire an internal representation of the JSON data.\n\nThe `kjson-core` library provides the basic functionality required to represent JSON values in Kotlin, including:\n- parsing functions to convert JSON text to a structure of JSON values\n- classes to hold the internal forms of the values\n- output functions to create valid JSON representations from the internal form\n\nThe library is an evolution of the [`jsonutil`](https://github.com/pwall567/jsonutil) Java library; it makes better use\nof Kotlin-specific functionality like controlled nullability, and it adds functions to simplify the navigation of the\ninternal structure.\n\n## User Guide\n\nAll JSON values are represented by Kotlin objects of type \u0026ldquo;`JSONValue?`\u0026rdquo; \u0026ndash; that is, they are all\ninstances of classes that implement the `JSONValue` interface, or in the case of the JSON \u0026ldquo;`null`\u0026rdquo; value\nthey are `null`.\n\n### `JSONValue`\n\nThe `JSONValue` interface specifies four functions:\n- `appendTo()` \u0026ndash; this appends the JSON text form of the object to a specified `Appendable`, _e.g._ a `Writer`\n  (when outputting JSON, it is more efficient to append to a single `Appendable`, as opposed to creating strings for\n  each element)\n- `toJSON()` \u0026ndash; this creates a `String` representation of the value in syntactically-correct JSON (a default\n  implementation makes use of the above `appendTo()` function)\n- `outputTo()` \u0026ndash; this outputs the JSON text form of the value using an `IntConsumer` (similar to `appendTo()`, but\n  allowing a greater choice of output mechanism)\n- `coOutputTo()` (suspend function) \u0026ndash; non-blocking version of `outputTo()`, suitable for use in a coroutine-based\n  environment\n\n`JSONValue` is a sealed interface and the implementing classes are limited to:\n- [`JSONString`](#jsonstring) \u0026ndash; a string value\n- [`JSONInt`](#jsonint) \u0026ndash; a number value that fits in a 32-bit signed integer\n- [`JSONLong`](#jsonlong) \u0026ndash; a number value that fits in a 64-bit signed integer\n- [`JSONDecimal`](#jsondecimal) \u0026ndash; any number value, including non-integer (uses `BigDecimal` internally)\n- [`JSONBoolean`](#jsonboolean) \u0026ndash; a boolean value\n- [`JSONArray`](#jsonarray) \u0026ndash; an array\n- [`JSONObject`](#jsonobject) \u0026ndash; an object\n\nThe implementing classes are all immutable.\n\nFollowing a common Kotlin pattern, there are creation functions named `JSONValue` which create the appropriate\nimplementing class depending on the parameter type:\n\n| Parameter Type                    | Result                        |\n|-----------------------------------|-------------------------------|\n| `String`                          | [`JSONString`](#jsonstring)   |\n| `Int`                             | [`JSONInt`](#jsonint)         |\n| `Long`                            | [`JSONLong`](#jsonlong)       |\n| `BigDecimal`                      | [`JSONDecimal`](#jsondecimal) |\n| `Boolean`                         | [`JSONBoolean`](#jsonboolean) |\n| `vararg JSONValue?`               | [`JSONArray`](#jsonarray)     |\n| `vararg Pair\u003cString, JSONValue?\u003e` | [`JSONObject`](#jsonobject)   |\n| `vararg JSONObject.Property`      | [`JSONObject`](#jsonobject)   |\n\n### `JSONPrimitive`\n\n`JSONPrimitive` is a sealed interface (and a sub-interface of [`JSONValue`](#jsonvalue)) implemented by the classes for\nprimitive values, _i.e._ [`JSONInt`](#jsonint), [`JSONLong`](#jsonlong), [`JSONDecimal`](#jsondecimal),\n[`JSONString`](#jsonstring) and [`JSONBoolean`](#jsonboolean).\nIt is a parameterised interface, where the parameter is the type of the value.\nThe interface specifies a single value (named `value`), of the parameter type.\nThe value is never `null`.\n\n### `JSONNumber`\n\nIn addition to implementing [`JSONPrimitive`](#jsonprimitive), the number value classes [`JSONInt`](#jsonint),\n[`JSONLong`](#jsonlong) and [`JSONDecimal`](#jsondecimal) all derive from the sealed class `JSONNumber`, which itself\nderives from the system class `kotlin.Number`.\nThis means that these classes may be used without conversion anywhere a `Number` is called for.\n\nThe `Number` class provides a set of `toInt()`, `toLong()` _etc._ functions, to which `JSONNumber` adds the following:\n\n| Function      | Converts the value to... |\n|---------------|--------------------------|\n| `toDecimal()` | `BigDecimal`             |\n| `toULong()`   | `ULong`                  |\n| `toUInt()`    | `UInt`                   |\n| `toUShort()`  | `UShort`                 |\n| `toUByte()`   | `UByte`                  |\n\n`JSONNumber` also provides the following boolean functions:\n\n| Function          | Returns `true` iff...                                            |\n|-------------------|------------------------------------------------------------------|\n| `isIntegral()`    | the value has no fractional part, or the fractional part is zero |\n| `isLong()`        | the value may be converted to `Long` with no loss of precision   |\n| `isInt()`         | the value may be converted to `Int` with no loss of precision    |\n| `isShort()`       | the value may be converted to `Short` with no loss of precision  |\n| `isByte()`        | the value may be converted to `Byte` with no loss of precision   |\n| `isULong()`       | the value may be converted to `ULong` with no loss of precision  |\n| `isUInt()`        | the value may be converted to `UInt` with no loss of precision   |\n| `isUShort()`      | the value may be converted to `UShort` with no loss of precision |\n| `isUByte()`       | the value may be converted to `UByte` with no loss of precision  |\n| `isZero()`        | the value is equal to 0                                          |\n| `isNegative()`    | the value is less than 0                                         |\n| `isPositive()`    | the value is greater than 0                                      |\n| `isNotZero()`     | the value is not equal to 0                                      |\n| `isNotNegative()` | the value is greater than or equal to 0                          |\n| `isNotPositive()` | the value is less than or equal to 0                             |\n\nThe `JSONNumber` classes also override `equals()` (and `hashCode()`) so that instances with the same value but different\ntypes will be regarded as equal.\n`JSONInt(27)`, `JSONLong(27)` and `JSONDecimal(\"27.0\")` will all be considered equal, and will all return the same hash\ncode.\n\nFollowing a common Kotlin pattern, there are creation functions named `JSONNumber` which create the appropriate\nderived class depending on the parameter type:\n\n| Parameter Type                    | Result                        |\n|-----------------------------------|-------------------------------|\n| `Int`                             | [`JSONInt`](#jsonint)         |\n| `Long`                            | [`JSONLong`](#jsonlong)       |\n| `BigDecimal`                      | [`JSONDecimal`](#jsondecimal) |\n\n### `JSONInt`\n\nThe `JSONInt` class holds JSON number values that fit in a 32-bit signed integer.\nThe class derives from [`JSONNumber`](#jsonnumber), providing implementations for all the abstract functions of that\nclass, and it also implements [`JSONPrimitive`](#jsonprimitive) with the parameter type `Int`.\n\nThe `Int` value may be accessed by the property `value`.\n\n### `JSONLong`\n\nThe `JSONLong` class holds JSON number values that will fit in a 64-bit signed long integer.\nThe class derives from [`JSONNumber`](#jsonnumber), providing implementations for all the abstract functions of that\nclass, and it also implements [`JSONPrimitive`](#jsonprimitive) with the parameter type `Long`.\n\nThe `Long` value may be accessed by the property `value`.\n\n### `JSONDecimal`\n\nThe `JSONDecimal` class holds any JSON number values, including non-integer values.\nThe class derives from [`JSONNumber`](#jsonnumber), providing implementations for all the abstract functions of that\nclass, and it also implements [`JSONPrimitive`](#jsonprimitive) with the parameter type `BigDecimal`.\n\nThe `BigDecimal` value may be accessed by the property `value`.\n\n### `JSONString`\n\nThe `JSONString` class holds a JSON string value.\nThe class implements [`JSONPrimitive`](#jsonprimitive) with the parameter type `String`.\n\nThe parser converts JSON escape sequences on input, and the `appendJSON()` and `toJSON()` functions convert non-ASCII\ncharacters to escape sequences on output.\n\nThe `String` value may be accessed by the property `value` (which will never be `null`).\n\nA `JSONString` may be constructed dynamically using the `build {}` function, which takes as a lambda parameter an\nextension function on `StringBuilder`; anything appended to the `StringBuilder` will become part of the `JSONString`.\nFor example:\n```kotlin\n    val jsonString = JSONString.build {\n        append(\"Number = \")\n        append(number)\n    }\n```\n\n`JSONString` also implements the `CharSequence` interface, which allows access to all the functionality of that\ninterface without having to extract the `value` property.\nThe `subSequence()` function will return a new `JSONString`.\n\n### `JSONBoolean`\n\n`JSONBoolean` is an `enum class` with two members \u0026ndash; `TRUE` and `FALSE`.\nThe class implements [`JSONPrimitive`](#jsonprimitive) with the parameter type `Boolean`.\n\nThe `Boolean` value may be accessed by the property `value`.\n\n### `JSONStructure`\n\n`JSONStructure` is a sealed interface (another sub-interface of [`JSONValue`](#jsonvalue)) implemented by the classes\nfor structured types, that is, arrays and objects.\nIt specifies a single value `size` (`Int`) which gives the number of entries in the array or object, and the functions\n`isEmpty()` and `isNotEmpty()` which (unsurprisingly) return `true` or `false` respectively if the structure is empty.\n\n`JSONStructure` is a parameterised interface, where the parameter `K` is the type of the value to locate entries in the\nstructure, _i.e._ `Int` for `JSONArray` or `String` for `JSONObject`.\n\nIt also provides convenience functions to both get a member of the structure (using a key of the parameter type `K`) and\nconvert it to the required type:\n\n| Function        | Converts the value to... |\n|-----------------|--------------------------|\n| `getString(K)`  | `String`                 |\n| `getLong(K)`    | `Long`                   |\n| `getInt(K)`     | `Int`                    |\n| `getShort(K)`   | `Short`                  |\n| `getByte(K)`    | `Byte`                   |\n| `getULong(K)`   | `ULong`                  |\n| `getUInt(K)`    | `UInt`                   |\n| `getUShort(K)`  | `UShort`                 |\n| `getUByte(K)`   | `UByte`                  |\n| `getDecimal(K)` | `BigDecimal`             |\n| `getBoolean(K)` | `Boolean`                |\n| `getArray(K)`   | `JSONArray`              |\n| `getObject(K)`  | `JSONObject`             |\n\nThese have the advantage over, for example, `json[\"property\"].asString`, that the\n[`JSONTypeException`](#jsontypeexception) thrown when the type is incorrect includes the key or index used to select the\nitem.\n\n### `JSONArray`\n\nThe `JSONArray` class implements the `List\u003cJSONValue?\u003e` interface, and all the functions of that interface are available\nto navigate the array (indexing via `array[n]`, `contains(obj)`, `iterator()` _etc._).\nThe `subList()` function will return a new `JSONArray`.\n\nThe class also implements the [`JSONStructure`](#jsonstructure) interface with a parameter type of `Int`.\n\nThe constructor for `JSONArray` is not publicly accessible, but an `of()` function is available in the\n`companion object`, and a `build` function and the `Builder` nested class allow arrays to be constructed dynamically.\n\nFollowing a common Kotlin pattern, there is also a creation function named `JSONArray` taking a `vararg` array of\n`JSONValue?`.\n\n`JSONArray` implements the `equals()` and `hashCode()` functions as specified for the Java Collections classes, so that\nan instance of `JSONArray` may be compared safely with an instance of any class correctly implementing\n`List\u003cJSONValue?\u003e`.\n\nThe `JSONArray` class also provides optimised iteration functions to iterate over the items of an array.\nBecause the class implements the `List` interface, there are iteration functions available from the standard library,\nbut the additional functions are optimised for the specific implementation details of the `JSONArray` class.\n```kotlin\n    jsonArray.forEachItem {\n        println(\"Item = $it\")\n    }\n    jsonArray.forEachItemIndexed { index, item -\u003e\n        println(\"Item #$index = $item\")\n    }\n```\n\n### `JSONObject`\n\nThe `JSONObject` class implements the `Map\u003cString, JSONValue?\u003e` interface, and all the functions of that interface are\navailable to navigate the object (retrieval via `structure[\"name\"]`, `containsKey(\"name\")`, `entries` _etc._).\nThe class also implements the [`JSONStructure`](#jsonstructure) interface with a parameter type of `String`.\n\nThe original order of the input is maintained on parsing or on the programmatic creation of a `JSONObject`, and to take\nadvantage of this sequential ordering of properties, the `JSONObject` class also implements the `List\u003cProperty\u003e`\ninterface, where `Property` is a nested class representing the `Map.Entry` objects used by `JSONObject` (see\n[below](#jsonobjectproperty)).\nThis means that the `JSONObject` class provides both:\n```kotlin\n    jsonObject[\"name\"]  // get the property named \"name\" as a JSONValue?\n```\nand:\n```kotlin\n    jsonObject[3] // get the fourth property (index 3) as a JSONObject.Property\n ```\n\nThe constructor for `JSONObject` is not publicly accessible, but an `of()` function is available in the\n`companion object`, and a `build` function and the `Builder` nested class allow objects to be constructed dynamically.\n\nFollowing a common Kotlin pattern, there are also creation functions named `JSONObject` taking a `vararg` array of\n`Pair\u003cString, JSONValue?\u003e` or `JSONObject.Property`.\n\n`JSONObject` implements the `equals()` and `hashCode()` functions as specified for the Java Collections classes, so that\nan instance of `JSONObject` may be compared safely with an instance of any class correctly implementing\n`Map\u003cString, JSONValue?\u003e`.\n\nThe `JSONObject` class also provides optimised iteration functions to iterate over the entries, the keys (property\nnames) or the values of an object.\nBecause the class implements the `Map` interface, there are iteration functions available from the standard library, but\nthe additional functions are optimised for the specific implementation details of the `JSONObject` class.\n```kotlin\n    jsonObject.forEachEntry { name, value -\u003e\n        println(\"Property $name = $value\")\n    }\n    jsonObject.forEachProperty { property -\u003e\n        println(\"Property ${property.name} = ${property.value}\")\n    }\n    jsonObject.forEachKey {\n        println(\"Property name = $it\")\n    }\n    jsonObject.forEachValue {\n        println(\"Property value = $it\")\n    }\n```\n\n### `JSONObject.Property`\n\nThe `JSONObject.Property` nested class implements the `Map.Entry\u003cString, JSONValue?\u003e` interface, and is used to hold the\nkey-value pairs of the `Map` behind `JSONObject`,\n\nIt has two properties:\n\n| Name    | Type         | Contains           |\n|---------|--------------|--------------------|\n| `name`  | `String`     | The property name  |\n| `value` | `JSONValue?` | The property value |\n\nThe `JSONObject.Property` object is immutable.\n\nThere is an infix function `refersTo` taking a `String` and a `JSONValue?` which creates a `JSONObject.Property`:\n```kotlin\n    val property = \"propertyName\" refersTo JSONString(\"Property value\")\n```\n\n### `JSONException`\n\nError conditions will usually result in a `JSONException` being thrown.\nThis is a derived class of `RuntimeException`, and the `message` property will contain a text description of the error.\n\nThe exception also includes a property `key` (of type `Any?`) which is used to provide information on the location of\nthe error, for example a [`JSONPointer`](https://github.com/pwall567/kjson-pointer) or a property name.\nWhen the key is provided, it will be appended to the message, as \u0026ldquo;`, at {key}`\u0026rdquo;.\n\nStarting from version 8.1 of this library, `JSONException` has been extracted to a separate library \u0026ndash;\n[`kjson-exception`](https://github.com/pwall567/kjson-exception) \u0026ndash; so that it may be included in other projects\nindependent from this library\n\n### `JSONTypeException`\n\nA common error case arises when a `JSONValue` is found to be of the wrong type, for example, when a `JSONArray` is\nsupplied as a parameter to a function that expects a `JSONObject`, or when a property of an object is a `JSONString`\nwhen a `JSONInt` was expected.\nThe `JSONTypeException` provides a way of reporting such errors in a consistent manner, with error messages including\nthe human-readable node name, the expected type, the actual value and an optional key (as described\n[above](#jsonexception)).\n\nThe `JSONTypeException` constructor takes the following parameters, all of which are accessible as properties of the\nexception object:\n\n| Name       | Type         | Default  | Description                                         |\n|------------|--------------|----------|-----------------------------------------------------|\n| `nodeName` | `String`     | `\"Node\"` | The name of the field, _e.g._ `\"Surname\"`           |\n| `expected` | `String`     |          | The expected type, _e.g._ `\"string\"`                |\n| `value`    | `JSONValue?` |          | The actual value found                              |\n| `key`      | `Any?`       | `null`   | The \u0026ldquo;key\u0026rdquo; (the location in a structure) |\n\nFor example, the following exception:\n```kotlin\n    throw JSONTypeException(\"Surname\", \"string\", surname, \"/person/surname\")\n```\nwill result in this message (if an array was supplied in place of a string):\n```text\nSurname not correct type (string), was [ ... ], at /person/surname\n```\n\nThe actual value will be displayed using the [`displayValue()`](#human-friendly-output) function, and the\n\u0026ldquo;at\u0026rdquo; clause will be omitted if the `key` is `null` or `key.toString()` returns an empty string.\n\nFor a more convenient way of using this exception type, see [Error Reporting](#error-reporting) below.\n\n### `JSON`\n\nThe `JSON` object contains a number of functions to assist with parsing and object creation.\n\n#### Parsing Functions\n\nThe simplest way to parse JSON text is:\n```kotlin\n        val json = JSON.parse(text)\n```\n\nThe result will be of type `JSONValue?` \u0026ndash; it will be `null` if the text consists of just the string\n\u0026ldquo;`null`\u0026rdquo; (with possible leading and trailing whitespace).\n\nIf only non-null JSON values are expected:\n```kotlin\n        val json = JSON.parseNonNull(text)\n```\nThe result of this function will be of type `JSONValue` (no question mark) and an exception will be thrown if the JSON\nwas \u0026ldquo;`null`\u0026rdquo;.\n\nIf the JSON is expected to be an object (and it is an error if it is not):\n```kotlin\n        val json = JSON.parseObject(text)\n```\nIn this case the result will be of type `JSONObject`, and an exception will be thrown if it is not an object.\n\nSimilarly, if the JSON is expected to be an array:\n```kotlin\n        val json = JSON.parseArray(text)\n```\nThe result type will be `JSONArray`, and again, an exception will be thrown if the input is not of the correct type.\n\n#### `JSONValue` Creation Functions\n\nThe `JSON` object also provides a number of shortcut functions to create `JSONValue`s:\n\n| Function                                   | Creates       |\n|--------------------------------------------|---------------|\n| `JSON.of(Int)`                             | `JSONInt`     |\n| `JSON.of(Long)`                            | `JSONLong`    |\n| `JSON.of(BigDecimal)`                      | `JSONDecimal` |\n| `JSON.of(String)`                          | `JSONString`  |\n| `JSON.of(Boolean)`                         | `JSONBoolean` |\n| `JSON.of(vararg JSONValue?)`               | `JSONArray`   |\n| `JSON.of(vararg Pair\u003cString, JSONValue?\u003e)` | `JSONObject`  |\n\n#### Human-Friendly Output\n\nTo simplify error reporting, the `JSON` object provides a `displayValue()` extension function on `JSONValue?` to create\nan abbreviated form of the value suitable for error messages.\n\n| Parameter   | Type  | Default | Purpose                                         |\n|-------------|-------|--------:|-------------------------------------------------|\n| `maxString` | `Int` |      21 | limit the number of string characters displayed |\n| `maxArray`  | `Int` |       0 | limit the number of array items displayed       |\n| `maxObject` | `Int` |       0 | limit the number of object properties displayed |\n\nWhen displaying array items, the function will by default display `[ ... ]`, but when the `maxArray` parameter is\nsupplied with a positive value, the specified number of array items will be displayed.\nIf there are more values than specified in `maxArray`, the excess parameters are elided and `, ...` will be displayed.\n\nFor example:\n```kotlin\n    val array = JSONArray.build {\n        add(123)\n        add(456)\n        add(789)\n    }\n    array.displayValue()                // displays [ ... ]\n    array.displayValue(maxArray = 1)    // displays [ 123, ... ]\n    array.displayValue(maxArray = 2)    // displays [ 123, 456, ... ]\n    array.displayValue(maxArray = 3)    // displays [ 123, 456, 456 ]\n```\n\nSimilarly, when displaying objects, the function will by default display `{ ... }`, and the use of the `maxObject`\nparameter may be used to control the display of a specified number of properties.\n\nFor example:\n```kotlin\n    val obj = JSONObject.build {\n        add(\"alpha\", 123)\n        add(\"beta\", 456)\n        add(\"gamma\", 789)\n    }\n    obj.displayValue()                  // displays { ... }\n    obj.displayValue(maxObject = 1)     // displays { \"alpha\": 123, ... }\n    obj.displayValue(maxObject = 2)     // displays { \"alpha\": 123, \"beta\": 456, ... }\n    obj.displayValue(maxObject = 3)     // displays { \"alpha\": 123, \"beta\": 456, \"gamma\": 789 }\n```\n\nLong strings are shortened with \u0026ldquo;` ... `\u0026rdquo; in the middle.\nFor example:\n```kotlin\n    JSONString(\"the quick brown fox jumps over the lazy dog\").displayValue()\n```\nwill display:\n```\n\"the quic ... lazy dog\"\n```\nThe maximum number of characters to display in a string defaults to 21, but may be specified as a parameter, _e.g._\n`displayValue(maxString = 17)` (odd numbers are best, because they result in the same number of characters before and\nafter the elision).\n\nWhen nested array items or object properties are included, they are displayed using the same function recursively, but\nwith the `MaxString`, `maxArray` and `maxObject` values all halved.\nSo, for example, when `maxObject` is specified as 4, nested objects are displayed with `maxObject=2`, and next-level\nnested objects are displayed with `maxOnject = 1`.\n\nInternally, the `displayString()` function uses an `appendDisplayString()` extension function on `Appendable` to avoid\nhaving to create a large number of small strings.\nThis function is also available for public use, with the following parameters.\n\n| Parameter   | Type         | Default | Purpose                                         |\n|-------------|--------------|--------:|-------------------------------------------------|\n| `json`      | `JSONValue?` |         | the JSON value (or `null`)                      |\n| `maxString` | `Int`        |      21 | limit the number of string characters displayed |\n| `maxArray`  | `Int`        |       0 | limit the number of array items displayed       |\n| `maxObject` | `Int`        |       0 | limit the number of object properties displayed |\n\nFor example:\n```kotlin\n    val sb = StringBuilder()\n    sb.appendDisplayString(obj, maxArray = 4, maxObject = 2)\n```\n\n#### Security-Aware Output\n\nThere is often a requirement to log JSON inputs for later error diagnosis, with the restriction that logs must not\ncontain sensitive information.\nThe `elidedValue()` extension function on `JSONValue?` allows JSON values to be converted to the text form with certain\nnominated elements excluded.\n\nFor example:\n```kotlin\n    val json = JSON.parse(\"\"\"{\"name\":\"Adam\",\"accountNo\":\"12345678\"}\"\"\")\n    json.elidedValue(exclude = setOf(\"accountNo\"))\n```\nwill display:\n```\n{\"name\":\"Adam\",\"accountNo\":\"****\"}\n```\nAll elements with the specified name will be elided, wherever they occur in the object tree.\n\nThe elements to be elided may be specified as a `Collection` of element names to be excluded as shown above, or (less\nusefully) as a `Collection` of element names to be included (using the `include` parameter).\nThe substitute string (default \u0026ldquo;`****`\u0026rdquo;) may also be specified using the `substitute` parameter.\n\n#### Error Reporting\n\nTo simplify the creation of a `JSONTypeException`, the `JSON` object includes the `typeError()` extension function on\n`JSONValue?`.\nIt takes the following parameters:\n\n| Name       | Type     | Default  | Description                                         |\n|------------|----------|----------|-----------------------------------------------------|\n| `expected` | `String` |          | The expected type, _e.g._ `\"string\"`                | \n| `key`      | `Any?`   | `null`   | The \u0026ldquo;key\u0026rdquo; (the location in a structure) |\n| `nodeName` | `String` | `\"Node\"` | The name of the field, _e.g._ `\"Surname\"`           |\n\nIts use is best illustrated by example:\n```kotlin\n    if (node !is JSONString)\n        node.typeError(\"String\", \"/person/surname\", \"Surname\")\n```\nThis will produce an exception like the one shown in the description of [`JSONTypeException`](#jsontypeexception).\n\nThe conversion may be combined with the error reporting using the `asXxxxOrError()` functions:\n\n| Extension Function              | Result type  |\n|---------------------------------|--------------|\n| `JSONValue?.asStringOrError()`  | `String`     |\n| `JSONValue?.asLongOrError()`    | `Long`       |\n| `JSONValue?.asLongOrError()`    | `Long`       |\n| `JSONValue?.asIntOrError()`     | `Int`        |\n| `JSONValue?.asShortOrError()`   | `Short`      |\n| `JSONValue?.asByteOrError()`    | `Byte`       |\n| `JSONValue?.asULongOrError()`   | `ULong`      |\n| `JSONValue?.asUIntOrError()`    | `UInt`       |\n| `JSONValue?.asUShortOrError()`  | `UShort`     |\n| `JSONValue?.asUByteOrError()`   | `UByte`      |\n| `JSONValue?.asDecimalOrError()` | `BigDecimal` |\n| `JSONValue?.asNumberOrError()`  | `Number`     |\n| `JSONValue?.asBooleanOrError()` | `Boolean`    |\n| `JSONValue?.asArrayOrError()`   | `JSONArray`  |\n| `JSONValue?.asObjectOrError()`  | `JSONObject` |\n\nNote that the functions representing a simple value return the actual value type, not the `JSONValue` subtype.\nThe `asArrayOrError()` and `asObjectOrError()` functions return `JSONArray` and `JSONObject` respectively, but these can\nof course be used as the underlying implementation types (`List` and `Map`).\n\nThe functions all take the same parameters as the `typeError()` function (which they all call if the type is not\ncorrect), but in the case of these functions, the `expected` parameter also has a default value, a string representing\nthe expected type.\n\nUsing these functions, the above example (for the use of `typeError`) may be written:\n```kotlin\n    node.asStringOrError(key = \"/person/surname\", nodeName = \"Surname\")\n```\n\n#### Extension Values\n\nTo simplify casting a `JSONValue` to the expected type, the `JSON` object provides extension values on `JSONValue?`:\n\n| Extension Value              | Result type   | If the value is not of that type... |\n|------------------------------|---------------|-------------------------------------|\n| `JSONValue?.asString`        | `String`      | throw `JSONTypeException`           |\n| `JSONValue?.asStringOrNull`  | `String?`     | return `null`                       |\n| `JSONValue?.asLong`          | `Long`        | throw `JSONTypeException`           |\n| `JSONValue?.asLongOrNull`    | `Long?`       | return `null`                       |\n| `JSONValue?.asInt`           | `Int`         | throw `JSONTypeException`           |\n| `JSONValue?.asIntOrNull`     | `Int?`        | return `null`                       |\n| `JSONValue?.asShort`         | `Short`       | throw `JSONTypeException`           |\n| `JSONValue?.asShortOrNull`   | `Short?`      | return `null`                       |\n| `JSONValue?.asByte`          | `Byte`        | throw `JSONTypeException`           |\n| `JSONValue?.asByteOrNull`    | `Byte?`       | return `null`                       |\n| `JSONValue?.asULong`         | `ULong`       | throw `JSONTypeException`           |\n| `JSONValue?.asULongOrNull`   | `ULong?`      | return `null`                       |\n| `JSONValue?.asUInt`          | `UInt`        | throw `JSONTypeException`           |\n| `JSONValue?.asUIntOrNull`    | `UInt?`       | return `null`                       |\n| `JSONValue?.asUShort`        | `UShort`      | throw `JSONTypeException`           |\n| `JSONValue?.asUShortOrNull`  | `UShort?`     | return `null`                       |\n| `JSONValue?.asUByte`         | `UByte`       | throw `JSONTypeException`           |\n| `JSONValue?.asUByteOrNull`   | `UByte?`      | return `null`                       |\n| `JSONValue?.asDecimal`       | `BigDecimal`  | throw `JSONTypeException`           |\n| `JSONValue?.asDecimalOrNull` | `BigDecimal?` | return `null`                       |\n| `JSONValue?.asNumber`        | `Number`      | throw `JSONTypeException`           |\n| `JSONValue?.asNumberOrNull`  | `Number?`     | return `null`                       |\n| `JSONValue?.asBoolean`       | `Boolean`     | throw `JSONTypeException`           |\n| `JSONValue?.asBooleanOrNull` | `Boolean?`    | return `null`                       |\n| `JSONValue?.asArray`         | `JSONArray`   | throw `JSONTypeException`           |\n| `JSONValue?.asArrayOrNull`   | `JSONArray?`  | return `null`                       |\n| `JSONValue?.asObject`        | `JSONObject`  | throw `JSONTypeException`           |\n| `JSONValue?.asObjectOrNull`  | `JSONObject?` | return `null`                       |\n\nThe [`JSONTypeException`](#jsontypeexception) will use the default value `\"Node\"` for the `nodeName`, and the class name\nof the expected type as the default for `expected`.\nThe default value for `key` is `null`.\n\nAs with the `asXxxxOrError()` functions, the extension values representing a simple value return the actual value type,\nnot the `JSONValue` subtype (_i.e._ `asInt` returns `Int`, not `JSONInt`), but the `asArrayOrError()` and\n`asObjectOrError()` functions return `JSONArray` and `JSONObject` respectively.\n\n#### Extension Functions\n\nA further way of casting a `JSONValue` to the expected type is provided by the `asXxxxOr` functions:\n\n| Extension Function         | Result type  |\n|----------------------------|--------------|\n| `JSONValue?.asStringOr()`  | `String`     |\n| `JSONValue?.asLongOr()`    | `Long`       |\n| `JSONValue?.asIntOr()`     | `Int`        |\n| `JSONValue?.asShortOr()`   | `Short`      |\n| `JSONValue?.asByteOr()`    | `Byte`       |\n| `JSONValue?.asULongOr()`   | `ULong`      |\n| `JSONValue?.asUIntOr()`    | `UInt`       |\n| `JSONValue?.asUShortOr()`  | `UShort`     |\n| `JSONValue?.asUByteOr()`   | `UByte`      |\n| `JSONValue?.asDecimalOr()` | `BigDecimal` |\n| `JSONValue?.asNumberOr()`  | `Number`     |\n| `JSONValue?.asBooleanOr()` | `Boolean`    |\n| `JSONValue?.asArrayOr()`   | `JSONArray`  |\n| `JSONValue?.asObjectOr()`  | `JSONObject` |\n\nThe functions all take a single parameter \u0026ndash; a lambda with the `JSONValue?` as the receiver which will be invoked\nif the `JSONValue?` is not the correct type.\nThis may be used to provide a default value, silently ignoring the type error, but more commonly it will be used to\nthrow an exception.\nFor example:\n```kotlin\n    node.asStringOr { typeError(expected = \"string\", key = \"/person/surname\", nodeName = \"Surname\") }\n```\n\nThe advantage of using these functions as compared to `asXxxxOrError()`, is that these functions are inline, and the\ncode to set up the parameters and call a separate function will not be executed if the node is of the correct type.\n\nAgain, as with the `asXxxxOrError()` functions, the extension functions returning a simple value return the actual value\ntype, not the `JSONValue` subtype, and the `asArrayOr()` and `asObjectOr()` functions return `JSONArray` and\n`JSONObject` respectively.\n\n## JSON Lines\n\nThe [JSON Lines](https://jsonlines.org/) specification allows multiple JSON values to be specified in a single stream of\ndata, separated by newline (`\\u000a`) characters.\nFor example, events may be logged to a file as a sequence of objects on separate lines; the alternative would be to\noutput a JSON array, but this would require a \u0026ldquo;`]`\u0026rdquo; terminator, complicating the shutdown of the process\n(particularly abnormal shutdown).\n\n```json lines\n{\"time\":\"2023-06-24T12:24:10.321+10:00\",\"eventType\":\"ACCOUNT_OPEN\",\"accountNumber\": \"123456789\"}\n{\"time\":\"2023-06-24T12:24:10.321+10:00\",\"eventType\":\"DEPOSIT\",\"accountNumber\": \"123456789\",\"amount\":\"1000.00\"}\n```\n\nThe individual items are usually objects (or sometimes arrays) formatted similarly, but that is not a requirement\n\u0026ndash; the items may be of any JSON type.\n\nThe JSON Lines format is particularly suitable for streaming data, so the\n[`kjson-stream`](https://github.com/pwall567/kjson-stream) library is more likely to be useful for JSON Lines input than\nthe functions in this library that parse a complete file, but the functions here are provided for completeness.\n\n### Parsing JSON Lines\n\nThe `kjson-core` library includes functions to parse JSON Lines format:\n```kotlin\n    val lines = JSON.parseLines(multiLineString)\n```\nThe result will always be a `JSONArray`; an empty string will result in a zero-length array.\n\nWhile the `parseLines()` function (and its corresponding function in the `Parser` class) will correctly parse a stream\nof data in JSON Lines format, the newline separator is in fact not required.\nThe function will accept JSON objects and/or arrays concatenated without any delimiters, but because whitespace is\nallowed between tokens of JSON data, the newline (if present) will be ignored.\n\n### Output JSON Lines\n\nIn most cases, JSON Lines data will be output as individual objects using `appendTo()` or `toJSON()`.\nIf an entire `JSONArray` is required to be output in JSON Lines format, there are four additional functions for this\npurpose:\n- `appendJSONLinesTo()` \u0026ndash; this appends the JSON Lines form of the `JSONArray` to a specified `Appendable`, _e.g._\n  a `Writer`\n- `toJSONLinesTo()` \u0026ndash; this converts the `JSONArray` to a `String` in JSON Lines format\n- `outputJSONLinesTo()` \u0026ndash; this outputs the JSON Lines form of the `JSONArray` using an `IntConsumer` (similar to\n  `appendJSONLinesTo()`, but allowing a greater choice of output mechanism)\n- `coOutputJSONLinesTo()` (suspend function) \u0026ndash; non-blocking version of `outputJSONLinesTo()`, suitable for use in\n  a coroutine-based environment\n\nThe functions all add a single newline after each item in the `JSONArray` for human readability reasons, even though (as\nnoted above) this is not strictly necessary.\n\n## `ParseOptions`\n\nThe parser will by default apply strict validation to the JSON input, and in some cases this may be unhelpful.\nThere is occasionally a need to parse JSON that is not correctly formatted according to the specification, particularly\nfor human-edited JSON, as opposed to JSON output by an automated process.\nAlso, for human-edited JSON, the ability to add comments is sometimes seen as desirable.\n\nTo accommodate these requirements, and to allow the specification of a maximum nesting depth, the parser may be supplied\nwith a `ParseOptions` object.\nFor example:\n```kotlin\n    val options = ParseOptions(\n        objectKeyDuplicate = JSONObject.DuplicateKeyOption.ERROR,\n        objectKeyUnquoted = false,\n        objectTrailingComma = false,\n        arrayTrailingComma = false,\n        maximumNestingDepth = 1000,\n        slashSlashComment = false,\n        slashStarComment = false,\n    )\n    val jsonValue = Parser.parse(jsonString, options)\n```\n\nThe `parseOptions` parameter is available on most functions invoking the `Parser`.\nAll of the properties of the object have default values, so only the properties that differ from their defaults need be\nspecified.\n\n### `objectKeyDuplicate`\n\nThe JSON specification states that a given key **SHOULD** appear only once in an object, but some software may output\nobjects with the same key repeated multiple times.\nUnder normal circumstances, the parser will throw an exception when it encounters a second occurrence of the same key,\nbut if such data is required to be accepted, the `objectKeyDuplicate` options setting may be used to specify the desired\nbehaviour.\n\nThe field is an `enum` (`JSONObject.DuplicateKeyOption`), and the possible values are:\n\n- `ERROR`: treat the duplicate key as an error (this is the default)\n- `TAKE_FIRST`: take the value of the first occurrence and ignore duplicates\n- `TAKE_LAST`: take only the last occurrence and ignore any preceding occurrences\n- `CHECK_IDENTICAL`: ignore duplicates only if they are identical to the original value, otherwise report an error\n\n### `objectKeyUnquoted`\n\nUnlike JavaScript, on which it is based, JSON requires that object keys be enclosed in quotes.\nSometimes, particularly when parsing human-edited JSON, it can be a helpful to allow keys to be conventional computer\nlanguage identifiers, and this can be selected by the `objectKeyUnquoted` option.\n\nSetting this flag to `true` will cause the parser to allow object keys to be specified without quotes.\nWhen using this option, the keys must follow this pattern:\n\n- the first character must be ASCII alphabetic (upper or lower case) or underscore\n- subsequent characters must be ASCII alphabetic (upper or lower case) or numeric or underscore\n\n### `objectTrailingComma`\n\nWhen outputting the members of an object, it can be simpler to add a comma after each member, regardless of whether it\nis the last one.\nTo allow trailing commas in objects, the option `objectTrailingComma` can be set to `true`.\n\n### `arrayTrailingComma`\n\nSimilarly, when outputting the items of an array, it can be simpler to add a comma after each item.\nTo allow trailing commas in arrays, the option `arrayTrailingComma` can be set to `true`.\n\n### `maximumNestingDepth`\n\nFaulty JSON output software \u0026ndash; or malicious actors \u0026ndash; may sometimes cause a sequence of characters\nrepresenting very deep nesting of objects or arrays to be presented to the parser.\nVery few uses of JSON will require more than about 100 levels of nesting, so a sequence of characters that cause more\nthan a few hundred levels of nesting are almost always the result of an error or a malicious attack.\n\nThe parser needs to allocate a small amount of memory for each level of nesting, and unlimited nesting would cause the\nprocess to fail, so the parser limits the number of levels allowed.\nThe default maximum nesting level is 1000, which should be more than enough for most uses.\nThe limit may be increased (or decreased) by the use of the `maximumNestingDepth` option.\n\n### `slashSlashComment`\n\nWhen this option is set to `true`, single-line comments (starting with `//` and ending with a newline or carriage\nreturn) may be included anywhere spaces would be allowed in the JSON data (that is, not in the middle of a string or \nnumber, but anywhere between tokens).\n\n### `slashStarComment`\n\nWhen this option is set to `true`, delimited comments (starting with `/*` and ending with `*/`) may be included anywhere\nspaces would be allowed in the JSON data (see [above](#slashslashcomment)).\n\n## Class Diagram\n\nThis class diagram may help to explain the main classes and interfaces and the inheritance and interface implementation\nrelationships between them.\n\n![Class Diagram](diagram.png \"UML Class Diagram\")\n\nThe diagram was produced by [Dia](https://wiki.gnome.org/Apps/Dia/); the diagram file is at [diagram.dia](diagram.dia).\n\n## Dependency Specification\n\nThe latest version of the library is 10.2, and it may be obtained from the Maven Central repository.\n\n### Maven\n```xml\n    \u003cdependency\u003e\n      \u003cgroupId\u003eio.kjson\u003c/groupId\u003e\n      \u003cartifactId\u003ekjson-core\u003c/artifactId\u003e\n      \u003cversion\u003e10.2\u003c/version\u003e\n    \u003c/dependency\u003e\n```\n### Gradle\n```groovy\n    implementation \"io.kjson:kjson-core:10.2\"\n```\n### Gradle (kts)\n```kotlin\n    implementation(\"io.kjson:kjson-core:10.2\")\n```\n\nPeter Wall\n\n2025-06-09\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpwall567%2Fkjson-core","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpwall567%2Fkjson-core","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpwall567%2Fkjson-core/lists"}