Advertisement
Zgragselus

Codable - kotlin JSON

Nov 1st, 2022
1,740
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Kotlin 8.51 KB | None | 0 0
  1. package cz.otte.rum.json
  2.  
  3. import android.util.Log
  4. import org.json.JSONArray
  5. import kotlin.reflect.KMutableProperty
  6. import kotlin.reflect.full.declaredMemberProperties
  7. import org.json.JSONException
  8. import org.json.JSONObject
  9. import org.json.JSONTokener
  10. import kotlin.reflect.KClass
  11. import kotlin.reflect.KProperty1
  12. import kotlin.reflect.KType
  13. import kotlin.reflect.full.createInstance
  14. import kotlin.reflect.full.createType
  15. import kotlin.reflect.full.memberProperties
  16.  
  17. annotation class JsonName(val name: String)
  18.  
  19. annotation class JsonExclude()
  20.  
  21. open class Codable {
  22.     @Suppress("UNCHECKED_CAST")
  23.     fun<R> readInstanceProperty(instance: Any, propertyName: String): R {
  24.         val property = instance::class.members
  25.             .first { it.name == propertyName } as KProperty1<Any, *>
  26.  
  27.         return property.get(instance) as R
  28.     }
  29.  
  30.     fun toJsonObject(): JSONObject {
  31.         var result: JSONObject = JSONObject()
  32.  
  33.         for (property in this::class.declaredMemberProperties) {
  34.             var name = property.name
  35.             var annotation = property.annotations.find { it is JsonName } as? JsonName
  36.             if (annotation != null) {
  37.                 name = annotation.name
  38.             }
  39.  
  40.             var exclude = property.annotations.find { it is JsonExclude } as? JsonExclude
  41.             if (exclude != null) {
  42.                 continue
  43.             }
  44.  
  45.             Log.d("RUM", "Property - name ${property.returnType}")
  46.  
  47.             if (property.returnType == kotlin.String::class.createType()) {
  48.                 Log.d("RUM", "Setting - $name")
  49.                 result.put(name, readInstanceProperty<String>(this, property.name))
  50.             } else if (property.returnType == kotlin.Boolean::class.createType()) {
  51.                 result.put(name, readInstanceProperty<Boolean>(this, property.name))
  52.             } else if (property.returnType == kotlin.Double::class.createType()) {
  53.                 result.put(name, readInstanceProperty<Double>(this, property.name))
  54.             } else if (property.returnType == kotlin.Int::class.createType()) {
  55.                 result.put(name, readInstanceProperty<Int>(this, property.name))
  56.             } else if (property.returnType.toString().contains("ArrayList")) {
  57.                 // Handle arrays
  58.                 var elemType = property.returnType.arguments[0].type
  59.  
  60.                 var array: ArrayList<Any> = readInstanceProperty<ArrayList<Any>>(this, property.name)
  61.                 var jsonArray: JSONArray = JSONArray()
  62.  
  63.                 for (i in 0..(array.count()-1)) {
  64.                     Log.d("RUM", "Element - $i - Value - ${array[i]}")
  65.                     jsonArray.put(i, array[i])
  66.                 }
  67.  
  68.                 result.put(name, jsonArray)
  69.             } else {
  70.                 // Handle generic object
  71.                 //var jsonObject: JSONObject = JSONObject()
  72.  
  73.                 try {
  74.                     var codable: Codable = (readInstanceProperty(this, property.name) as Codable)
  75.                     if (codable != null) {
  76.                         result.put(name, codable.toJsonObject())
  77.                     }
  78.                 } catch (ex: ClassCastException) {
  79.                     Log.d("RUM", "Exception - class cast mismatch - '" + ex.toString() + "'")
  80.                 }
  81.             }
  82.         }
  83.  
  84.         return result
  85.     }
  86.  
  87.     fun<R> writeInstanceProperty(instance: Any, propertyName: Any, propertyValue: R) {
  88.         val property = instance::class.memberProperties
  89.             .first { it.name == propertyName }
  90.  
  91.         if (property is KMutableProperty<*>) {
  92.             property.setter.call(instance, propertyValue)
  93.         }
  94.     }
  95.  
  96.     fun fromJsonObjectArrayHelper(json: JSONObject, instance: Any) {
  97.         var it : Iterator<String> = json.keys()
  98.         while (it.hasNext()) {
  99.             var key: String = it.next()
  100.             var value = json.get(key)
  101.             if (value.toString() == "null") {
  102.                 continue
  103.             }
  104.             var type: KType = json.get(key)::class.createType()
  105.             Log.d("RUM", "Array Element Property - ${key} ${type} = ${value}")
  106.  
  107.             for (property in instance::class.declaredMemberProperties) {
  108.                 var name = property.name
  109.  
  110.                 var annotation = property.annotations.find { it is JsonName } as? JsonName
  111.                 if (annotation != null) {
  112.                     name = annotation.name
  113.                 }
  114.  
  115.                 var exclude = property.annotations.find { it is JsonExclude } as? JsonExclude
  116.                 if (exclude != null) {
  117.                     continue
  118.                 }
  119.  
  120.                 if (name == key) {
  121.                     if (property.returnType == type) {
  122.                         this.writeInstanceProperty(instance, property.name, value)
  123.                         Log.d("RUM", "Array Element Writing - ${key}")
  124.                     } else {
  125.                         Log.d("RUM", "Array Element Type mismatch - ${key} has type of ${type}, tries to match to ${property.returnType} - array ${property.returnType.javaClass.isArray()}")
  126.                     }
  127.                 }
  128.             }
  129.         }
  130.     }
  131.  
  132.     fun fromJsonObject(json: JSONObject) {
  133.         var it : Iterator<String> = json.keys()
  134.         while (it.hasNext()) {
  135.             var key: String = it.next()
  136.             var value = json.get(key)
  137.             if (value.toString() == "null") {
  138.                 continue
  139.             }
  140.             var type: KType = json.get(key)::class.createType()
  141.             Log.d("RUM", "Property - ${key} ${type} = ${value}")
  142.  
  143.             for (property in this::class.declaredMemberProperties) {
  144.                 var name = property.name
  145.  
  146.                 var annotation = property.annotations.find { it is JsonName } as? JsonName
  147.                 if (annotation != null) {
  148.                     name = annotation.name
  149.                 }
  150.  
  151.                 var exclude = property.annotations.find { it is JsonExclude } as? JsonExclude
  152.                 if (exclude != null) {
  153.                     continue
  154.                 }
  155.  
  156.                 if (name == key) {
  157.                     if (property.returnType == type) {
  158.                         this.writeInstanceProperty(this, property.name, value)
  159.                         Log.d("RUM", "Writing - ${key}")
  160.                     } else if (type.toString() == "org.json.JSONObject") {
  161.                         // Attempt to match JSON object
  162.                         var instance = (property.returnType.classifier!! as KClass<*>).createInstance()
  163.                         fromJsonObjectArrayHelper(value as JSONObject, instance)
  164.                         this.writeInstanceProperty(this, property.name, instance)
  165.                     } else if (type.toString() == "org.json.JSONArray" && property.returnType.toString().contains("ArrayList")) {
  166.                         // Handle arrays
  167.                         var arrayValue = value as JSONArray
  168.                         Log.d("RUM", "JSON Array of size ${arrayValue.length()}")
  169.  
  170.                         var elemType = property.returnType.arguments[0].type
  171.  
  172.                         Log.d("RUM", "No. of template arguments in typ - ${property.returnType.arguments.count()}")
  173.                         Log.d("RUM", "Template argument type - ${property.returnType.arguments[0].type}")
  174.  
  175.                         if (elemType != null) {
  176.                             for (i in 0..(arrayValue.length() - 1)) {
  177.                                 Log.d("RUM", "JSONArray element ${i} with type ${elemType}")
  178.  
  179.                                 var arrayItem = arrayValue.getJSONObject(i)
  180.                                 var instance = (elemType.classifier!! as KClass<*>).createInstance()
  181.                                 fromJsonObjectArrayHelper(arrayItem, instance)
  182.  
  183.                                 var propertyInstance = this::class.memberProperties.first { it.name == property.name }
  184.                                 (propertyInstance.getter.call(this) as ArrayList<Any?>).add(instance)
  185.                             }
  186.                         }
  187.                     } else {
  188.                         Log.d("RUM", "Type mismatch - ${key} has type of ${type}, tries to match to ${property.returnType} - array ${property.returnType.javaClass.isArray()}")
  189.                     }
  190.                 }
  191.             }
  192.         }
  193.     }
  194.  
  195.     fun decode(str: String) {
  196.         var json = JSONTokener(str).nextValue() as JSONObject
  197.         this.fromJsonObject(json)
  198.     }
  199.  
  200.     fun encode(): String {
  201.         var result : JSONObject = this.toJsonObject()
  202.         return result.toString()
  203.     }
  204. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement