# Guide to JSONPath for Querying JSON in Kotlin

### Overview
  * **Java** and **Kotlin** are very powerful statically typed languages, but sometimes we face situations where we need to handle dynamically changing objects according to requirements. Examples include **Map<String, Any>**, **List<Any>**, and **JSON** strings of type **String**. Reading, adding, and modifying this data can be quite cumbersome. Using `Jayway JsonPath`, data can be controlled in a very elegant and easy manner based on the **Path**.

### build.gradle.kts
  * Add the following content to the **build.gradle.kts** file at the project root.

```kotlin
dependencies {
    implementation("com.jayway.jsonpath:json-path:2.9.0")
}
```

### Initializing JsonPath Object
  * It's time to initialize **JsonPath** from the original source.

```kotlin
// Creating JsonPath object
// Arguments can be Map<String, Any>, List<Any>, JSON String
val inputJsonPath = JsonPath.parse(input)
```

  * `JsonPath.parse()` can take a `String` type containing a **JSON** string as an argument. (If it's not a valid **JSON** string, **com.jayway.jsonpath.InvalidJsonException** exception is thrown.) It can also take dynamically stored data in `Map<String, Any>`, `List<String>` types as arguments.

### Querying Data with JsonPath
  * Use `.read()` to easily query data from complex paths.

```kotlin
// Returns the foo.bar array as a List
// If the Path does not exist, com.jayway.jsonpath.PathNotFoundException exception is thrown
inputJsonPath.read("$['foo']['bar']") as List<Map<String, Any>>

// Returns the total count of the foo.bar array
// If the Path does not exist, com.jayway.jsonpath.PathNotFoundException exception is thrown
inputJsonPath.read("$['foo']['bar'].length()") as Int
```

### JsonPath Data Addition/Modification
  * Use `.put()` to add/modify data and `set()` for data modification.

```kotlin
// Modify root's foo.bar to foobar, create new if not exist
inputJsonPath.put("$['foo']", "bar", "foobar")

// Modify foo.bar to foobar, ignore if not exist
inputJsonPath.set("$['foo']['bar']", "foobar")
```

  * `.put()` ignores if the **Path** does not exist. It creates a new **Key** if it does not exist, and overwrites the existing value if it does.
  * `.set()` ignores if the **Path** does not exist. (A **com.jayway.jsonpath.PathNotFoundException** exception occurs if the parent Path does not exist.) That is, it overwrites the existing value only if the **Key** exists.

### Acquiring Result Data with JsonPath
  * Use `.json()`, `.jsonString()` to obtain the result data.

```kotlin
// Create the result as a Map
val outputMap = inputJsonPath.json() as Map<String, Any>

// Create the result as a JSON String
val outputJsonString = inputJsonPath.jsonString()
```

  * For the final result, `.json()` allows type conversion to `Map<String, Any>` or `List<String>`.
  * For the final result, `.jsonString()` returns a `String` type containing a **JSON** string.

### References and Further Reading
  * [Jayway JsonPath](https://github.com/json-path/JsonPath)
  * [JSONPath Online Evaluator](https://jsonpath.com/)

