Jackson解析数据为空时字段类型产生变化的JSON字段

对于PHP、Python这类动态语言编写的API接口,其返回的JSON经常有这种情况:

1、字段有数据时:

{
    "name":"Test",
    "tags":{
        "caches":"caches",
        "caching":"caching",
        "feeds":"feeds",
        "late-caching":"late caching",
        "speed":"speed"
    }
}

2、字段无数据时:

{
"name":"Test",
"tags":[]
}

可以发现,tags字段有数据时其类型是个集合,而当tags字段无数据时其类型则是个数组……

这就导致无法准确的编写用于映射数据的实体类。

为了应对这种情况,可以在注入Bean时为Jackson配置选项将为空的字符串、数组都映射为空对象(NULL)。

代码:

mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
mapper.enable(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT);

Kotlin使用Java反射Api操作KClass时遇到的变量作用域问题记录

Kotlin本身带的反射Api依据官方文档来看貌似是残缺的,想实现完整的反射支持只能调用Java的反射Api,类似下面这样:

val test = Test::class.java

这样就可以通过test对象调用Java的反射Api了,这样在操作Java Class的时候是没问题的,但是操作Kotlin的KClass就会出现变量作用域的问题……

问题的根源在于Kotlin代码在翻译成Java代码后无论你先前声明的成员变量的作用域是公有还是私有,都会被翻译成私有,并辅以一堆Get、Set方法用来操作该变量。这似乎是挺符合Java世界的标准的,在Kotlin下访问一个变量会自动调用其Get、Set方法。但在反射的这个应用场景下就会出问题。看一下下面这个语句:

test.getFields().forEach {
    println(it.name)
}

上面这段代码会输出什么?

什么也没有……

包括你使用test.getField("testVar")时也会给你抛出一个找不到成员变量的异常。这就是问题表现。你不再能像之前习惯的那样直接操作字段了……

这个问题除了老老实实调用对应的Get、Set方法操作外还可以通过将成员变量声明为JvmField的形式防止其被翻译成私有:

class Test {
    @JvmField
    val testVar: String? = null 
}

不过我更建议还是老老实实麻烦一点调用Get、Set方法操作……因为直接操作变量的话将来一旦类的内部对变量的读写进行了一些预处理操作,直接通过访问变量字段的方式操作变量就无法触发这些操作,代码维护起来会很麻烦。