Лучше ли использовать сериализацию и сторонние библиотеки или анализировать JSON вручную в Kotlin / Java? - PullRequest
0 голосов
/ 19 апреля 2020

Kotlin команда создает собственный синтаксический анализатор JSON, а пример использования выглядит следующим образом:

@Serializable
data class Data(val a: Int, val b: String = "42")

fun main() {
    // Json also has .Default configuration which provides more reasonable settings,
    // but is subject to change in future versions
    val json = Json(JsonConfiguration.Stable)
    // serializing objects
    val jsonData = json.stringify(Data.serializer(), Data(42))
    // serializing lists
    val jsonList = json.stringify(Data.serializer().list, listOf(Data(42)))
    println(jsonData) // {"a": 42, "b": "42"}
    println(jsonList) // [{"a": 42, "b": "42"}]

    // parsing data back
    val obj = json.parse(Data.serializer(), """{"a":42}""") // b is optional since it has default value
    println(obj) // Data(a=42, b="42")
}

Но он не может анализировать JSON массивы (также я не делал не могу найти, может ли моши ). Итак, почему сторонние библиотеки для разбора JSON должны быть предпочтительнее? Или, может быть, лучше разобрать JSON вручную?

Я нашел этот код в репозитории googlemaps , который обеспечивает анализ JSON объекта без сторонних библиотек. Он анализирует JSON координаты и кажется вполне работоспособным. Пример ввода JSON (взятый из ресурсов) и кода ниже:

[{"lat" : 51.5145160, "lng" : -0.1270060 },
{ "lat" : 51.5064490, "lng" : -0.1244260, "title" : "Corinthia Hotel London", "snippet": "Whitehall Pl"},
{ "lat" : 51.5097080, "lng" : -0.1200450, "title" : "Savoy Place", "snippet" : "Covent Garden"},
{ "lat" : 51.5090680, "lng" : -0.1421420, "title" : "Albemarle St", "snippet": "Mayfair"},
{ "lat" : 51.4976080, "lng" : -0.1456320, "title" : " Victoria Square", "snippet": " Belgravia" },
{ "lat" : 51.5046150, "lng" : -0.1473780}]

 /**
 * Returns a list of cluster items read from the provided [inputStream]
 */
@Throws(JSONException::class)
fun read(inputStream: InputStream): List<MyItem> {
    // This matches only once in whole input so Scanner.next returns whole InputStream as a
    // String. http://stackoverflow.com/a/5445161/2183804
    val REGEX_INPUT_BOUNDARY_BEGINNING = "\\A"

    val items = mutableListOf<MyItem>()
    val json = Scanner(inputStream)
        .useDelimiter(REGEX_INPUT_BOUNDARY_BEGINNING).next()
    val array = JSONArray(json)
    for (i in 0 until array.length()) {
        var title: String? = null
        var snippet: String? = null
        val `object` = array.getJSONObject(i)
        val lat = `object`.getDouble("lat")
        val lng = `object`.getDouble("lng")
        if (!`object`.isNull("title")) {
            title = `object`.getString("title")
        }
        if (!`object`.isNull("snippet")) {
            snippet = `object`.getString("snippet")
        }
        items.add(MyItem(LatLng(lat, lng), title, snippet))
    }
    return items
}

И последний элемент:

data class MyItem(val latLng: LatLng, val myTitle: String?, val mySnippet: String?) : ClusterItem

Итак, комбинируя оба метода, я получил что-то вроде более короткая версия (мне также нужно добавить модификаторы в класс данных). Но стоит ли использовать его, если ручной синтаксический анализ выглядит достаточно хорошо?

fun read(inputStream: InputStream): List<ClusterMarker> {
    val items = mutableListOf<ClusterMarker>()
    val json = Json(JsonConfiguration.Stable)
    val jsonString = inputStreamToString(inputStream)
    val array = JSONArray(jsonString)
    for (i in 0 until array.length()) {
        val jObject = array.getJSONObject(i)
        items.add(json.parse(ClusterMarker.serializer(), jObject.toString()))
    }
    return items
}

PS Может быть, будет сложно проанализировать сложные JSON-файлы с большим количеством внутренних объектов / массивов. Но, тем не менее, они должны обрабатываться тщательно даже в сторонних библиотеках.

...