调用Google Books API时Gson报Expected BEGIN_ARRAY but was BEGIN_OBJECT异常
问题描述
在Jetpack Compose项目中使用Retrofit搭配Gson调用Google Books API(接口地址:https://www.googleapis.com/books/v1/volumes?q=jazz+history)时,抛出异常:
java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
项目app模块build.gradle.kts依赖配置:
// Retrofit implementation("com.squareup.retrofit2:retrofit:2.9.0") implementation("com.squareup.retrofit2:converter-gson:2.9.0")
该API返回的JSON结构为包含kind、totalItems、items数组的对象,items中是具体书籍条目。项目相关代码如下:
AppContainer.kt
package com.example.bookshelf.data import com.example.bookshelf.network.BookshelfApiService import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory interface AppContainer { val bookshelfRepository: BookshelfRepository } class DefaultAppContainer : AppContainer { private val baseUrl = "https://www.googleapis.com/books/v1/volumes/" private val retrofit = Retrofit.Builder() .addConverterFactory(GsonConverterFactory.create()) .baseUrl(baseUrl) .build() private val retrofitService: BookshelfApiService by lazy { retrofit.create(BookshelfApiService::class.java) } override val bookshelfRepository: BookshelfRepository by lazy { NetworkBookshelfRepository(retrofitService) } }
BookshelfApiService.kt
package com.example.bookshelf.network import retrofit2.http.GET import retrofit2.http.Path interface BookshelfApiService { @GET("?q=jazz+history") suspend fun getBooks(): List<BookshelfBook> @GET("{volume_id}") suspend fun getVolume(@Path("id") id: String): BookshelfVolume }
BookshelfBook.kt
package com.example.bookshelf.network import kotlinx.serialization.Serializable @Serializable data class BookshelfBook( val id: String )
BookshelfVolume.kt
package com.example.bookshelf.network import kotlinx.serialization.Serializable @Serializable data class BookshelfVolume( val imageLinks: Map<String, String> )
已用Python3成功解析该JSON,但Android Studio中使用Gson时出现上述错误,请求解决。
解决方案
问题根源
异常核心原因是:Gson期望解析一个数组(BEGIN_ARRAY),但实际收到的是一个JSON对象(BEGIN_OBJECT)。你在BookshelfApiService中定义getBooks()返回List<BookshelfBook>,但Google Books API返回的最外层是包含items数组的对象,而非直接的数组。
另外还有两个次要问题:
- 数据类使用了
kotlinx.serialization.Serializable注解,但你用的是Gson转换器,该注解对Gson无效,Gson无需额外注解(除非需要@SerializedName映射字段名)。 getVolume()方法的@Path参数名不匹配:@Path("id")应对应@GET("{volume_id}")中的volume_id,需改为@Path("volume_id")。
修复步骤
- 创建顶层响应数据类
新增对应API返回结构的数据类,包裹整个响应:
package com.example.bookshelf.network data class BookshelfResponse( val kind: String, val totalItems: Int, val items: List<BookshelfBook> )
- 修改API接口定义
更新getBooks()的返回类型为BookshelfResponse,同时修正getVolume()的@Path参数:
interface BookshelfApiService { @GET("?q=jazz+history") suspend fun getBooks(): BookshelfResponse @GET("{volume_id}") suspend fun getVolume(@Path("volume_id") id: String): BookshelfVolume }
- 移除无效注解
删除BookshelfBook和BookshelfVolume上的@Serializable注解(若后续不使用Kotlin Serialization):
// BookshelfBook.kt package com.example.bookshelf.network data class BookshelfBook( val id: String )
// BookshelfVolume.kt package com.example.bookshelf.network data class BookshelfVolume( val imageLinks: Map<String, String> )
- 在Repository中提取目标数组
调用API时,从BookshelfResponse中取出items列表:
class NetworkBookshelfRepository( private val apiService: BookshelfApiService ) : BookshelfRepository { override suspend fun getBooks(): List<BookshelfBook> { return apiService.getBooks().items } }
验证
修改后重新运行,Gson会先解析顶层的BookshelfResponse对象,再从中提取items数组,完全匹配数据类结构,异常即可消除。
内容的提问来源于stack exchange,提问作者Alexandru Gheorghe
相关产品推荐
相关产品推荐

