首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Kotlin + Arrow + Gson =无?

Kotlin + Arrow + Gson =无?
EN

Stack Overflow用户
提问于 2018-11-02 18:48:28
回答 1查看 645关注 0票数 0

我在Kotlin有一个由图书和借款者组成的简单图书馆的模型,其中一本书如果有借款者,就会被检出。我使用Arrow选项对借款人的缺席/在场进行编码:

代码语言:javascript
复制
data class Borrower(val name: Name, val maxBooks: MaxBooks)
data class Book(val title: String, val author: String, val borrower: Option<Borrower> = None)

在Gson中,我在将这些对象序列化/反序列化到JSON /从JSON到JSON时遇到了困难--特别是在图书中将Option<Borrower>表示为JSON null

代码语言:javascript
复制
[
  {
    "title": "Book100",
    "author": "Author100",
    "borrower": {
      "name": "Borrower100",
      "maxBooks": 100
    }
  },
  {
    "title": "Book200",
    "author": "Author200",
    "borrower": null
  }
]

我的反序列化代码:

代码语言:javascript
复制
fun jsonStringToBooks(jsonString: String): List<Book> {
    val gson = Gson()
    return try {
        gson.fromJson(jsonString, object : TypeToken<List<Book>>() {}.type)
    } catch (e: Exception) {
        emptyList()
    }
}

我得到了一个空名单。几乎相同的jsonStringToBorrowers工作得很好。

有人能给我指明正确的方向吗?

使用像kotlinx.serializationKlaxon这样的不同的JSON库是一个更好的主意吗?他们是如何做null <-> None的呢?

谢谢!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-11-03 13:50:48

在返回空列表之前不记录异常,这一事实掩盖了这个问题。如果您记录了该异常,您就会得到以下信息:

java.lang.RuntimeException:未能调用没有arg的私有arrow.core.Option()

这意味着Gson不知道如何创建Option类,因为它没有公共的空构造函数。实际上,Option是一个密封类(因此抽象),包含两个具体的子类:SomeNone。为了获得Option的实例,您应该使用工厂方法之一,比如Option.just(xxx)Option.empty()等。

现在,为了修复您的代码,您需要告诉Gson如何反序列化Option类。为此,您需要为gson对象注册一个类型适配器。

可能的实施办法如下:

代码语言:javascript
复制
class OptionTypeAdapter<E>(private val adapter: TypeAdapter<E>) : TypeAdapter<Option<E>>() {

    @Throws(IOException::class)
    override fun write(out: JsonWriter, value: Option<E>) {
        when (value) {
            is Some -> adapter.write(out, value.t)
            is None -> out.nullValue()
        }
    }

    @Throws(IOException::class)
    override fun read(input: JsonReader): Option<E> {
        val peek = input.peek()
        return if (peek != JsonToken.NULL) {
            Option.just(adapter.read(input))
        } else {
            input.nextNull()
            Option.empty()
        }
    }

    companion object {

        fun getFactory() = object : TypeAdapterFactory {
            override fun <T> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
                val rawType = type.rawType as Class<*>
                if (rawType != Option::class.java) {
                    return null
                }
                val parameterizedType = type.type as ParameterizedType
                val actualType = parameterizedType.actualTypeArguments[0]
                val adapter = gson.getAdapter(TypeToken.get(actualType))
                return OptionTypeAdapter(adapter) as TypeAdapter<T>
            }
        }
    }

}

您可以通过以下方式使用它:

代码语言:javascript
复制
fun main(args: Array<String>) {
    val gson = GsonBuilder()
        .registerTypeAdapterFactory(OptionTypeAdapter.getFactory())
        .create()
    val result: List<Book> = try {
        gson.fromJson(json, TypeToken.getParameterized(List::class.java, Book::class.java).type)
    } catch (e: Exception) {
        e.printStackTrace()
        emptyList()
    }

    println(result)
}

该守则的产出如下:

代码语言:javascript
复制
[Book(title=Book100, author=Author100, borrower=Some(Borrower(name=Borrower100, maxBooks=100))), Book(title=Book200, author=Author200, borrower=None)]
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53124280

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档