在开发中经常遇到需要将云接口查询回来的JSON数据转换到实体类中使用,以前经常一个个实体类手写转换,太糙了,后来写了个java的工具类,现在开始学习Kotlin语言,所以重新写一个Kotlin的版本,了解下kotlin下使用反射和注解有什么不同。
实现一个JSON数据转实体类的工具库,满足以下条件:
1、能够标注JSON中的字段名,实现实体类中对应接受数据的变量名不一定与JSON字段名相同;
2、能够忽略实体类中的某些变量,不进行转换;
3、能够满足JSONObject中的JSONArray转换到List的要求。
首先定义一个注解
/**
* 变量注解
*
* @author D10NG
* @date on 2019-10-23 15:29
*/
@kotlin.annotation.Target(AnnotationTarget.FIELD)
@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
annotation class DLField (
// 在JSON中的名字
val nameInJson: String = ""
)
/**
* 类型识别工具
*
* @author D10NG
* @date on 2019-10-23 16:33
*/
object TypeMatch {
fun isString(clz: Class<*>) : Boolean {
return clz == String::class.java
}
fun isBoolean(clz: Class<*>) : Boolean {
return clz == Boolean::class.java
}
fun isInt(clz: Class<*>) : Boolean {
return clz == Int::class.java ||
clz == Integer::class.java ||
clz == Byte::class.java ||
clz == Short::class.java
}
fun isLong(clz: Class<*>) : Boolean {
return clz == Long::class.java
}
fun isDouble(clz: Class<*>) : Boolean {
return clz == Double::class.java ||
clz == Float::class.java
}
fun isList(clz: Class<*>) : Boolean {
return clz == List::class.java
}
fun isBaseJsonEntity(clz: Class<*>) : Boolean {
val sc = clz.superclass ?: return false
return sc == BaseJsonEntity::class.java
}
}
最重要的代码来了
/**
* 基础类
*
* @author D10NG
* @date on 2019-10-23 15:25
*/
open class BaseJsonEntity : Serializable {
/**
* 从JSON中读取数据
* @param json
* @param excludeNames 排除的变量
*/
open fun setFromJson(json: JSONObject, vararg excludeNames: String) {
val nameList = excludeNames.asList()
// 获取所有字段,包含父类的
val fs: MutableList<Field> = mutableListOf()
var tempClass: Class<in Any>? = this.javaClass
while (tempClass != null) {
fs.addAll(tempClass.declaredFields)
tempClass = tempClass.superclass
}
for (f in fs) {
// 排除不符合的变量
val annotation = f.getAnnotation(DLField::class.java) ?: continue
if (nameList.contains(f.name)) continue
val modifier = Modifier.toString(f.modifiers)
if (modifier.contains("static") || modifier.contains("final")) continue
// 提取json中的字段名
var name = annotation.nameInJson
if (name.isEmpty()) {
name = f.name
}
// 将private变量改成外部类可读
f.isAccessible = true
// 判断变量类型
when {
TypeMatch.isString(f.type) -> f.set(this, json.optString(name))
TypeMatch.isInt(f.type) -> f.setInt(this, json.optInt(name))
TypeMatch.isLong(f.type) -> f.setLong(this, json.optLong(name))
TypeMatch.isDouble(f.type) -> f.setDouble(this, json.optDouble(name))
TypeMatch.isBoolean(f.type) -> f.setBoolean(this, json.optBoolean(name))
TypeMatch.isList(f.type) -> {
// List 类型,去获取其中的泛型
val paramType = f.genericType as ParameterizedType
// 得到泛型里的class类型对象
val typeClz = paramType.actualTypeArguments[0] as Class<*>
f.set(this, getListFromJsonArray(typeClz, json.getJSONArray(name)))
}
TypeMatch.isBaseJsonEntity(f.type) -> {
// 同样继承了当前类的变量
val obj = f.type.newInstance()
val method = f.type.getMethod("setFromJson",
JSONObject::class.java, Array<String>::class.java)
val array = emptyArray<String>()
method.invoke(obj, json.optJSONObject(name), array)
f.set(this, obj)
}
else -> f.set(this, json.opt(name))
}
}
}
// 获取array数据
private fun getListFromJsonArray(clz: Class<*>, array: JSONArray) : List<Any> {
val list: MutableList<Any> = arrayListOf()
for (i in 0 until array.length()) {
when {
TypeMatch.isString(clz) -> list.add(array.optString(i))
TypeMatch.isInt(clz) -> list.add(array.optInt(i))
TypeMatch.isLong(clz) -> list.add(array.optLong(i))
TypeMatch.isDouble(clz) -> list.add(array.optDouble(i))
TypeMatch.isBoolean(clz) -> list.add(array.optBoolean(i))
TypeMatch.isBaseJsonEntity(clz) -> {
// 同样继承了当前类的变量
val obj = clz.newInstance()
val method = clz.getMethod("setFromJson",
JSONObject::class.java, Array<String>::class.java)
val temp = emptyArray<String>()
method.invoke(obj, array.optJSONObject(i), temp)
list.add(obj)
}
}
}
return list
}
/**
* 转换为JSON
* @param excludeNames 排除的变量
*/
open fun toJson(vararg excludeNames: String) : JSONObject {
val json = JSONObject()
val nameList = excludeNames.asList()
// 获取所有字段,包含父类的
val fs: MutableList<Field> = mutableListOf()
var tempClass: Class<in Any>? = this.javaClass
while (tempClass != null) {
fs.addAll(tempClass.declaredFields)
tempClass = tempClass.superclass
}
for (f in fs) {
// 排除不符合的变量
val annotation = f.getAnnotation(DLField::class.java) ?: continue
if (nameList.contains(f.name)) continue
val modifier = Modifier.toString(f.modifiers)
if (modifier.contains("static") || modifier.contains("final")) continue
// 提取json中的字段名
var name = annotation.nameInJson
if (name.isEmpty()) {
name = f.name
}
// 将private变量改成外部类可读
f.isAccessible = true
// 判断变量类型
when {
TypeMatch.isList(f.type) -> {
// List 类型,去获取其中的泛型
val paramType = f.genericType as ParameterizedType
// 得到泛型里的class类型对象
val typeClz = paramType.actualTypeArguments[0] as Class<*>
var value = f.get(this) as List<Any>?
if (value == null) value = emptyList()
json.put(name, toJsonArray(typeClz, value))
}
TypeMatch.isBaseJsonEntity(f.type) -> {
// 同样继承了当前类的变量
val instance = f.get(this)
val method = f.type.getMethod("toJson", Array<String>::class.java)
val temp: JSONObject = method.invoke(instance, emptyArray<String>()) as JSONObject
json.put(name, temp)
}
else -> json.put(name, f.get(this))
}
}
return json
}
// list转换为JSONArray
private fun toJsonArray(clz: Class<*>, value: List<Any>): JSONArray {
val array = JSONArray()
for (i in value.indices) {
if (TypeMatch.isBaseJsonEntity(clz)) {
// 同样继承了当前类的变量
val method = clz.getMethod("toJson", Array<String>::class.java)
val temp: JSONObject = method.invoke(value[i], emptyArray<String>()) as JSONObject
array.put(temp)
} else {
array.put(value[i])
}
}
return array
}
}
你可以直接复制上面的代码进你的工程使用,也可以添加依赖库的形式
1、在根目录的build.gradle
里插入
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
2、在app的build.gradle
里插入
dependencies {
implementation 'com.github.D10NGYANG:JsonEntityManager:1.1'
}
可以使用插件快速创建,详情查看:
Android KotlinJSON快速生成实体类插件使用
但是生成实体类的并非可以直接使用,需要根据情况修改
测试实体类
data class TestInfo (
// 使用nameInJson标注在JSON中对应的字段
@DLField(nameInJson = "int1")
var intT: Int = 0,
@DLField
var stringT: String = "",
// 这是一个普通Array,用于读取JSON中的JSONArray
@DLField
var listT: List<String> = emptyList(),
// 这是另一个继承了BaseJsonEntity()的变量
@DLField
var test2: Test2Info = Test2Info(),
// 这是继承了BaseJsonEntity()的变量列表
@DLField
var testList: List<Test2Info> = emptyList()
) : BaseJsonEntity()
另一个
data class Test2Info (
@DLField
var para1: String = "0",
@DLField
var para2: Int = 2,
@DLField
var para3: Boolean = false
) : BaseJsonEntity()
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// {"int1":3,"listT":["1a","2b","3c"],"stringT":"abcd","test2":{"para1":"efgh","para2":1234,"para3":true},"testList":[{"para1":"L0","para2":0,"para3":false},{"para1":"L1","para2":1,"para3":true}]}
val str = "{\"int1\":3,\"listT\":[\"1a\",\"2b\",\"3c\"],\"stringT\":\"abcd\",\"test2\":{\"para1\":\"efgh\",\"para2\":1234,\"para3\":true},\"testList\":[{\"para1\":\"L0\",\"para2\":0,\"para3\":false},{\"para1\":\"L1\",\"para2\":1,\"para3\":true}]}"
val json = JSONObject(str)
val test = TestInfo()
test.setFromJson(json)
Log.e("测试", "json=${test.toJson()}")
}
}
# 实体转换工具
-keep class com.dlong.jsonentitylib.** {*;}
-dontwarn com.dlong.jsonentitylib.**
https://github.com/D10NGYANG/JsonEntityManager