개조가 BEGIN_OBJECT로 예상되었지만 BEGIN_ARRAY였습니다.
저는 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였습니다.
여기서 무엇이 잘못 되었습니까?
지금은 다음과 같은 형식으로 응답을 구문 분석하고 있습니다.
{
"contacts": [
{ .. }
]
}
예외는 루트에서 객체를 기대하지만 실제 데이터는 실제로 배열이라는 점에서이를 알려줍니다. 즉, 유형을 배열로 변경해야합니다.
가장 쉬운 방법은 콜백에서 직접 유형으로 목록을 사용하는 것입니다.
@GET("/users.json")
void contacts(Callback<List<User>> cb);
인터페이스에서
@GET("/users.json")
void contacts(Callback<Contacts> cb);
이 코드로
@GET("/users.json")
void contacts(Callback<List<Contacts>> cb);
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의 경우)
이 경우는 json responses다음과 같은 형식에 적용됩니다.[{...} ,{...}]
예
[
{
"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 응답에 적용됩니다.
예
{
"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":[{...} ,{...}]}
예
{
"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 : json 배열 응답 파싱 , 사례 2 : json 객체 응답 파싱 , 혼합 : 다른 json 객체 내부에서 json 배열 파싱
목록으로 변환하십시오.
다음은 그 예입니다.
BenchmarksListModel_v1[] benchmarksListModel = res.getBody().as(BenchmarksListModel_v1[].class);
소스 코드 작동
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();
}
});
MPV를 사용 하여 Deserializer에 다음을 넣으십시오.
JsonObject obj = new JsonObject();
obj.add("data", json);
JsonArray data = obj.getAsJsonObject().getAsJsonArray("data");
여기서 스택은 Kotlin, Retrofit2, RxJava이며 일반 Call메서드에서 마이그레이션하고 있습니다.
내가 만든 서비스는 던지고 메시지 com.google.gson.JsonSyntaxException와 java.lang.IllegalStateException함께 :
Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column2
But all the answers I could find said that this was caused by not having an array type in the service, which I already did. My Kotlin service looked like this:
// 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>>>
}
The problem was the Result in there, which I had put in when I was using an earlier Call based solution.
Removing it fixed the problem. I also had to change the signature of the two error handling methods at my call-site for the service:
/// WORKING SERVICE
interface InventoryService {
@GET("getInventoryData/{storeId}")
fun getInventoryData(@Path("storeId") storeId: String,
@Query("startDate") startDate: String,
@Query("endDate") endDate: String) :
Single<List<InventoryData>>
}
And the call-site fragment code that uses the service:
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()
}
Note that the above code has been changed a little. In particular I used a Retrofit2 ConverterFactory to allow the dates to be passed in as OffsetDateTime objects instead of strings.
참고URL : https://stackoverflow.com/questions/24154917/retrofit-expected-begin-object-but-was-begin-array
'IT TIP' 카테고리의 다른 글
| EPPlus로 XLSX 셀 너비를 설정하는 방법은 무엇입니까? (0) | 2020.11.03 |
|---|---|
| Git Stash Uncached : 모든 미 단계 변경 사항을 삭제하는 방법은 무엇입니까? (0) | 2020.11.03 |
| 문자열에서 ASCII가 아닌 문자 제거 (0) | 2020.11.02 |
| 문자열 내에서 URL을 찾기위한 정규식 (0) | 2020.11.02 |
| gem install pg --with-pg-config 작동, 번들 실패 (0) | 2020.11.02 |