在Android中与Moshi一起解析没有密钥的JSON列表
我要做的是从用户存储库列表的GitHub API呼叫中获取JSON响应。
GitHub的响应示例如下所示。
[
{
"id": 78688034,
"node_id": "MDEwOlJlcG9zaXRvcnk3ODY4ODAzNA==",
"name": "py3status",
"full_name": "randomguy/py3status",
"private": false,
"owner": {
"login": "randomguy",
"id": 798223,
"node_id": "MDQ6VXNlcjc5ODIyMw==",
"avatar_url": "https://avatars.githubusercontent.com/u/798223?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/randomguy",
"html_url": "https://github.com/randomguy",
"followers_url": "https://api.github.com/users/randomguy/followers",
"following_url": "https://api.github.com/users/randomguy/following{/other_user}",
"gists_url": "https://api.github.com/users/randomguy/gists{/gist_id}",
"starred_url": "https://api.github.com/users/randomguy/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/randomguy/subscriptions",
"organizations_url": "https://api.github.com/users/randomguy/orgs",
"repos_url": "https://api.github.com/users/randomguy/repos",
"events_url": "https://api.github.com/users/randomguy/events{/privacy}",
"received_events_url": "https://api.github.com/users/randomguy/received_events",
"type": "User",
"site_admin": false
},
"html_url": "https://github.com/randomguy/py3status",
"description": "py3status is an extensible i3status wrapper written in python",
"fork": true,
"url": "https://api.github.com/repos/randomguy/py3status",
"forks_url": "https://api.github.com/repos/randomguy/py3status/forks",
"keys_url": "https://api.github.com/repos/randomguy/py3status/keys{/key_id}",
"collaborators_url": "https://api.github.com/repos/randomguy/py3status/collaborators{/collaborator}",
"teams_url": "https://api.github.com/repos/randomguy/py3status/teams",
"hooks_url": "https://api.github.com/repos/randomguy/py3status/hooks",
"issue_events_url": "https://api.github.com/repos/randomguy/py3status/issues/events{/number}",
"events_url": "https://api.github.com/repos/randomguy/py3status/events",
"assignees_url": "https://api.github.com/repos/randomguy/py3status/assignees{/user}",
"branches_url": "https://api.github.com/repos/randomguy/py3status/branches{/branch}",
"tags_url": "https://api.github.com/repos/randomguy/py3status/tags",
"blobs_url": "https://api.github.com/repos/randomguy/py3status/git/blobs{/sha}",
"git_tags_url": "https://api.github.com/repos/randomguy/py3status/git/tags{/sha}",
"git_refs_url": "https://api.github.com/repos/randomguy/py3status/git/refs{/sha}",
"trees_url": "https://api.github.com/repos/randomguy/py3status/git/trees{/sha}",
"statuses_url": "https://api.github.com/repos/randomguy/py3status/statuses/{sha}",
"languages_url": "https://api.github.com/repos/randomguy/py3status/languages",
"stargazers_url": "https://api.github.com/repos/randomguy/py3status/stargazers",
"contributors_url": "https://api.github.com/repos/randomguy/py3status/contributors",
"subscribers_url": "https://api.github.com/repos/randomguy/py3status/subscribers",
"subscription_url": "https://api.github.com/repos/randomguy/py3status/subscription",
"commits_url": "https://api.github.com/repos/randomguy/py3status/commits{/sha}",
"git_commits_url": "https://api.github.com/repos/randomguy/py3status/git/commits{/sha}",
"comments_url": "https://api.github.com/repos/randomguy/py3status/comments{/number}",
"issue_comment_url": "https://api.github.com/repos/randomguy/py3status/issues/comments{/number}",
"contents_url": "https://api.github.com/repos/randomguy/py3status/contents/{+path}",
"compare_url": "https://api.github.com/repos/randomguy/py3status/compare/{base}...{head}",
"merges_url": "https://api.github.com/repos/randomguy/py3status/merges",
"archive_url": "https://api.github.com/repos/randomguy/py3status/{archive_format}{/ref}",
"downloads_url": "https://api.github.com/repos/randomguy/py3status/downloads",
"issues_url": "https://api.github.com/repos/randomguy/py3status/issues{/number}",
"pulls_url": "https://api.github.com/repos/randomguy/py3status/pulls{/number}",
"milestones_url": "https://api.github.com/repos/randomguy/py3status/milestones{/number}",
"notifications_url": "https://api.github.com/repos/randomguy/py3status/notifications{?since,all,participating}",
"labels_url": "https://api.github.com/repos/randomguy/py3status/labels{/name}",
"releases_url": "https://api.github.com/repos/randomguy/py3status/releases{/id}",
"deployments_url": "https://api.github.com/repos/randomguy/py3status/deployments",
"created_at": "2017-01-11T23:05:15Z",
"updated_at": "2017-01-11T23:05:17Z",
"pushed_at": "2017-08-04T18:56:56Z",
"git_url": "git://github.com/randomguy/py3status.git",
"ssh_url": "[email protected]:randomguy/py3status.git",
"clone_url": "https://github.com/randomguy/py3status.git",
"svn_url": "https://github.com/randomguy/py3status",
"homepage": "",
"size": 3078,
"stargazers_count": 0,
"watchers_count": 0,
"language": "Python",
"has_issues": false,
"has_projects": true,
"has_downloads": true,
"has_wiki": true,
"has_pages": false,
"forks_count": 0,
"mirror_url": null,
"archived": false,
"disabled": false,
"open_issues_count": 0,
"license": {
"key": "bsd-3-clause",
"name": "BSD 3-Clause \"New\" or \"Revised\" License",
"spdx_id": "BSD-3-Clause",
"url": "https://api.github.com/licenses/bsd-3-clause",
"node_id": "MDc6TGljZW5zZTU="
},
"allow_forking": true,
"is_template": false,
"web_commit_signoff_required": false,
"topics": [
],
"visibility": "public",
"forks": 0,
"open_issues": 0,
"watchers": 0,
"default_branch": "master"
}
]
如您所见,响应是以arraylist的形式 由于此响应对JSON列表没有钥匙值,因此自动生成的数据类如下所示(UserRepoListerSponse和UserRepoListerSponseponsem)。
class UserRepoListResponse : ArrayList<UserRepoListResponseItem>()
@JsonClass(generateAdapter = true)
data class UserRepoListResponseItem(
@Json(name ="allow_forking") val allowForking: Boolean,
@Json(name ="archive_url") val archiveUrl: String,
@Json(name ="archived") val archived: Boolean,
@Json(name ="assignees_url") val assigneesUrl: String,
@Json(name ="blobs_url") val blobsUrl: String,
@Json(name ="branches_url") val branchesUrl: String,
@Json(name ="clone_url") val cloneUrl: String,
@Json(name ="collaborators_url") val collaboratorsUrl: String,
@Json(name ="comments_url") val commentsUrl: String,
@Json(name ="commits_url") val commitsUrl: String,
@Json(name ="compare_url") val compareUrl: String,
@Json(name ="contents_url") val contentsUrl: String,
@Json(name ="contributors_url") val contributorsUrl: String,
@Json(name ="created_at") val createdAt: String,
@Json(name ="default_branch") val defaultBranch: String,
@Json(name ="deployments_url") val deploymentsUrl: String,
@Json(name ="description") val description: String,
@Json(name ="disabled") val disabled: Boolean,
@Json(name ="downloads_url") val downloadsUrl: String,
@Json(name ="events_url") val eventsUrl: String,
@Json(name ="fork") val fork: Boolean,
@Json(name ="forks") val forks: Int,
@Json(name ="forks_count") val forksCount: Int,
@Json(name ="forks_url") val forksUrl: String,
@Json(name ="full_name") val fullName: String,
@Json(name ="git_commits_url") val gitCommitsUrl: String,
@Json(name ="git_refs_url") val gitRefsUrl: String,
@Json(name ="git_tags_url") val gitTagsUrl: String,
@Json(name ="git_url") val gitUrl: String,
@Json(name ="has_downloads") val hasDownloads: Boolean,
@Json(name ="has_issues") val hasIssues: Boolean,
@Json(name ="has_pages") val hasPages: Boolean,
@Json(name ="has_projects") val hasProjects: Boolean,
@Json(name ="has_wiki") val hasWiki: Boolean,
@Json(name ="homepage") val homepage: String,
@Json(name ="hooks_url") val hooksUrl: String,
@Json(name ="html_url") val htmlUrl: String,
@Json(name ="id") val id: Int,
@Json(name ="is_template") val isTemplate: Boolean,
@Json(name ="issue_comment_url") val issueCommentUrl: String,
@Json(name ="issue_events_url") val issueEventsUrl: String,
@Json(name ="issues_url") val issuesUrl: String,
@Json(name ="keys_url") val keysUrl: String,
@Json(name ="labels_url") val labelsUrl: String,
@Json(name ="language") val language: String,
@Json(name ="languages_url") val languagesUrl: String,
@Json(name ="license") val license: License,
@Json(name ="merges_url") val mergesUrl: String,
@Json(name ="milestones_url") val milestonesUrl: String,
@Json(name ="mirror_url") val mirrorUrl: Any,
@Json(name ="name") val name: String,
@Json(name ="node_id") val nodeId: String,
@Json(name ="notifications_url") val notificationsUrl: String,
@Json(name ="open_issues") val openIssues: Int,
@Json(name ="open_issues_count") val openIssuesCount: Int,
@Json(name ="owner") val owner: Owner,
@Json(name ="private") val privateValue: Boolean,
@Json(name ="pulls_url") val pullsUrl: String,
@Json(name ="pushed_at") val pushedAt: String,
@Json(name ="releases_url") val releasesUrl: String,
@Json(name ="size") val size: Int,
@Json(name ="ssh_url") val sshUrl: String,
@Json(name ="stargazers_count") val stargazersCount: Int,
@Json(name ="stargazers_url") val stargazersUrl: String,
@Json(name ="statuses_url") val statusesUrl: String,
@Json(name ="subscribers_url") val subscribersUrl: String,
@Json(name ="subscription_url") val subscriptionUrl: String,
@Json(name ="svn_url") val svnUrl: String,
@Json(name ="tags_url") val tagsUrl: String,
@Json(name ="teams_url") val teamsUrl: String,
@Json(name ="topics") val topics: List<String>,
@Json(name ="trees_url") val treesUrl: String,
@Json(name ="updated_at") val updatedAt: String,
@Json(name ="url") val url: String,
@Json(name ="visibility") val visibility: String,
@Json(name ="watchers") val watchers: Int,
@Json(name ="watchers_count") val watchersCount: Int
)
我正在使用Retrofit2和Moshi。依赖项如下所示
// retrofit moshi
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation "com.squareup.retrofit2:converter-moshi:2.9.0"
//Moshi Library Dependencies - Core Moshi JSON Library and Moshi's Kotlin support and converter factory
implementation "com.squareup.moshi:moshi:1.13.0"
implementation "com.squareup.moshi:moshi-kotlin:1.13.0"
,这是我设置moshi和retrofit2的方式
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
private val retrofit = Retrofit.Builder()
.addConverterFactory(MoshiConverterFactory.create(moshi))
.baseUrl(BASE_URL)
.client(getHttpClient())
.build()
,这是我的API调用函数,
@GET("/users/{username}/repos")
suspend fun getUserRepos(
@Path("username") username: String,
): UserRepoListResponse
然后我调用API调用,我得到此错误
Expected BEGIN_OBJECT but was BEGIN_ARRAY at path $
我在做什么错?请帮我..
What I am trying to do is to get Json response from GitHub API call of user's repository list.
response example from Github is like below.
[
{
"id": 78688034,
"node_id": "MDEwOlJlcG9zaXRvcnk3ODY4ODAzNA==",
"name": "py3status",
"full_name": "randomguy/py3status",
"private": false,
"owner": {
"login": "randomguy",
"id": 798223,
"node_id": "MDQ6VXNlcjc5ODIyMw==",
"avatar_url": "https://avatars.githubusercontent.com/u/798223?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/randomguy",
"html_url": "https://github.com/randomguy",
"followers_url": "https://api.github.com/users/randomguy/followers",
"following_url": "https://api.github.com/users/randomguy/following{/other_user}",
"gists_url": "https://api.github.com/users/randomguy/gists{/gist_id}",
"starred_url": "https://api.github.com/users/randomguy/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/randomguy/subscriptions",
"organizations_url": "https://api.github.com/users/randomguy/orgs",
"repos_url": "https://api.github.com/users/randomguy/repos",
"events_url": "https://api.github.com/users/randomguy/events{/privacy}",
"received_events_url": "https://api.github.com/users/randomguy/received_events",
"type": "User",
"site_admin": false
},
"html_url": "https://github.com/randomguy/py3status",
"description": "py3status is an extensible i3status wrapper written in python",
"fork": true,
"url": "https://api.github.com/repos/randomguy/py3status",
"forks_url": "https://api.github.com/repos/randomguy/py3status/forks",
"keys_url": "https://api.github.com/repos/randomguy/py3status/keys{/key_id}",
"collaborators_url": "https://api.github.com/repos/randomguy/py3status/collaborators{/collaborator}",
"teams_url": "https://api.github.com/repos/randomguy/py3status/teams",
"hooks_url": "https://api.github.com/repos/randomguy/py3status/hooks",
"issue_events_url": "https://api.github.com/repos/randomguy/py3status/issues/events{/number}",
"events_url": "https://api.github.com/repos/randomguy/py3status/events",
"assignees_url": "https://api.github.com/repos/randomguy/py3status/assignees{/user}",
"branches_url": "https://api.github.com/repos/randomguy/py3status/branches{/branch}",
"tags_url": "https://api.github.com/repos/randomguy/py3status/tags",
"blobs_url": "https://api.github.com/repos/randomguy/py3status/git/blobs{/sha}",
"git_tags_url": "https://api.github.com/repos/randomguy/py3status/git/tags{/sha}",
"git_refs_url": "https://api.github.com/repos/randomguy/py3status/git/refs{/sha}",
"trees_url": "https://api.github.com/repos/randomguy/py3status/git/trees{/sha}",
"statuses_url": "https://api.github.com/repos/randomguy/py3status/statuses/{sha}",
"languages_url": "https://api.github.com/repos/randomguy/py3status/languages",
"stargazers_url": "https://api.github.com/repos/randomguy/py3status/stargazers",
"contributors_url": "https://api.github.com/repos/randomguy/py3status/contributors",
"subscribers_url": "https://api.github.com/repos/randomguy/py3status/subscribers",
"subscription_url": "https://api.github.com/repos/randomguy/py3status/subscription",
"commits_url": "https://api.github.com/repos/randomguy/py3status/commits{/sha}",
"git_commits_url": "https://api.github.com/repos/randomguy/py3status/git/commits{/sha}",
"comments_url": "https://api.github.com/repos/randomguy/py3status/comments{/number}",
"issue_comment_url": "https://api.github.com/repos/randomguy/py3status/issues/comments{/number}",
"contents_url": "https://api.github.com/repos/randomguy/py3status/contents/{+path}",
"compare_url": "https://api.github.com/repos/randomguy/py3status/compare/{base}...{head}",
"merges_url": "https://api.github.com/repos/randomguy/py3status/merges",
"archive_url": "https://api.github.com/repos/randomguy/py3status/{archive_format}{/ref}",
"downloads_url": "https://api.github.com/repos/randomguy/py3status/downloads",
"issues_url": "https://api.github.com/repos/randomguy/py3status/issues{/number}",
"pulls_url": "https://api.github.com/repos/randomguy/py3status/pulls{/number}",
"milestones_url": "https://api.github.com/repos/randomguy/py3status/milestones{/number}",
"notifications_url": "https://api.github.com/repos/randomguy/py3status/notifications{?since,all,participating}",
"labels_url": "https://api.github.com/repos/randomguy/py3status/labels{/name}",
"releases_url": "https://api.github.com/repos/randomguy/py3status/releases{/id}",
"deployments_url": "https://api.github.com/repos/randomguy/py3status/deployments",
"created_at": "2017-01-11T23:05:15Z",
"updated_at": "2017-01-11T23:05:17Z",
"pushed_at": "2017-08-04T18:56:56Z",
"git_url": "git://github.com/randomguy/py3status.git",
"ssh_url": "[email protected]:randomguy/py3status.git",
"clone_url": "https://github.com/randomguy/py3status.git",
"svn_url": "https://github.com/randomguy/py3status",
"homepage": "",
"size": 3078,
"stargazers_count": 0,
"watchers_count": 0,
"language": "Python",
"has_issues": false,
"has_projects": true,
"has_downloads": true,
"has_wiki": true,
"has_pages": false,
"forks_count": 0,
"mirror_url": null,
"archived": false,
"disabled": false,
"open_issues_count": 0,
"license": {
"key": "bsd-3-clause",
"name": "BSD 3-Clause \"New\" or \"Revised\" License",
"spdx_id": "BSD-3-Clause",
"url": "https://api.github.com/licenses/bsd-3-clause",
"node_id": "MDc6TGljZW5zZTU="
},
"allow_forking": true,
"is_template": false,
"web_commit_signoff_required": false,
"topics": [
],
"visibility": "public",
"forks": 0,
"open_issues": 0,
"watchers": 0,
"default_branch": "master"
}
]
As you can see, the response is in arrayList form but with NO Key value.
Since this response doesn't have Key value for Json List, auto generated data classes look like these below(UserRepoListResponse and UserRepoListResponseItem).
class UserRepoListResponse : ArrayList<UserRepoListResponseItem>()
@JsonClass(generateAdapter = true)
data class UserRepoListResponseItem(
@Json(name ="allow_forking") val allowForking: Boolean,
@Json(name ="archive_url") val archiveUrl: String,
@Json(name ="archived") val archived: Boolean,
@Json(name ="assignees_url") val assigneesUrl: String,
@Json(name ="blobs_url") val blobsUrl: String,
@Json(name ="branches_url") val branchesUrl: String,
@Json(name ="clone_url") val cloneUrl: String,
@Json(name ="collaborators_url") val collaboratorsUrl: String,
@Json(name ="comments_url") val commentsUrl: String,
@Json(name ="commits_url") val commitsUrl: String,
@Json(name ="compare_url") val compareUrl: String,
@Json(name ="contents_url") val contentsUrl: String,
@Json(name ="contributors_url") val contributorsUrl: String,
@Json(name ="created_at") val createdAt: String,
@Json(name ="default_branch") val defaultBranch: String,
@Json(name ="deployments_url") val deploymentsUrl: String,
@Json(name ="description") val description: String,
@Json(name ="disabled") val disabled: Boolean,
@Json(name ="downloads_url") val downloadsUrl: String,
@Json(name ="events_url") val eventsUrl: String,
@Json(name ="fork") val fork: Boolean,
@Json(name ="forks") val forks: Int,
@Json(name ="forks_count") val forksCount: Int,
@Json(name ="forks_url") val forksUrl: String,
@Json(name ="full_name") val fullName: String,
@Json(name ="git_commits_url") val gitCommitsUrl: String,
@Json(name ="git_refs_url") val gitRefsUrl: String,
@Json(name ="git_tags_url") val gitTagsUrl: String,
@Json(name ="git_url") val gitUrl: String,
@Json(name ="has_downloads") val hasDownloads: Boolean,
@Json(name ="has_issues") val hasIssues: Boolean,
@Json(name ="has_pages") val hasPages: Boolean,
@Json(name ="has_projects") val hasProjects: Boolean,
@Json(name ="has_wiki") val hasWiki: Boolean,
@Json(name ="homepage") val homepage: String,
@Json(name ="hooks_url") val hooksUrl: String,
@Json(name ="html_url") val htmlUrl: String,
@Json(name ="id") val id: Int,
@Json(name ="is_template") val isTemplate: Boolean,
@Json(name ="issue_comment_url") val issueCommentUrl: String,
@Json(name ="issue_events_url") val issueEventsUrl: String,
@Json(name ="issues_url") val issuesUrl: String,
@Json(name ="keys_url") val keysUrl: String,
@Json(name ="labels_url") val labelsUrl: String,
@Json(name ="language") val language: String,
@Json(name ="languages_url") val languagesUrl: String,
@Json(name ="license") val license: License,
@Json(name ="merges_url") val mergesUrl: String,
@Json(name ="milestones_url") val milestonesUrl: String,
@Json(name ="mirror_url") val mirrorUrl: Any,
@Json(name ="name") val name: String,
@Json(name ="node_id") val nodeId: String,
@Json(name ="notifications_url") val notificationsUrl: String,
@Json(name ="open_issues") val openIssues: Int,
@Json(name ="open_issues_count") val openIssuesCount: Int,
@Json(name ="owner") val owner: Owner,
@Json(name ="private") val privateValue: Boolean,
@Json(name ="pulls_url") val pullsUrl: String,
@Json(name ="pushed_at") val pushedAt: String,
@Json(name ="releases_url") val releasesUrl: String,
@Json(name ="size") val size: Int,
@Json(name ="ssh_url") val sshUrl: String,
@Json(name ="stargazers_count") val stargazersCount: Int,
@Json(name ="stargazers_url") val stargazersUrl: String,
@Json(name ="statuses_url") val statusesUrl: String,
@Json(name ="subscribers_url") val subscribersUrl: String,
@Json(name ="subscription_url") val subscriptionUrl: String,
@Json(name ="svn_url") val svnUrl: String,
@Json(name ="tags_url") val tagsUrl: String,
@Json(name ="teams_url") val teamsUrl: String,
@Json(name ="topics") val topics: List<String>,
@Json(name ="trees_url") val treesUrl: String,
@Json(name ="updated_at") val updatedAt: String,
@Json(name ="url") val url: String,
@Json(name ="visibility") val visibility: String,
@Json(name ="watchers") val watchers: Int,
@Json(name ="watchers_count") val watchersCount: Int
)
I am using Retofit2 and Moshi. Dependencies are like below
// retrofit moshi
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation "com.squareup.retrofit2:converter-moshi:2.9.0"
//Moshi Library Dependencies - Core Moshi JSON Library and Moshi's Kotlin support and converter factory
implementation "com.squareup.moshi:moshi:1.13.0"
implementation "com.squareup.moshi:moshi-kotlin:1.13.0"
and this is how I set up Moshi and Retrofit2
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
private val retrofit = Retrofit.Builder()
.addConverterFactory(MoshiConverterFactory.create(moshi))
.baseUrl(BASE_URL)
.client(getHttpClient())
.build()
and this is my api call function
@GET("/users/{username}/repos")
suspend fun getUserRepos(
@Path("username") username: String,
): UserRepoListResponse
then I call the API call, I get this error
Expected BEGIN_OBJECT but was BEGIN_ARRAY at path $
what am I doing wrong? please help me..
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
因为您获得的JSON是一个数组,因此您需要返回数组(列表)类型而不是对象类型。该错误来自Moshi,试图将数组(外代码)作为对象(外代码
{}
)作为对象。更改以下内容:
返回列表
Because the JSON you are getting is an array, you need to return an array (List) type instead of an object type. The error came from Moshi trying to parse an array (outer tokens
[]
) as an object (outer tokens{}
).Change this:
to return a list instead