J'essaye de créer un DSL pour créer des JSONObjects. Voici une classe de générateur et un exemple d'utilisation:

import org.json.JSONObject

fun json(build: JsonObjectBuilder.() -> Unit): JSONObject {
    val builder = JsonObjectBuilder()
    builder.build()
    return builder.json
}

class JsonObjectBuilder {
    val json = JSONObject()

    infix fun <T> String.To(value: T) {
        json.put(this, value)
    }
}

fun main(args: Array<String>) {
    val jsonObject =
            json {
                "name" To "ilkin"
                "age" To 37
                "male" To true
                "contact" To json {
                    "city" To "istanbul"
                    "email" To "xxx@yyy.com"
                }
            }
    println(jsonObject)
}

La sortie du code ci-dessus est:

{"contact":{"city":"istanbul","email":"xxx@yyy.com"},"name":"ilkin","age":37,"male":true}

Cela fonctionne comme prévu. Mais il crée une instance JsonObjectBuilder supplémentaire à chaque fois qu'il crée un objet json. Est-il possible d'écrire un DSL pour créer des objets json sans déchets supplémentaires?

20
ilkinulas 25 janv. 2017 à 23:52

4 réponses

Meilleure réponse

Vous pouvez utiliser un Deque comme pile pour suivre votre contexte JSONObject actuel avec un seul JsonObjectBuilder:

fun json(build: JsonObjectBuilder.() -> Unit): JSONObject {
    return JsonObjectBuilder().json(build)
}

class JsonObjectBuilder {
    private val deque: Deque<JSONObject> = ArrayDeque()

    fun json(build: JsonObjectBuilder.() -> Unit): JSONObject {
        deque.push(JSONObject())
        this.build()
        return deque.pop()
    }

    infix fun <T> String.To(value: T) {
        deque.peek().put(this, value)
    }
}

fun main(args: Array<String>) {
    val jsonObject =
            json {
                "name" To "ilkin"
                "age" To 37
                "male" To true
                "contact" To json {
                    "city" To "istanbul"
                    "email" To "xxx@yyy.com"
                }
            }
    println(jsonObject)
}

Exemple de sortie:

{"contact":{"city":"istanbul","email":"xxx@yyy.com"},"name":"ilkin","age":37,"male":true}

Appeler json et build sur plusieurs threads sur un seul JsonObjectBuilder serait problématique, mais cela ne devrait pas être un problème pour votre cas d'utilisation.

18
mfulton26 27 janv. 2017 à 14:31

Avez-vous besoin d'un DSL? Vous perdez la capacité d'appliquer les clés String, mais vanilla Kotlin n'est pas si mal :)

JSONObject(mapOf(
        "name" to "ilkin",
        "age" to 37,
        "male" to true,
        "contact" to mapOf(
                "city" to "istanbul",
                "email" to "xxx@yyy.com"
        )
))
14
James Bassett 26 janv. 2017 à 04:25

J'ai trouvé une autre solution. Vous pouvez simplement hériter de la classe JSONObject sans avoir à créer d'autres objets.

class Json() : JSONObject() {

    constructor(init: Json.() -> Unit) : this() {
        this.init()
    }

    infix fun <T> String.To(value: T) {
        put(this, value)
    }
}

fun main(args: Array<String>) {
    val jsonObject =
            Json {
                "name" To "ilkin"
                "age" To 37
                "male" To true
                "contact" To Json {
                    "city" To "istanbul"
                    "email" To "xxx@yyy.com"
                }
            }
    println(jsonObject)
}

La sortie du code sera la même.

{"contact":{"city":"istanbul","email":"xxx@yyy.com"},"name":"ilkin","age":37,"male":true}

UPD : si vous utilisez la bibliothèque gson, vous pouvez consulter cette bibliothèque géniale. Cela ne crée aucun déchet, le code source est facile à lire et à comprendre.

1
Alex Misiulia 21 mars 2018 à 09:12

Je ne sais pas si j'ai bien compris la question. Vous ne voulez pas de constructeur?

import org.json.JSONArray
import org.json.JSONObject

class Json() {

    private val json = JSONObject()

    constructor(init: Json.() -> Unit) : this() {
        this.init()
    }

    infix fun String.to(value: Json) {
        json.put(this, value.json)
    }

    infix fun <T> String.to(value: T) {
        json.put(this, value)
    }

    override fun toString(): String {
        return json.toString()
    }
}

fun main(args: Array<String>) {

    val json = Json {
        "name" to "Roy"
        "body" to Json {
            "height" to 173
            "weight" to 80
        }
        "cars" to JSONArray().apply {
            put("Tesla")
            put("Porsche")
            put("BMW")
            put("Ferrari")
        }
    }

    println(json)

}

Tu auras

{
  "name": "Roy",
  "body": {
    "weight": 80,
    "height": 173
  },
  "cars": [
    "Tesla",
    "Porsche",
    "BMW",
    "Ferrari"
  ]
}
5
Arst 15 août 2018 à 02:13