使用Google HTTP Client反序列化Kotlin数据类

时间:2018-03-28 16:26:01

标签: kotlin gson

我正在使用Google HTTP客户端发出API请求,我希望使用parseAs()方法为我反序列化JSON响应。我的模型是Kotlin数据类,但反序列化器无法实例化我的类:

Caused by: java.lang.IllegalArgumentException: unable to create new instance of class com.ippontech.blog.stats.model.GitFile because it has no accessible default constructor

这是我的Kotlin数据类:

data class GitFile(
        val name: String,
        @SerializedName("download_url") val downloadUrl: String)

我使用的代码:

val requestFactory = NetHttpTransport().createRequestFactory{
    it.setParser(JsonObjectParser(GsonFactory()))
}

val request = requestFactory.buildGetRequest(
        GenericUrl("https://api.github.com/repos/ippontech/blog-usa/contents/posts"))
val type = object : TypeToken<List<GitFile>>() {}.type
val rawResponse = request.execute().parseAs(type)

另一方面,如果我将响应作为字符串检索,然后使用Gson解析器,它可以正常工作:

val requestFactory = NetHttpTransport().createRequestFactory()
val request = requestFactory.buildGetRequest(
        GenericUrl("https://api.github.com/repos/ippontech/blog-usa/contents/posts"))
val rawResponse = request.execute().parseAsString()
val type = object : TypeToken<List<GitFile>>() {}.type
val gitFiles: List<GitFile> = Gson().fromJson(rawResponse, type)

这似乎表明JsonObjectParser在这里并没有完全发挥作用。

我正在使用的版本:

compile 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.2.30'
compile 'com.google.code.gson:gson:2.8.0'
compile 'com.google.apis:google-api-services-sheets:v4-rev512-1.23.0'
compile 'com.google.api-client:google-api-client-gson:1.23.0'

有关如何解决这个问题的想法吗?

1 个答案:

答案 0 :(得分:0)

这是因为基础JsonObjectParser方法在{/ p>中使用newInstance

public static <T> T newInstance(Class<T> clazz) {
    try {
        return clazz.newInstance();
    } catch (IllegalAccessException var2) {
        throw handleExceptionForNewInstance(var2, clazz);
    } catch (InstantiationException var3) {
        throw handleExceptionForNewInstance(var3, clazz);
    }
}

虽然你的GitFile只有一个非默认构造函数(no-args),但它清楚地告诉你。

从一个角度来看,您可以添加如下默认值:

data class GitFile(
        val name: String,
        @SerializedName("download_url") val downloadUrl: String
) {
    constructor() : this(name = "", downloadUrl = "")
}

这不会失败,但似乎工作错误:解析的对象属性对我来说都是null(我在配置JsonObjectParser实例时不知道我缺少什么)。

Gson不需要默认构造函数,可以无缝工作。 但它似乎需要一个自定义ObjectParser实现,我相信,它的工作速度会更快:

class GsonObjectParser(private val gson: Gson) : ObjectParser {

    override fun <T : Any?> parseAndClose(inputStream: InputStream?, charset: Charset?, clazz: Class<T>?): T {
        return doParseAndClose(InputStreamReader(inputStream, charset), clazz);
    }

    override fun parseAndClose(inputStream: InputStream?, charset: Charset?, type: Type?): Any {
        return doParseAndClose(InputStreamReader(inputStream, charset), type);
    }

    override fun <T : Any?> parseAndClose(reader: Reader?, clazz: Class<T>?): T {
        return doParseAndClose(reader, clazz);
    }

    override fun parseAndClose(reader: Reader?, type: Type?): Any {
        return doParseAndClose(reader, type);
    }

    private fun <T : Any?> doParseAndClose(reader: Reader?, type: Type?): T {
        JsonReader(reader).use {
            return gson.fromJson(reader, type);
        };
    }

}
data class GitFile(
    val name: String?,
    val downloadUrl: String?
)

fun main(args: Array<String>) {

    val gson = GsonBuilder()
            .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
            .create();
    val requestFactory = NetHttpTransport().createRequestFactory {
        it.setParser(GsonObjectParser(gson))
    }
    val request = requestFactory.buildGetRequest(GenericUrl("https://api.github.com/repos/ippontech/blog-usa/contents/posts"))
    val type = object : TypeToken<List<GitFile>>() {}.type
    val gitFiles = request.execute().parseAs(type) as List<GitFile>
    gitFiles
            .stream()
            .map { gitFile -> gitFile.name + ": " + gitFile.downloadUrl }
            .forEach { gitFile -> System.out.println(gitFile) }
}

截至今天的输出的第一行:

10-tips-and-tricks-for-cassandra.md: https://raw.githubusercontent.com/ippontech/blog-usa/master/posts/10-tips-and-tricks-for-cassandra.md
5-laws-every-developer-should-know.md: https://raw.githubusercontent.com/ippontech/blog-usa/master/posts/5-laws-every-developer-should-know.md
a-journey-into-blockchain-private-network-with-ethereum.md: https://raw.githubusercontent.com/ippontech/blog-usa/master/posts/a-journey-into-blockchain-private-network-with-ethereum.md