[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-7581":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":9,"language":10,"languages":9,"totalLinesOfCode":9,"stars":11,"forks":12,"watchers":13,"openIssues":14,"contributorsCount":15,"subscribersCount":15,"size":15,"stars1d":15,"stars7d":15,"stars30d":16,"stars90d":15,"forks30d":15,"starsTrendScore":15,"compositeScore":17,"rankGlobal":9,"rankLanguage":9,"license":18,"archived":19,"fork":19,"defaultBranch":20,"hasWiki":21,"hasPages":19,"topics":22,"createdAt":9,"pushedAt":9,"updatedAt":25,"readmeContent":26,"aiSummary":27,"trendingCount":15,"starSnapshotCount":15,"syncStatus":28,"lastSyncTime":29,"discoverSource":30},7581,"klaxon","cbeust\u002Fklaxon","cbeust","A JSON parser for Kotlin",null,"Kotlin",1860,123,25,91,0,1,19.28,"Apache License 2.0",false,"master",true,[23,24],"json","kotlin","2026-06-12 02:01:41","\n\u003Cimg src=\"doc\u002Fklaxon.png\" alt=\"Klaxon logo\" height=\"101\" width=\"220\" \u002F>\n\nKlaxon is a library to parse JSON in Kotlin\n\n## Install\n\n```kotlin\ndependencies {\n    implementation 'com.beust:klaxon:5.5'\n}\n```\n\n## Developer setup\n\nFollow these steps to get the project running locally for development:\n\n- **Prerequisites:**\n    - JDK 8 or 11 installed and `JAVA_HOME` set.\n    - Git\n- **Clone the repo:**\n\n```bash\ngit clone https:\u002F\u002Fgithub.com\u002Fcbeust\u002Fklaxon.git\ncd klaxon\n```\n\n- **Build the project:**\n\nUnix\u002FmacOS:\n```bash\n.\u002Fgradlew build\n```\n\nWindows (PowerShell\u002FCMD):\n```powershell\n.\\gradlew.bat build\n```\n\n- **Run tests:**\n\n```bash\n.\u002Fgradlew test\n```\n\n- **Run a single test class:**\n\n```bash\n.\u002Fgradlew test --tests com.beust.klaxon.BindingTest\n```\n\n- **Import into IDE:** Import the project as a Gradle project in IntelliJ IDEA (use the Gradle wrapper). Enable auto-import for Gradle changes.\n\n- **Useful module\u002Ftask shortcuts:**\n    - Assemble JARs: `.\u002Fgradlew assemble`\n    - Run aggregate task: `.\u002Fgradlew publishToMavenLocal`\n    - Generate signature files: `.\u002Fgradlew signCustomPublication`\n\n## Community\n\nJoin the [`#klaxon` Slack channel](https:\u002F\u002Fkotlinlang.slack.com\u002Fmessages\u002FC90AVCDQU\u002F).\n\n## Use\n\nKlaxon has different API's depending on your needs:\n\n- [An object binding API](#object-binding-api) to bind JSON documents directly to your objects, and vice versa.\n- [A streaming API](#streaming-api) to process your JSON documents as they're being read.\n- [A low level API](#low-level-api) to manipulate JSON objects and use queries on them.\n- [A JSON path query API](#json-path-query-api) to extract specific parts of your JSON document while streaming.\n\nThese four API's cover various scenarios and you can decide which one to use based on whether you want\nto stream your document and whether you need to query it.\n\n|                     | Streaming | Query        | Manipulation |\n|---------------------|-----------|--------------|--------------|\n| Object binding API  | No        | No           | Kotlin objects |\n| Streaming API       | Yes       | No           | Kotlin objects and JsonObject\u002FJsonArray |\n| Low level API       | No        | Yes          | Kotlin objects |\n| JSON Path query API | Yes       | Yes          | JsonObject\u002FJsonArray |\n\n\n## Object binding API\n\n### General usage\n\n\nTo use Klaxon's high level API, you define your objects inside a class. Klaxon supports all the classes you can\ndefine in Kotlin:\n\n- Regular and `data` classes.\n- Mutable and immutable classes.\n- Classes with default parameters.\n\nFor example:\n\n```kotlin\nclass Person(val name: String, val age: Int)\n```\n\nClasses with default parameters are supported as well:\n\n```kotlin\nclass Person (val name: String, var age: Int = 23)\n```\n\nOnce you've specified your value class, you invoke the `parse()` function, parameterized with that class:\n\n```kotlin\nval result = Klaxon()\n    .parse\u003CPerson>(\"\"\"\n    {\n      \"name\": \"John Smith\",\n    }\n    \"\"\")\n\nassert(result?.name == \"John Smith\")\nassert(result.age == 23)\n```\n\n### The @Json annotation\n\nThe `@Json` annotation allows you to customize how the mapping between your JSON documents and\nyour Kotlin objects is performed. It supports the following attributes:\n\n#### `name`\n\nUse the `name` attribute when your Kotlin property has a different name than the field found in your\nJSON document:\n\n```kotlin\ndata class Person(\n    @Json(name = \"the_name\")\n    val name: String\n)\n```\n\n```kotlin\nval result = Klaxon()\n    .parse\u003CPerson>(\"\"\"\n    {\n      \"the_name\": \"John Smith\", \u002F\u002F note the field name\n      \"age\": 23\n    }\n\"\"\")\n\nassert(result.name == \"John Smith\")\nassert(result.age == 23)\n```\n\n#### `ignored`\n\nYou can set this boolean attribute to `true` if you want certain properties of your value class not to be\nmapped during the JSON parsing process. This is useful if you defined additional properties in your value classes.\n\n```kotlin\nclass Ignored(val name: String) {\n   @Json(ignored = true)\n   val actualName: String get() = ...\n}\n```\n\nIn this example, Klaxon will not try to find a field called `actualName` in your JSON document.\n\nNote that you can achieve the same result by declaring these properties `private`:\n\n```kotlin\nclass Ignored(val name: String) {\n   private val actualName: String get() = ...\n}\n```\n\nAdditionally, if you want to declare a property `private` but still want that property to be visible to\nKlaxon, you can annotate it with `@Json(ignored = false)`.\n\n#### `index`\n\nThe `index` attribute allows you to specify where in the JSON string the key should appear. This allows you to\nspecify that certain keys should appear before others:\n\n```kotlin\nclass Data(\n    @Json(index = 1) val id: String,\n    @Json(index = 2) val name: String\n)\nprintln(Klaxon().toJsonString(Data(\"id\", \"foo\")))\n\n\u002F\u002F displays { \"id\": \"id\", \"name\": \"foo\" }\n```\n\nwhereas\n\n```kotlin\nclass Data(\n    @Json(index = 2) val id: String,\n    @Json(index = 1) val name: String\n)\nprintln(Klaxon().toJsonString(Data(\"id\", \"foo\")))\n\n\u002F\u002F displays { \"name\": \"foo\" , \"id\": \"id\" }\n```\n\nProperties that are not assigned an index will be displayed in a non deterministic order in the output JSON.\n\n#### `serializeNull`\n\nBy default, all properties with the value null are serialized to JSON, for example: \n\n```kotlin\nclass Data(\n    val id: Int?\n)\nprintln(Klaxon().toJsonString(Data(null)))\n\n\u002F\u002F displays { \"id\": null }\n```\n\nIf you instead want the properties with a null value to be absent in the JSON string, \nuse `@Json(serializeNull = false)`:\n\n```kotlin\nclass Data(\n    @Json(serializeNull = false)\n    val id: Int?\n)\nprintln(Klaxon().toJsonString(Data(null)))\n\n\u002F\u002F displays {}\n```\n\nIf `serializeNull` is false, the Kotlin default values for this property will be ignored during parsing. \nInstead, if the property is absent in the JSON, the value will default to `null`.\n\n\nIf you don't want to apply this option to every attribute, you can also set it as an instance-wide setting for Klaxon:\n```kotlin\nval settings = KlaxonSettings(serializeNull = false)\n```\n\nThis saves you the hassle of setting these attributes onto every single field.\n\n```kotlin\ndata class User(\n    val username: String, val email: String, \u002F\u002F mandatory\n    val phone: String?, val fax: String?, val age: Int? \u002F\u002F optional\n)\n\nKlaxon(settings)\n  .toJsonString(User(\"user\", \"user@example.org\", null, null, null))\n\n\u002F\u002F displays {}\n```\n\nYou may still set settings with the `@Json` annotation onto specific fields.\nThey will take precedence over global settings of the Klaxon instance.\n\n### Renaming fields\n\nOn top of using the `@Json(name=...)` annotation to rename fields, you can implement a field renamer yourself that\nwill be applied to all the fields that Klaxon encounters, both to and from JSON. You achieve this result by passing an \nimplementation of the `FieldRenamer` interface to your `Klaxon` object:\n\n```kotlin\n    val renamer = object: FieldRenamer {\n        override fun toJson(fieldName: String) = FieldRenamer.camelToUnderscores(fieldName)\n        override fun fromJson(fieldName: String) = FieldRenamer.underscoreToCamel(fieldName)\n    }\n\n    val klaxon = Klaxon().fieldRenamer(renamer)\n```\n\n### Custom types\n\nKlaxon will do its best to initialize the objects with what it found in the JSON document but you can take control\nof this mapping yourself by defining type converters.\n\nThe converter interface is as follows:\n\n```kotlin\ninterface Converter {\n    fun canConvert(cls: Class\u003C*>) : Boolean\n    fun toJson(value: Any): String\n    fun fromJson(jv: JsonValue) : Any\n}\n```\n\nYou define a class that implements this interface and implement the logic that converts your class to and from JSON.\nFor example, suppose you receive a JSON document with a field that can either be a `0` or a `1` and you want to\nconvert that field into your own type that's initialized with a boolean:\n\n```kotlin\nclass BooleanHolder(val flag: Boolean)\n\nval myConverter = object: Converter {\n    override fun canConvert(cls: Class\u003C*>)\n        = cls == BooleanHolder::class.java\n\n    override fun toJson(value: Any): String\n        = \"\"\"{\"flag\" : \"${if ((value as BooleanHolder).flag == true) 1 else 0}\"\"\"\n\n    override fun fromJson(jv: JsonValue)\n        = BooleanHolder(jv.objInt(\"flag\") != 0)\n\n}\n```\n\nNext, you declare your converter to your `Klaxon` object before parsing:\n\n```kotlin\nval result = Klaxon()\n    .converter(myConverter)\n    .parse\u003CBooleanHolder>(\"\"\"\n        { \"flag\" : 1 }\n    \"\"\")\n\nassert(result.flag)\n```\n\n### JsonValue\n\nThe `Converter` type passes you an instance of the [`JsonValue`](https:\u002F\u002Fgithub.com\u002Fcbeust\u002Fklaxon\u002Fblob\u002Fmaster\u002Fklaxon\u002Fsrc\u002Fmain\u002Fkotlin\u002Fcom\u002Fbeust\u002Fklaxon\u002FJsonValue.kt) class.\nThis class is a container of a Json value. It\nis guaranteed to contain one and exactly one of either a number, a string, a character, a `JsonObject` or a `JsonArray`.\nIf one of these fields is set, the others are guaranteed to be `null`. Inspect that value in your converter to make\nsure that the value you are expecting is present, otherwise, you can cast a `KlaxonException` to report the invalid\nJSON that you just found.\n\n### Field conversion overriding\n\nIt's sometimes useful to be able to specify a type conversion for a specific field without that conversion applying\nto all types of your document (for example, your JSON document might contain various dates of different formats).\nYou can use field conversion types for this kind of situation.\n\nSuch fields are specified by your own annotation, which you need to specify as targetting a `FIELD`:\n\n```kotlin\n@Target(AnnotationTarget.FIELD)\nannotation class KlaxonDate\n```\n\nNext, annotate the field that requires this specific handling in the constructor of your class. Do note that such\na constructor needs to be annotated with `@JvmOverloads`:\n\n```kotlin\nclass WithDate @JvmOverloads constructor(\n    @KlaxonDate\n    val date: LocalDateTime\n)\n```\n\nDefine your type converter (which has the same type as the converters defined previously). In this case, we\nare converting a `String` from JSON into a `LocalDateTime`:\n\n```kotlin\nval dateConverter = object: Converter {\n    override fun canConvert(cls: Class\u003C*>)\n        = cls == LocalDateTime::class.java\n\n    override fun fromJson(jv: JsonValue) =\n        if (jv.string != null) {\n            LocalDateTime.parse(jv.string, DateTimeFormatter.ofPattern(\"yyyy-MM-dd HH:mm\"))\n        } else {\n            throw KlaxonException(\"Couldn't parse date: ${jv.string}\")\n        }\n\n    override fun toJson(o: Any)\n            = \"\"\" { \"date\" : $o } \"\"\"\n}\n```\n\nFinally, declare the association between that converter and your annotation in your `Klaxon` object before parsing:\n\n```kotlin\nval result = Klaxon()\n    .fieldConverter(KlaxonDate::class, dateConverter)\n    .parse\u003CWithDate>(\"\"\"\n    {\n      \"theDate\": \"2017-05-10 16:30\"\n    }\n\"\"\")\n\nassert(result?.date == LocalDateTime.of(2017, 5, 10, 16, 30))\n```\n\n### Property strategy\n\nYou can instruct Klaxon to dynamically ignore properties with the `PropertyStrategy` interface:\n\n```kotlin\ninterface PropertyStrategy {\n    \u002F**\n     * @return true if this property should be mapped.\n     *\u002F\n    fun accept(property: KProperty\u003C*>): Boolean\n}\n```\n\nThis is a dynamic version of `@Json(ignored = true)`, which you can register with your `Klaxon` instance with the function `propertyStrategy()`:\n\n```kotlin\nval ps = object: PropertyStrategy {\n    override fun accept(property: KProperty\u003C*>) = property.name != \"something\"\n}\nval klaxon = Klaxon().propertyStrategy(ps)\n```\n\nYou can define multiple `PropertyStrategy` instances, and in such a case, they all need to return `true` for a property to be included.\n\n### Polymorphism\n\nJSON documents sometimes contain dynamic payloads whose type can vary. Klaxon supports two different use cases for\npolymorphism: polymorphic classes and polymorphic fields. Klaxon gives you control on polymorphism with the\nannotation `@TypeFor`, which can be placed either on a class or on a field.\n\n#### Polymorphic classes\n\nA polymorphic class is a class whose actual type is defined by one of its own properties. Consider this JSON:\n\n```json\n[\n    { \"type\": \"rectangle\", \"width\": 100, \"height\": 50 },\n    { \"type\": \"circle\", \"radius\": 20}\n]\n```\n\nThe content of the field `type` determines the class that needs to be instantiated. You would model this as\nfollows with Klaxon:\n\n```kotlin\n@TypeFor(field = \"type\", adapter = ShapeTypeAdapter::class)\nopen class Shape(val type: String)\ndata class Rectangle(val width: Int, val height: Int): Shape(\"rectangle\")\ndata class Circle(val radius: Int): Shape(\"circle\")\n```\n\nThe type adapter is as follows:\n\n```kotlin\nclass ShapeTypeAdapter: TypeAdapter\u003CShape> {\n    override fun classFor(type: Any): KClass\u003Cout Shape> = when(type as String) {\n        \"rectangle\" -> Rectangle::class\n        \"circle\" -> Circle::class\n        else -> throw IllegalArgumentException(\"Unknown type: $type\")\n    }\n}\n```\n\n#### Polymorphic fields\n\nKlaxon also allows a field to determine the class to be instantiated for another field. Consider the following JSON document:\n\n```json\n[\n    { \"type\": 1, \"shape\": { \"width\": 100, \"height\": 50 } },\n    { \"type\": 2, \"shape\": { \"radius\": 20} }\n]\n```\n\nThis is an array of polymorphic objects. The `type` field is a discriminant which determines the type of the field\n`shape`: if its value is `1`, the shape is a rectangle, if `2`, it's a circle.\n\nTo parse this document with Klaxon, we first model these classes with a hierarchy:\n\n```kotlin\nopen class Shape\ndata class Rectangle(val width: Int, val height: Int): Shape()\ndata class Circle(val radius: Int): Shape()\n```\n\nWe then define the class that the objects of this array are instances of:\n\n```kotlin\nclass Data (\n    @TypeFor(field = \"shape\", adapter = ShapeTypeAdapter::class)\n    val type: Integer,\n\n    val shape: Shape\n)\n```\n\nNotice the `@TypeFor` annotation, which tells Klaxon which field this value is a discriminant for, and also provides\na class that will translate these integer values into the correct class:\n\n```kotlin\nclass ShapeTypeAdapter: TypeAdapter\u003CShape> {\n    override fun classFor(type: Any): KClass\u003Cout Shape> = when(type as Int) {\n        1 -> Rectangle::class\n        2 -> Circle::class\n        else -> throw IllegalArgumentException(\"Unknown type: $type\")\n    }\n}\n```\n\nWith this code in place, you can now parse the provided JSON document above the regular way and the the following\ntests will pass:\n\n```kotlin\nval shapes = Klaxon().parseArray\u003CData>(json)\nassertThat(shapes!![0].shape as Rectangle).isEqualTo(Rectangle(100, 50))\nassertThat(shapes[1].shape as Circle).isEqualTo(Circle(20))\n```\n\n## Streaming API\n\nThe streaming API is useful in a few scenarios:\n\n- When your JSON document is very large and reading it all in memory might cause issues.\n- When you want your code to react as soon as JSON values are being read, without waiting for the entire document\nto be parsed.\n\nThis second point is especially important to make mobile apps as responsive as possible and make them less reliant\non network speed.  \n\nNote: the streaming API requires that each value in the document be handled by the reader.  If you are simply\nlooking to extract a single value the [`PathMatcher API`](#json-path-query-api) may be a better fit.\n\n### Writing JSON with the streaming API\n\nAs opposed to conventional JSON libraries, Klaxon doesn't supply a `JsonWriter` class to create JSON documents since\nthis need is already covered by the `json()` function, documented in the [Advanced DSL](#dsl) section.\n\n### Reading JSON with the streaming API\n\nStreaming JSON is performed with the `JsonReader` class. Here is an example:\n\n```kotlin\nval objectString = \"\"\"{\n     \"name\" : \"Joe\",\n     \"age\" : 23,\n     \"flag\" : true,\n     \"array\" : [1, 3],\n     \"obj1\" : { \"a\" : 1, \"b\" : 2 }\n}\"\"\"\n\nJsonReader(StringReader(objectString)).use { reader ->\n    reader.beginObject() {\n        var name: String? = null\n        var age: Int? = null\n        var flag: Boolean? = null\n        var array: List\u003CAny> = arrayListOf\u003CAny>()\n        var obj1: JsonObject? = null\n        while (reader.hasNext()) {\n            val readName = reader.nextName()\n            when (readName) {\n                \"name\" -> name = reader.nextString()\n                \"age\" -> age = reader.nextInt()\n                \"flag\" -> flag = reader.nextBoolean()\n                \"array\" -> array = reader.nextArray()\n                \"obj1\" -> obj1 = reader.nextObject()\n                else -> Assert.fail(\"Unexpected name: $readName\")\n            }\n        }\n    }\n}\n```\n\nThere are two special functions to be aware of: `beginObject()` and `beginArray()`. Use these functions\nwhen you are about to read an object or an array from your JSON stream. These functions will make sure\nthat the stream is correctly positioned (open brace or open bracket) and once you are done consuming\nthe content of that entity, the functions will make sure that your object is correctly closed (closing brace\nor closing bracket). Note that these functions accept a closure as an argument, so there are no `closeObject()\u002FcloseArray()` functions.\n\nIt is possible to mix both the object binding and streaming API's, so you can benefit from the best of both worlds.\n\nFor example, suppose your JSON document contains an array with thousands of elements in them, each of these elements\nbeing an object in your code base. You can use the streaming API to consume the array one element at a time and then\nuse the object binding API to easily map these elements directly to one of your objects:\n\n```kotlin\ndata class Person(val name: String, val age: Int)\nval array = \"\"\"[\n        { \"name\": \"Joe\", \"age\": 23 },\n        { \"name\": \"Jill\", \"age\": 35 }\n    ]\"\"\"\n\nfun streamingArray() {\n    val klaxon = Klaxon()\n    JsonReader(StringReader(array)).use { reader ->\n        val result = arrayListOf\u003CPerson>()\n        reader.beginArray {\n            while (reader.hasNext()) {\n                val person = klaxon.parse\u003CPerson1>(reader)\n                result.add(person)\n            }\n        }\n    }\n}\n```\n## JSON Path Query API\n\nThe [JSON Path specification](https:\u002F\u002Fgithub.com\u002Fjson-path\u002FJsonPath) defines how to locate elements inside\na JSON document. Klaxon allows you to define path matchers that can match specific elements in your\ndocument and receive a callback each time a matching element is found.\n\nConsider the following document:\n\n```json\n{\n   \"library\": {\n       \"books\": [\n           {\n               \"author\": \"Herman Melville\",\n               \"title\": \"Moby Dick\"\n           },\n           {\n               \"author\": \"Jules Vernes\",\n               \"title\": \"L'île mystérieuse\"\n           }\n       ]\n   }\n}\n```\n\nAccording to the JSON Path spec, the two authors have the following JSON paths:\n\n```\n$.library.books[0].author\n$.library.books[1].author\n```\n\nWe'll define a [`PathMatcher`](https:\u002F\u002Fgithub.com\u002Fcbeust\u002Fklaxon\u002Fblob\u002Fmaster\u002Fklaxon\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Fbeust\u002Fklaxon\u002FPathMatcher.kt) that uses a regular expression to filter only the elements we want:\n\n```kotlin\nval pathMatcher = object : PathMatcher {\n    override fun pathMatches(path: String) = Pattern.matches(\".*library.*books.*author.*\", path)\n\n    override fun onMatch(path: String, value: Any) {\n        println(\"Adding $path = $value\")\n    }\n}\n\nKlaxon()\n    .pathMatcher(pathMatcher)\n    .parseJsonObject(document)\n```\n\nOutput:\n\n```\nAdding $.library.books[0].author = Herman Melville\nAdding $.library.books[1].author = Jules Vernes\n```\n\nTwo notes:\n- Klaxon doesn't support the JSON Path expression language, only the element location specification.\n- This API is streaming: your path observers will be notified as soon as a matching element has been\ndetected and its value completely parsed.\n\n\n## Low level API\n\nValues parsed from a valid JSON file can be of the following type:\n\n* Int\n* Long\n* BigInteger\n* String\n* Double\n* Boolean\n* JsonObject\n* JsonArray\n\n`JsonObject` behaves like a `Map` while `JsonArray` behaves like a `List`. Once you have parsed a file, you should cast it to the type that you expect. For example, consider this simple file called `object.json`:\n\n```json\n{\n    \"firstName\" : \"Cedric\",\n    \"lastName\" : \"Beust\"\n}\n```\n\nSince this is a JSON object, we parse it as follows:\n\n```kotlin\nfun parse(name: String) : Any? {\n    val cls = Parser::class.java\n    return cls.getResourceAsStream(name)?.let { inputStream ->\n        return Parser.default().parse(inputStream)\n    }\n}\n\n\u002F\u002F ...\n\nval obj = parse(\"\u002Fobject.json\") as JsonObject\n```\n\nParse from String value :\n```kotlin\nval parser: Parser = Parser.default()\nval stringBuilder: StringBuilder = StringBuilder(\"{\\\"name\\\":\\\"Cedric Beust\\\", \\\"age\\\":23}\")\nval json: JsonObject = parser.parse(stringBuilder) as JsonObject\nprintln(\"Name : ${json.string(\"name\")}, Age : ${json.int(\"age\")}\")\n```\nResult :\n```\nName : Cedric Beust, Age : 23\n```\n\nYou can also access the JSON content as a file, or any other resource you can get an `InputStream` from.\n\nLet's query these values:\n\n```kotlin\nval firstName = obj.string(\"firstName\")\nval lastName = obj.string(\"lastName\")\nprintln(\"Name: $firstName $lastName\")\n\n\u002F\u002F Prints: Name: Cedric Beust\n```\n\n`JsonObject` implements the following methods:\n\n```kotlin\nfun int(fieldName: String) : Int?\nfun long(fieldName: String) : Long?\nfun bigInt(fieldName: String) : BigInteger?\nfun string(fieldName: String) : String?\nfun double(fieldName: String) : Double?\nfun boolean(fieldName: String) : Boolean?\nfun obj(fieldName: String) : JsonObject?\nfun \u003CT> array(thisType: T, fieldName: String) : JsonArray\u003CT>?\n```\n\n`JsonArray` implements the same methods, except that they return `JsonArray`s of the same type. This allows you to easily fetch collections of fields or even sub-objects. For example, consider the following:\n\n```json\n[\n    {\n        \"name\" : \"John\",\n        \"age\" : 20\n    },\n    {\n        \"name\" : \"Amy\",\n        \"age\" : 25\n    },\n    {\n        \"name\" : \"Jessica\",\n        \"age\" : 38\n    }\n]\n```\n\nWe can easily collect all the ages as follows:\n\n```kotlin\nval array = parse(\"\u002Fe.json\") as JsonArray\u003CJsonObject>\n\nval ages = array.long(\"age\")\nprintln(\"Ages: $ages\")\n\n\u002F\u002F Prints: Ages: JsonArray(value=[20, 25, 38])\n```\n\nSince a `JsonArray` behaves like a `List`, we can apply closures on them, such as `filter`:\n\n```kotlin\nval oldPeople = array.filter {\n    it.long(\"age\")!! > 30\n}\nprintln(\"Old people: $oldPeople\")\n\n\u002F\u002F Prints: Old people: [JsonObject(map={age=38, name=Jessica})]\n```\n\nLet's look at a more complex example:\n\n```json\n[\n    {\n        \"first\": \"Dale\",\n        \"last\": \"Cooper\",\n        \"schoolResults\" : {\n            \"scores\": [\n                { \"name\": \"math\", \"grade\" : 90 },\n                { \"name\": \"physics\", \"grade\" : 50 },\n                { \"name\": \"history\", \"grade\" : 85 }\n            ],\n            \"location\" : \"Berkeley\"\n        }\n    },\n    {\n        \"first\": \"Kara\",\n        \"last\": \"Thrace\",\n        \"schoolResults\" : {\n            \"scores\": [\n                { \"name\": \"math\", \"grade\" : 75 },\n                { \"name\": \"physics\", \"grade\" : 90 },\n                { \"name\": \"history\", \"grade\" : 55 }\n            ],\n            \"location\" : \"Stanford\"\n        }\n    },\n    {\n        \"first\": \"Jack\",\n        \"last\": \"Harkness\",\n        \"schoolResults\" : {\n            \"scores\": [\n                { \"name\": \"math\", \"grade\" : 40 },\n                { \"name\": \"physics\", \"grade\" : 82 },\n                { \"name\": \"history\", \"grade\" : 60 }\n            ],\n            \"location\" : \"Berkeley\"\n        }\n    }\n]\n```\n\nLet's chain a few operations, for example, finding the last names of all the people who studied in Berkeley:\n\n```kotlin\nprintln(\"=== Everyone who studied in Berkeley:\")\nval berkeley = array.filter {\n    it.obj(\"schoolResults\")?.string(\"location\") == \"Berkeley\"\n}.map {\n    it.string(\"last\")\n}\nprintln(\"$berkeley\")\n\n\u002F\u002F Prints:\n\u002F\u002F === Everyone who studied in Berkeley:\n\u002F\u002F [Cooper, Harkness]\n```\n\nAll the grades over 75:\n\n```kotlin\nprintln(\"=== All grades bigger than 75\")\nval result = array.flatMap {\n    it.obj(\"schoolResults\")\n            ?.array\u003CJsonObject>(\"scores\")?.filter {\n                it.long(\"grade\")!! > 75\n            }!!\n}\nprintln(\"Result: $result\")\n\n\u002F\u002F Prints:\n\u002F\u002F === All grades bigger than 75\n\u002F\u002F Result: [JsonObject(map={name=math, grade=90}), JsonObject(map={name=history, grade=85}), JsonObject(map={name=physics, grade=90}), JsonObject(map={name=physics, grade=82})]\n\n```\n\nNote the use of `flatMap` which transforms an initial result of a list of lists into a single list. If you use `map`, you will get a list of three lists:\n\n```kotlin\n\u002F\u002F Using map instead of flatMap\n\u002F\u002F Prints:\n\u002F\u002F Result: [[JsonObject(map={name=math, grade=90}), JsonObject(map={name=history, grade=85})], [JsonObject(map={name=physics, grade=90})], [JsonObject(    map={name=physics, grade=82})]]\n```\n\n## Pretty printing\n\nYou can convert any `JsonObject` to a valid JSON string by calling `toJsonString()` on it. If you want to get a pretty-printed\nversion of that string, call `toJsonString(true)`\n\n## DSL\n\nYou can easily create JSON objects with Klaxon's DSL. There are two different variants of that DSL: declarative and imperative.\n\nThe declarative DSL uses maps and pairs (with the `to` operator) to declare the associations between your keys and your values:\n\n```kotlin\nval obj = json {\n    \"color\" to \"red\",\n    \"age\" to 23\n}\n```\n\nThe declarative syntax limits you to only having values in your object, so if you need to use arbitrary pieces of code inside your DSL object, you can use the imperative syntax instead. This syntax doesn't use pairs but lambdas, and you use the function `put()` to define your fields:\n\n```kotlin\nval obj = json {\n   repeat(3) {\n      put(\"field$it\", it * 2)\n   }\n}\n```\n\nOutput:\n\n```json\n{\n  \"fields\": {\n    \"field0\": 0,\n    \"field1\": 2,\n    \"field2\": 4\n  }\n}\n```\n\n## Flattening and path lookup\n\nIf we have the following JSON\n```json\n{\n\t\"users\" : [\n\t    {\n\t        \"email\" : \"user@is.here\"\n\t    },\n\t    {\n\t    \t\"email\" : \"spammer@there.us\"\n\t    }\n\t]\n}\n```\n\nWe can find all emails by\n\n```kotlin\n(parse(\"my.json\") as JsonObject).lookup\u003CString?>(\"users.email\")\n```\n\n## Parsers\n\nThere are two parser implementations with official support. The first is written in Kotlin and is accessed by calling\n`Parser.default()`.\n\nThe second is a parser implemented using the [FasterXML Jackson](https:\u002F\u002Fgithub.com\u002FFasterXML\u002Fjackson) mapper.\nThis parser has been found to take 1\u002F2 the time of the default Parser on large JSON payloads.\n\nThe Jackson mapper can be found at the coordinates\n`com.beust:klaxon-jackson:[version]`. To use this parser, call the extension `Parser.jackson()`.\n\n### Implementation\n\nThe Kotlin based Parser is implemented as a mutable state machine supported by a simplistic `State` monad,\nmaking the main loop very simple:\n\n```kotlin\nval stateMachine = StateMachine()\nval lexer = Lexer(inputStream)\nvar world = World(Status.INIT)\ndo {\n    val token = lexer.nextToken()\n    world = stateMachine.next(world, token)\n} while (token.tokenType != Type.EOF)\n```\n\n## Troubleshooting\n\nHere are a few common errors and how to resolve them.\n\n- `NoSuchMethodException: \u003Cinit>`\n\nYou might see the following exception:\n\n```kotlin\nCaused by: java.lang.NoSuchMethodException: BindingAdapterTest$personMappingTest$Person.\u003Cinit>()\n\tat java.lang.Class.getConstructor0(Class.java:3082)\n\tat java.lang.Class.newInstance(Class.java:412)\n```\n\nThis is typically caused by your object class being defined inside a function (which makes its constructor require an\n additional parameter that Klaxon doesn't know how to fill).\n\nSolution: move that class definition outside of the function.\n","Klaxon 是一个用于 Kotlin 的 JSON 解析库。它提供了多种 API 来满足不同的需求，包括对象绑定 API、流式 API、低级 API 以及 JSON 路径查询 API。对象绑定 API 可以直接将 JSON 文档绑定到 Kotlin 对象上；流式 API 支持在读取时处理 JSON 文档；低级 API 允许对 JSON 对象进行操作和查询；而 JSON 路径查询 API 则可以在流式处理的同时提取特定部分的数据。这些功能使得 Klaxon 非常适合需要高效解析和处理 JSON 数据的 Kotlin 项目，无论是简单的数据绑定还是复杂的流式处理场景。",2,"2026-06-11 03:13:09","top_language"]