GSON ขว้างปา“ คาดว่าจะ BEGIN_OBJECT แต่เป็น BEGIN_ARRAY” หรือไม่


295

ฉันพยายามแยกสตริง JSON แบบนี้

[
   {
      "updated_at":"2012-03-02 21:06:01",
      "fetched_at":"2012-03-02 21:28:37.728840",
      "description":null,
      "language":null,
      "title":"JOHN",
      "url":"http://rus.JOHN.JOHN/rss.php",
      "icon_url":null,
      "logo_url":null,
      "id":"4f4791da203d0c2d76000035",
      "modified":"2012-03-02 23:28:58.840076"
   },
   {
      "updated_at":"2012-03-02 14:07:44",
      "fetched_at":"2012-03-02 21:28:37.033108",
      "description":null,
      "language":null,
      "title":"PETER",
      "url":"http://PETER.PETER.lv/rss.php",
      "icon_url":null,
      "logo_url":null,
      "id":"4f476f61203d0c2d89000253",
      "modified":"2012-03-02 23:28:57.928001"
   }
]

ลงในรายการของวัตถุ

List<ChannelSearchEnum> lcs = (List<ChannelSearchEnum>) new Gson().fromJson( jstring , ChannelSearchEnum.class);

นี่คือคลาสวัตถุที่ฉันใช้

import com.google.gson.annotations.SerializedName;

public class ChannelSearchEnum {



@SerializedName("updated_at")
private String updated_at;

@SerializedName("fetched_at")
private String fetched_at;

@SerializedName("description")
private String description;

@SerializedName("language")
private String language;

@SerializedName("title")
private String title;

@SerializedName("url")
private String url;

@SerializedName("icon_url")
private String icon_url;

@SerializedName("logo_url")
private String logo_url;

@SerializedName("id")
private String id;

@SerializedName("modified")
private String modified;

public final String get_Updated_at() {
    return this.updated_at;
}

public final String get_Fetched_at() {
    return this.fetched_at;
}

public final String get_Description() {
    return this.description;
}

public final String get_Language() {
    return this.language;
}

public final String get_Title() {
    return this.title;
}

public final String get_Url() {
    return this.url;
}

public final String get_Icon_url() {
    return this.icon_url;
}

public final String get_Logo_url() {
    return this.logo_url;
}

public final String get_Id() {
    return this.id;
}

public final String get_Modified() {
    return this.modified;
}

        }

แต่มันก็โยนฉันด้วย

com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2

ความคิดใดที่ฉันควรแก้ไข


12
@Soni - ไม่ถูกต้อง หากคุณไปที่ jsonlint.org และคัดลอก / วาง JSON ของเขาคุณจะเห็นว่าถูกต้อง
Brian Roach

@Soni - ไม่, ลบ "[" และ "]" แต่ยังคงเหมือนเดิม มันอาจจะมากกว่านี้เพราะสตริงที่ฉันมีมีหลายวัตถุไม่ใช่แค่วัตถุเดียว
Roger Travis

คุณjstringมีลักษณะอย่างไรที่คุณพูดถึงในรหัสของคุณ?
IgorGanapolsky

ฉันสังเกตความคิดหนึ่งเมื่อการตอบสนองกลับมาในอาร์เรย์แล้วลองใช้ในรายการมันแก้ปัญหาของฉัน
iamkdblue

คำตอบ:


331

ปัญหาคือคุณกำลังบอกว่าGsonคุณมีวัตถุประเภทของคุณ คุณทำไม่ได้ คุณมีวัตถุประเภทต่าง ๆ มากมาย คุณไม่สามารถลองและส่งผลลัพธ์เช่นนั้นและคาดหวังว่ามันจะทำงานได้อย่างน่าอัศจรรย์;)

คู่มือผู้ใช้สำหรับGsonอธิบายวิธีจัดการกับสิ่งนี้:

https://github.com/google/gson/blob/master/UserGuide.md

สิ่งนี้จะได้ผล:

ChannelSearchEnum[] enums = gson.fromJson(yourJson, ChannelSearchEnum[].class);

แต่นี่จะดีกว่า:

Type collectionType = new TypeToken<Collection<ChannelSearchEnum>>(){}.getType();
Collection<ChannelSearchEnum> enums = gson.fromJson(yourJson, collectionType);

อาจจะแน่นอน ในฐานะที่เป็นอาร์เรย์ของวัตถุประเภทนั้นจะยังคงอยู่ที่รันไทม์ดังนั้น gson จึงรู้ว่าต้องหาอะไร ความคิดที่ดี.
njzk2

3
+1 สำหรับTypoToken<Collection<Something>>- อย่าใช้อาร์เรย์เมื่อคุณมี Collection (subclasses) และ / หรือ Iterables
Philipp Reichart

คุณคิดว่าเป็นวิธีที่ถูกต้องในการแยกวิเคราะห์ obj / array ที่เลือกหรือไม่ ช่วยstackoverflow.com/questions/18140830/…
LOG_TAG

1
ถ้าเราต้องการทำให้มันเป็นสตริง; ตัวอย่างเช่นฉันสามารถเขียนบางอย่างเช่น String [] t = gson.fromJson (myJson, String []. class)
Sahin Yanlık

4
รู้สึกว่าคำตอบนี้ยังไม่เสร็จ !!
EngineSense

45

ปัญหาคือว่าคุณกำลังขอวัตถุประเภทChannelSearchEnumแต่สิ่งที่คุณมีจริงเป็นวัตถุประเภทList<ChannelSearchEnum>แต่สิ่งที่คุณจริงต้องเป็นวัตถุของพิมพ์

คุณสามารถบรรลุสิ่งนี้ด้วย:

Type collectionType = new TypeToken<List<ChannelSearchEnum>>(){}.getType();
List<ChannelSearchEnum> lcs = (List<ChannelSearchEnum>) new Gson()
               .fromJson( jstring , collectionType);

1
สิ่งที่ประเภทของTypeว่าคืออะไร? สิ่งที่จะนำเข้า
smatthewenglish

4
@ S.Matthew_English มีแนวโน้มมากที่สุดjava.lang.reflect.Type
Guillaume Polet

36

ในสตริง JSON ของฉันกรณี:

[{"category":"College Affordability",
  "uid":"150151",
  "body":"Ended more than $60 billion in wasteful subsidies for big banks and used the savings to put the cost of college within reach for more families.",
  "url":"http:\/\/www.whitehouse.gov\/economy\/middle-class\/helping middle-class-families-pay-for-college",
  "url_title":"ending subsidies for student loan lenders",
  "type":"Progress",
  "path":"node\/150385"}]

และฉันพิมพ์ "หมวดหมู่" และ "url_title" ใน recycleview

Datum.class

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

public class Datum {
@SerializedName("category")
@Expose
private String category;
@SerializedName("uid")
@Expose
private String uid;
@SerializedName("url_title")
@Expose
private String urlTitle;

/**
 * @return The category
 */
public String getCategory() {
    return category;
}

/**
 * @param category The category
 */
public void setCategory(String category) {
    this.category = category;
}

/**
 * @return The uid
 */
public String getUid() {
    return uid;
}

/**
 * @param uid The uid
 */
public void setUid(String uid) {
    this.uid = uid;
}

/**
 * @return The urlTitle
 */
public String getUrlTitle() {
    return urlTitle;
}

/**
 * @param urlTitle The url_title
 */
public void setUrlTitle(String urlTitle) {
    this.urlTitle = urlTitle;
}

}

RequestInterface

import java.util.List;

import retrofit2.Call;
import retrofit2.http.GET;

/**
 * Created by Shweta.Chauhan on 13/07/16.
 */

public interface RequestInterface {

   @GET("facts/json/progress/all")
   Call<List<Datum>> getJSON();
}

DataAdapter

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Shweta.Chauhan on 13/07/16.
 */

public class DataAdapter extends RecyclerView.Adapter<DataAdapter.MyViewHolder>{

private Context context;
private List<Datum> dataList;

public DataAdapter(Context context, List<Datum> dataList) {
    this.context = context;
    this.dataList = dataList;
}

@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.data,parent,false);
    return new MyViewHolder(view);
}

@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
    holder.categoryTV.setText(dataList.get(position).getCategory());
    holder.urltitleTV.setText(dataList.get(position).getUrlTitle());

}

@Override
public int getItemCount() {
    return dataList.size();
}

public class MyViewHolder extends RecyclerView.ViewHolder{

    public TextView categoryTV, urltitleTV;

    public MyViewHolder(View itemView) {
        super(itemView);
        categoryTV = (TextView) itemView.findViewById(R.id.txt_category);
        urltitleTV = (TextView)     itemView.findViewById(R.id.txt_urltitle);
    }
}
}

และในที่สุด MainActivity.java

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class MainActivity extends AppCompatActivity {

private RecyclerView recyclerView;
private DataAdapter dataAdapter;
private List<Datum> dataArrayList;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    initViews();
}

private void initViews(){
    recyclerView=(RecyclerView) findViewById(R.id.recycler_view);
    recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
    loadJSON();
}

private void loadJSON(){
    dataArrayList = new ArrayList<>();
    Retrofit retrofit=new Retrofit.Builder().baseUrl("https://www.whitehouse.gov/").addConverterFactory(GsonConverterFactory.create()).build();
    RequestInterface requestInterface=retrofit.create(RequestInterface.class);
    Call<List<Datum>> call= requestInterface.getJSON();
    call.enqueue(new Callback<List<Datum>>() {
        @Override
        public void onResponse(Call<List<Datum>> call, Response<List<Datum>> response) {
            dataArrayList = response.body();
            dataAdapter=new DataAdapter(getApplicationContext(),dataArrayList);
            recyclerView.setAdapter(dataAdapter);
        }

        @Override
        public void onFailure(Call<List<Datum>> call, Throwable t) {
            Log.e("Error",t.getMessage());
        }
    });
}
}

5
คำตอบที่ดีที่สุดสำหรับปัญหาประเภทนี้
Nicky Manali

4
สิ่งนี้จะตอบคำถามได้อย่างสมบูรณ์แบบโดยเฉพาะสำหรับผู้ใช้ติดตั้งเพิ่มเติม สำหรับผู้ที่ต้องการความชัดเจนส่วนที่คุณต้องการมากที่สุดคือการโทร <รายการ <ข้อมูล>> getJSON ();
Carlos Anyona

13

ทางเลือกอาจเป็น

เพื่อให้คำตอบของคุณดูเหมือน

myCustom_JSONResponse

{"master":[
   {
      "updated_at":"2012-03-02 21:06:01",
      "fetched_at":"2012-03-02 21:28:37.728840",
      "description":null,
      "language":null,
      "title":"JOHN",
      "url":"http://rus.JOHN.JOHN/rss.php",
      "icon_url":null,
      "logo_url":null,
      "id":"4f4791da203d0c2d76000035",
      "modified":"2012-03-02 23:28:58.840076"
   },
   {
      "updated_at":"2012-03-02 14:07:44",
      "fetched_at":"2012-03-02 21:28:37.033108",
      "description":null,
      "language":null,
      "title":"PETER",
      "url":"http://PETER.PETER.lv/rss.php",
      "icon_url":null,
      "logo_url":null,
      "id":"4f476f61203d0c2d89000253",
      "modified":"2012-03-02 23:28:57.928001"
   }
]
}

แทน

server_JSONResponse

[
   {
      "updated_at":"2012-03-02 21:06:01",
      "fetched_at":"2012-03-02 21:28:37.728840",
      "description":null,
      "language":null,
      "title":"JOHN",
      "url":"http://rus.JOHN.JOHN/rss.php",
      "icon_url":null,
      "logo_url":null,
      "id":"4f4791da203d0c2d76000035",
      "modified":"2012-03-02 23:28:58.840076"
   },
   {
      "updated_at":"2012-03-02 14:07:44",
      "fetched_at":"2012-03-02 21:28:37.033108",
      "description":null,
      "language":null,
      "title":"PETER",
      "url":"http://PETER.PETER.lv/rss.php",
      "icon_url":null,
      "logo_url":null,
      "id":"4f476f61203d0c2d89000253",
      "modified":"2012-03-02 23:28:57.928001"
   }
]

รหัส

  String server_JSONResponse =.... // the string in which you are getting your JSON Response after hitting URL
String myCustom_JSONResponse="";// in which we will keep our response after adding object element to it
     MyClass apiResponse = new MyClass();

     myCustom_JSONResponse="{\"master\":"+server_JSONResponse+"}";



    apiResponse = gson.fromJson(myCustom_JSONResponse, MyClass .class);

หลังจากนี้มันจะเป็นเพียงแค่อื่น ๆ GSON Parsing


จะเป็นอย่างไรถ้าฉันไม่สามารถเปลี่ยนรูปแบบ json ของฉันได้ ฉันกำลังใช้คำขอ gson ของวอลเล่ย์เพื่อตั้งคลาสโมเดลของฉัน ทำอย่างไร? ขอบคุณ
Kaveesh Kanwal

@KaveeshKanwal ลองใช้วิธีแก้ไขปัญหาอื่น ๆ ที่มีให้ในหัวข้อนี้นอกเหนือจากนี้ฉันไม่มีความคิด
DeltaCap019

8

ตามคู่มือผู้ใช้ GSONคุณไม่สามารถทำได้

ข้อ จำกัด ของคอลเลกชัน

สามารถทำให้เป็นอันดับของคอลเลกชันของวัตถุใด ๆ แต่ไม่สามารถทำการ deserialize จากมัน เนื่องจากไม่มีวิธีสำหรับผู้ใช้ในการระบุประเภทของวัตถุที่เกิดขึ้น


7
เขาไม่ได้มีการเก็บรวบรวมวัตถุพลเขามีคอลเลกชันของหนึ่งที่เฉพาะเจาะจงชนิดของวัตถุที่Gsonมีความสุขจะจัดการกับ
ไบรอันแมลงสาบ

ที่จริงฉันเริ่มต้นด้วยการเขียนคำตอบกับ TypeToken เช่นเดียวกับที่คุณทำ แต่เนื่องจากประเภททั่วไปไม่ได้ฝังตัวที่รันไทม์ฉันจึงไม่เห็นว่ามันจะทำงานอย่างไร (แม้ว่าฉันยังไม่ได้ทดสอบ)
njzk2

3

นี่เป็นรายการ Json array ดังนั้นจึงควรใช้ArrayListข้อมูลนี้เพื่อจัดการกับข้อมูล ในจุดปลาย API ของคุณเพิ่มรายการอาร์เรย์เช่นนี้

 @GET("places/")
Call<ArrayList<Place>> getNearbyPlaces(@Query("latitude") String latitude, @Query("longitude") String longitude);

1

คุณต้องแจ้งให้ Gson ทราบประเภทคำตอบเพิ่มเติมของคุณด้านล่าง

import com.google.common.reflect.TypeToken;
import java.lang.reflect.Type;


Type collectionType = new TypeToken<List<UserSite>>(){}.getType();
List<UserSite> userSites  = gson.fromJson( response.getBody() , collectionType);

1

ฉันไม่แน่ใจว่านี่เป็นวิธีที่ดีที่สุดในการใช้ GSON แต่ใช้งานได้สำหรับฉัน คุณสามารถใช้บางอย่างเช่นนี้ในMainActivity:

 public void readJson() {
    dataArrayList = new ArrayList<>();
    String json = "[\n" + IOHelper.getData(this) + "\n]\n";
    Log.d(TAG, json);
    try{
        JSONArray channelSearchEnums = new JSONArray(json);

        for(int i=0; i< channelSearchEnums.length(); i++)
        {
            JSONObject enum = channelSearchEnums.getJSONObject(i);
            ChannelSearchEnum channel = new ChannelSearchEnum(
                   enum.getString("updated_at"), enum.getString("fetched_at"),
                   enum.getString("description"), enum.getString("language"),
                   enum.getString("title"), enum.getString("url"),
                   enum.getString("icon_url"), enum.getString("logo_url"),
                   enum.getString("id"), enum.getString("modified"))         

                   dataArrayList.add(channel);
        }

         //The code and place you want to show your data            

    }catch (Exception e)
    {
        Log.d(TAG, e.getLocalizedMessage());
    }
}

คุณมีเพียงสาย แต่ถ้าคุณจะมีคู่หรือ int, คุณสามารถใส่getDoubleหรือgetIntมากเกินไป

วิธีการIOHelperเรียนคือถัดไป (ที่นี่เส้นทางจะถูกบันทึกในการจัดเก็บข้อมูลภายใน):

 public static String getData(Context context) {
    try {
        File f = new File(context.getFilesDir().getPath() + "/" + fileName);
        //check whether file exists
        FileInputStream is = new FileInputStream(f);
        int size = is.available();
        byte[] buffer = new byte[size];
        is.read(buffer);
        is.close();
        return new String(buffer);
    } catch (IOException e) {
        Log.e("TAG", "Error in Reading: " + e.getLocalizedMessage());
        return null;
    }
}

หากคุณต้องการข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้คุณสามารถดูวิดีโอนี้ที่ฉันได้รับรหัสreadJson(); และหัวข้อนี้getData()ที่ฉันได้รับรหัสของ


0

Kotlin:

var list=ArrayList<Your class name>()
val listresult: Array<YOUR CLASS NAME> = Gson().fromJson(
                YOUR JSON RESPONSE IN STRING,
                Array<Your class name>:: class.java)

list.addAll(listresult)

ฉันไม่ได้ลงคะแนนหรือลงคะแนนเพียงแก้ไขเท่านั้น
Shredator
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.