我是JSON解析的新手,我正在使用Square的Retrofit库并遇到了这个问题。
我正在尝试解析这个JSON响应:
[
{
"id": 3,
"username": "jezer",
"regid": "oiqwueoiwqueoiwqueoiwq",
"url": "http:\/\/192.168.63.175:3000\/users\/3.json"
},
{
"id": 4,
"username": "emulator",
"regid": "qwoiuewqoiueoiwqueoq",
"url": "http:\/\/192.168.63.175:3000\/users\/4.json"
},
{
"id": 7,
"username": "test",
"regid": "ksadqowueqiaksj",
"url": "http:\/\/192.168.63.175:3000\/users\/7.json"
}
]
以下是我的模特:
public class Contacts {
public List<User> contacts;
}
...
public class User {
String username;
String regid;
@Override
public String toString(){
return(username);
}
}
我的界面:
public interface ContactsInterface {
@GET("/users.json")
void contacts(Callback<Contacts> cb);
}
我的成功方法:
@Override
public void success(Contacts c, Response r) {
List<String> names = new ArrayList<String>();
for (int i = 0; i < c.contacts.size(); i++) {
String name = c.contacts.get(i).toString();
Log.d("Names", "" + name);
names.add(name);
}
ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item, names);
mSentTo.setAdapter(spinnerAdapter);
}
当我在成功方法上使用它时会抛出错误
预计BEGIN_OBJECT但在第1行第2列是BEGIN_ARRAY
这里有什么问题?
答案 0 :(得分:136)
现在,您正在解析响应,就像它的格式如下:
{
"contacts": [
{ .. }
]
}
该异常告诉您这一点,因为您期望根目录中的对象,但实际数据实际上是一个数组。这意味着您需要将类型更改为数组。
最简单的方法是在回调中使用列表作为直接类型:
@GET("/users.json")
void contacts(Callback<List<User>> cb);
答案 1 :(得分:7)
在您的界面中 替换
@GET("/users.json")
void contacts(Callback<Contacts> cb);
通过此代码
@GET("/users.json")
void contacts(Callback<List<Contacts>> cb);
答案 2 :(得分:4)
<强> dependencies used :
强>
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.3.0'
json回复可以是array response
或object response
,也可以是两者的组合。请参阅以下三种情况
Case 1 : Parsing a json array response
(OP&#39; s)
此案例适用于 json responses
[{...} ,{...}]
E.g。
[
{
"id": 3,
"username": "jezer",
"regid": "oiqwueoiwqueoiwqueoiwq",
"url": "http:\/\/192.168.63.175:3000\/users\/3.json"
},
.
.
]
首先为这个数组创建一个模型类,或者只是转到jsonschema2pojo并自动生成一个如下所示
Contacts.java
public class Contacts {
@SerializedName("id")
@Expose
private Integer id;
@SerializedName("username")
@Expose
private String username;
@SerializedName("regid")
@Expose
private String regid;
@SerializedName("url")
@Expose
private String url;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getRegid() {
return regid;
}
public void setRegid(String regid) {
this.regid = regid;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
<强> ContactsInterface
强>
在这种情况下,您应该返回一个对象列表,如下所示
public interface ContactsInterface {
@GET("/users.json")
Call<List<Contacts>> getContacts();
}
然后按以下
进行retrofit2
调用
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("baseurl_here")
.addConverterFactory(GsonConverterFactory.create())
.build();
ContactsInterface request = retrofit.create(ContactsInterface.class);
Call<List<Contacts>> call = request.getContacts();
call.enqueue(new Callback<List<Contacts>>() {
@Override
public void onResponse(Call<List<Contacts>> call, Response<List<Contacts>> response) {
Toast.makeText(MainActivity.this,response.body().toString(),Toast.LENGTH_SHORT).show();
}
@Override
public void onFailure(Call<List<Contacts>> call, Throwable t) {
Log.e("Error",t.getMessage());
}
});
response.body()
会为您提供对象列表
您还可以检查以下两个案例供参考
<强> Case 2 : Parsing a json object response
强>
这种情况适用于那些形式为{..}
的json响应E.g。
{
"id": 3,
"username": "jezer",
"regid": "oiqwueoiwqueoiwqueoiwq",
"url": "http:\/\/192.168.63.175:3000\/users\/3.json"
}
在这里,我们与上面的示例具有相同的object
。因此模型类将是相同的,但是像上面的例子我们没有这些对象的数组 - 只有一个对象,因此我们不需要将它解析为列表。
因此,对object response
public interface ContactsInterface {
@GET("/users.json")
Call<Contacts> getContacts();
}
然后按以下
进行retrofit2
调用
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("baseurl_here")
.addConverterFactory(GsonConverterFactory.create())
.build();
ContactsInterface request = retrofit.create(ContactsInterface.class);
Call<Contacts> call = request.getContacts();
call.enqueue(new Callback<Contacts>() {
@Override
public void onResponse(Call<Contacts> call, Response<Contacts> response) {
Toast.makeText(MainActivity.this,response.body().toString(),Toast.LENGTH_SHORT).show();
}
@Override
public void onFailure(Call<Contacts> call, Throwable t) {
Log.e("Error",t.getMessage());
}
});
response.body()
将为您提供对象
您还可以在解析json对象响应时检查常见错误:"expected begin_array but was begin_object"
<强> Case 3 : Parsing a json array inside json object
强>
此案例适用于 json responses
{"array_name":[{...} ,{...}]}
E.g。
{
"contacts":
[
{
"id": 3,
"username": "jezer",
"regid": "oiqwueoiwqueoiwqueoiwq",
"url": "http:\/\/192.168.63.175:3000\/users\/3.json"
}
]
}
这里你需要两个模型类,因为我们有两个对象(一个在外面,一个在数组内)。生成如下所示
<强> ContactWrapper
强>
public class ContactWrapper {
@SerializedName("contacts")
@Expose
private List<Contacts> contacts = null;
public List<Contacts> getContacts() {
return contacts;
}
public void setContacts(List<Contacts> contacts) {
this.contacts = contacts;
}
}
您可以使用上面生成的 Contacts.java
作为列表对象(针对案例1生成)
因此,对object response
public interface ContactsInterface {
@GET("/users.json")
Call<ContactWrapper> getContacts();
}
然后按以下
进行retrofit2
调用
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("baseurl_here")
.addConverterFactory(GsonConverterFactory.create())
.build();
ContactsInterface request = retrofit.create(ContactsInterface.class);
Call<ContactWrapper> call = request.getContacts();
call.enqueue(new Callback<ContactWrapper>() {
@Override
public void onResponse(Call<ContactWrapper> call, Response<ContactWrapper> response) {
Toast.makeText(MainActivity.this,response.body().getContacts().toString(),Toast.LENGTH_SHORT).show();
}
@Override
public void onFailure(Call<ContactWrapper> call, Throwable t) {
Log.e("Error",t.getMessage());
}
});
此处与案例1的区别在于我们应该使用response.body().getContacts()
代替response.body()
来获取对象列表
以上案例的一些参考文献:
案例1:Parsing a json array response, 案例2:Parsing a json object response, 混合:Parsing json array inside another json object
答案 3 :(得分:1)
将其转换为列表。
以下是示例:
BenchmarksListModel_v1[] benchmarksListModel = res.getBody().as(BenchmarksListModel_v1[].class);
答案 4 :(得分:1)
源代码工作
https://drive.google.com/open?id=0BzBKpZ4nzNzUVFRnVVkzc0JabUU
public interface ApiInterface {
@GET("inbox.json")
Call<List<Message>> getInbox();
}
call.enqueue(new Callback<List<Message>>() {
@Override
public void onResponse(Call<List<Message>> call, Response<List<Message>> response) {
YourpojoClass.addAll(response.body());
mAdapter.notifyDataSetChanged();
}
@Override
public void onFailure(Call<List<Message>> call, Throwable t) {
Toast.makeText(getApplicationContext(), "Unable to fetch json: " + t.getMessage(), Toast.LENGTH_LONG).show();
}
});
答案 5 :(得分:0)
使用 MPV ,在您的反序列化程序中,输入此
$(function () {
$("#checkin").datepicker({
dateFormat: "M-dd-yy",
minDate: 0,
onClose: function () {
var date2 = $('#checkin').datepicker('getDate');
date2.setDate(date2.getDate() + 1);
$('#checkout').datepicker('setDate', date2);
$('#checkout ').datepicker('option', 'minDate', date2);
datepicked();
$('#checkout').datepicker('option');
}
});
$('#checkout').datepicker({
dateFormat: "M-dd-yy",
minDate: 0,
onSelect: function () {
var dt1 = $('#checkin ').datepicker('getDate');
var dt2 = $('#checkout').datepicker('getDate');
datepicked();
//check to prevent a user from entering a date below date of dt1
if (dt2 <= dt1) {
var minDate = $('#checkout ').datepicker('option', 'minDate');
$('#checkout').datepicker('setDate', minDate);
$('#checkin').datepicker('option');
}
}
});
var datepicked = function() {
var checkin = $('#checkin');
var checkout = $('#checkout');
var nights = $('#nights');
var fromDate = checkin.datepicker('getDate');
var toDate = checkout.datepicker('getDate');
if (toDate && fromDate) {
var oneDay = 1000*60*60*24;
var difference = Math.ceil((toDate.getTime() - fromDate.getTime()) / oneDay);
nights.val(difference);
}
};
});
$(function () {
$("#date").datepicker({
dateFormat: "dd-M-yy",
minDate: 0,
autoclose: true,
startDate: new Date()
});
});
答案 6 :(得分:0)
这里的堆栈是Kotlin,Retrofit2,RxJava,我们正从常规的Call
方法迁移到该堆栈。
我创建的服务正在抛出com.google.gson.JsonSyntaxException
和java.lang.IllegalStateException
并显示以下消息:
Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column2
但是我能找到的所有答案都说这是由于服务中没有 array 类型引起的,而我已经这样做了。我的Kotlin服务看起来像这样:
// Data class. Retrofit2 & Gson can deserialize this. No extra code needed.
data class InventoryData(
val productCode: String,
val stockDate: String,
val availCount: Int,
val totalAvailCount: Int,
val inventorySold: Int,
val closed: Boolean
)
// BROKEN SERVICE. Throws com.google.gson.JsonSyntaxException
// Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column2
interface InventoryService {
@GET("getInventoryData/{storeId}")
fun getInventoryData(@Path("storeId") storeId: String,
@Query("startDate") startDate: String,
@Query("endDate") endDate: String) :
Result<Single<List<InventoryData>>>
}
问题是其中的Result
是我在使用较早的基于Call
的解决方案时所插入的。
删除它可以解决问题。我还必须在服务的呼叫站点更改两种错误处理方法的签名:
/// WORKING SERVICE
interface InventoryService {
@GET("getInventoryData/{storeId}")
fun getInventoryData(@Path("storeId") storeId: String,
@Query("startDate") startDate: String,
@Query("endDate") endDate: String) :
Single<List<InventoryData>>
}
以及使用该服务的呼叫站点片段代码:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.disposables
.add(viewModel.ratsService.getInventoryData(it, fromDate, toDate)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(this::successResult, this::failureResult))
}
}
private fun failureResult(error: Throwable) {
when (error) {
is HttpException -> { if (error.code() == 401) {
textField.text = "Log in required!" } }
else -> textField.text = "Error: $error."
}
}
/// Had to change to this from previous broken
/// one that took `Result<List<InventoryData>>`
private fun successResult(result: List<InventoryData>) {
textField.text = result.toString()
}
请注意,上面的代码已稍作更改。特别是,我使用Retrofit2 ConverterFactory
来允许日期以OffsetDateTime对象而不是字符串的形式传递。