/AutoConverter

auto conversion between json and data class

Primary LanguageKotlin

License: MIT

AutoConverter

AutoConverter is a simple tool to convert data classes to JSONObject. It can be used in Android log entity conversion, or in any other use case where you need to convert a data class to a JSONObject.

I planned two versions, one is the ksp version, and the other is kcp and IDE plugin version.

  • serialization: toJSONObject
  • deserialization: fromJSONObject, it is defined as a extended function for KClass
  • nested classes
  • naming strategy for properties, e.g. camel to underline
  • code style config, e.g. indent
  • fields marked nullable
  • conversion config: JSONArray/List, JSONObject/Map
  • kcp and idea plugin version
  • publish to maven central

KSP

Usage

The AutoConvert definition

/**
 * Auto convert annotation

 * @property functions enabled auto convert functions, toJSONObject by default
 * @property namingStrategy naming strategy, None by default
 * @property filePostfix file postfix, Ext by default, filename is ClassName + filePostfix
 * @constructor Create empty Auto convert
 */
@MustBeDocumented
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.BINARY)
annotation class AutoConvert(
    val functions: Array<ACFunction> = [ACFunction.ToJSONObject],
    val namingStrategy: NamingStrategy = NamingStrategy.None,
    val filePostfix: String = "Ext"
)

Add AutoConvert to your classes

package com.mato.stg4cpp

import com.mato.stg4.annotation.ACFunction
import com.mato.stg4.annotation.AutoConvert
import com.mato.stg4cpp.pkg2.Location

@AutoConvert(functions = [ACFunction.FromJSONObject, ACFunction.ToJSONObject])
data class Restaurant(
    val score: Float,
    val comments: Int = 0,
    val location: Location? = null,
    val foods: List<String> = emptyList(),
)
// Location.kt, it's a nested class, too. And it has different package name with the outer.
package com.mato.stg4cpp.pkg2

import com.mato.stg4.annotation.ACFunction
import com.mato.stg4.annotation.AutoConvert

@AutoConvert(functions = [ACFunction.ToJSONObject, ACFunction.FromJSONObject])
data class Location(
    val longitude: Double = 0.0,
    val latitude: Double = 0.0,
    val address: String = ""
)

The generate files:

  • LocationExt.kt
// Read-only, generated by AutoConverter.
package com.mato.stg4cpp.pkg2

import kotlin.Result
import kotlin.reflect.KClass
import org.json.JSONObject

public fun Location.toJSONObject(): Result<JSONObject> = kotlin.runCatching {
    JSONObject().also {
        it.put("longitude", this.longitude)
        it.put("latitude", this.latitude)
        it.put("address", this.address)
    }
}

public fun KClass<Location>.fromJSONObject(payload: JSONObject): Result<Location> =
    kotlin.runCatching {
        Location(
            longitude = payload.get("longitude") as Double,
            latitude = payload.get("latitude") as Double,
            address = payload.get("address") as String
        )
    }
}
  • RestaurantExt.kt
// Read-only, generated by AutoConverter.
package com.mato.stg4cpp

import com.mato.stg4cpp.pkg2.Location
import com.mato.stg4cpp.pkg2.fromJSONObject
import com.mato.stg4cpp.pkg2.toJSONObject
import kotlin.Result
import kotlin.reflect.KClass
import org.json.JSONObject

public fun KClass<Restaurant>.fromJSONObject(payload: JSONObject): Result<Restaurant> =
    kotlin.runCatching {
        Restaurant(
            score = payload.get("score") as Float,
            comments = payload.get("comments") as Int,
            location = payload.optJSONObject("location")?.let {
                Location::class.fromJSONObject(it).getOrThrow() },
            foods=payload.get("foods") as List<String>
        )
    }

public fun Restaurant.toJSONObject(): Result<JSONObject> = kotlin.runCatching {
    JSONObject().also {
        it.put("score", this.score)
        it.put("comments", this.comments)
        it.put("location", this.location?.toJSONObject()?.getOrThrow())
        it.put("foods", this.foods)
    }
}

[WIP] KCP