GSON melempar "Diharapkan BEGIN_OBJECT tetapi apakah BEGIN_ARRAY"?

295

Saya mencoba mengurai string JSON seperti ini

[
   {
      "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"
   }
]

ke dalam daftar objek.

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

Ini kelas objek yang saya gunakan.

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;
}

        }

Tapi itu membuatku senang

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

Ada ide bagaimana saya harus memperbaikinya?

Roger Travis
sumber
12
@Soni - itu tidak benar. Jika Anda pergi ke jsonlint.org dan menyalin / menempelkan JSON-nya, Anda akan melihat bahwa itu valid.
Brian Roach
@Soni - tidak, menghapus "[" dan "]", tetapi masih sama. tebak itu mungkin lebih karena string yang saya miliki berisi beberapa objek, bukan hanya satu.
Roger Travis
Seperti apa jstringpenampilan Anda di kode Anda?
IgorGanapolsky
Saya mengamati satu pemikiran, ketika respon kembali dalam array kemudian mencoba untuk mengambil dalam Daftar, itu menyelesaikan masalah saya.
iamkdblue

Jawaban:

331

Masalahnya adalah Anda mengatakan GsonAnda memiliki objek tipe Anda. Kamu tidak. Anda memiliki berbagai objek tipe Anda. Anda tidak bisa hanya mencoba dan memberikan hasil seperti itu dan berharap itu bekerja secara ajaib;)

Panduan pengguna untuk GsonMenjelaskan cara menangani ini:

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

Ini akan berhasil:

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

Tapi ini lebih baik:

Type collectionType = new TypeToken<Collection<ChannelSearchEnum>>(){}.getType();
Collection<ChannelSearchEnum> enums = gson.fromJson(yourJson, collectionType);
Brian Roach
sumber
mungkin memang. sebagai array objek, tipe dipertahankan pada saat runtime sehingga gson tahu apa yang harus dicari. ide bagus.
njzk2
3
+1 untuk TypoToken<Collection<Something>>- jangan gunakan array ketika Anda dapat memiliki Collection (subclasses) dan / atau Iterables.
Philipp Reichart
Apakah Anda pikir itu adalah metode yang tepat untuk mengurai objek / array yang dipilih? help stackoverflow.com/questions/18140830/…
LOG_TAG
1
Bagaimana jika kita ingin membuatnya dengan tali; Misalnya saya dapat menulis sesuatu seperti String [] t = gson.fromJson (myJson, String []. Class)
Sahin Yanlık
4
Merasa jawaban ini belum selesai !!
EngineSense
45

Masalahnya adalah Anda meminta objek bertipe ChannelSearchEnumtetapi yang sebenarnya Anda miliki adalah objek bertipe List<ChannelSearchEnum>.

Anda dapat mencapai ini dengan:

Type collectionType = new TypeToken<List<ChannelSearchEnum>>(){}.getType();
List<ChannelSearchEnum> lcs = (List<ChannelSearchEnum>) new Gson()
               .fromJson( jstring , collectionType);
Guillaume Polet
sumber
1
seperti apa Typeitu? apa yang harus diimpor?
smatthewenglish
4
@ S.Matthew_English kemungkinan besarjava.lang.reflect.Type
Guillaume Polet
36

Dalam string JSON kasus saya:

[{"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"}]

dan saya mencetak "kategori" dan "url_title" di 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;
}

}

Minta Permukaan

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);
    }
}
}

dan akhirnya 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());
        }
    });
}
}
Shweta Chauhan
sumber
5
jawaban terbaik untuk jenis masalah seperti itu
Nicky Manali
4
Ini menjawab pertanyaan dengan sempurna terutama untuk pengguna retrofit. Bagi siapa pun yang mencari kejelasan, bagian yang paling Anda butuhkan adalah Panggil <Daftar <Data>> getJSON ();
Carlos Anyona
13

Alternatifnya bisa

untuk membuat respons Anda terlihat seperti

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"
   }
]
}

dari pada

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"
   }
]

KODE

  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);

Setelah ini akan menjadi yang lainnya GSON Parsing

DeltaCap019
sumber
bagaimana jika saya tidak dapat mengubah format json saya? Saya menggunakan permintaan gson volley untuk mengatur kelas model saya. Bagaimana cara melakukannya? Terima kasih
Kaveesh Kanwal
@KaveeshKanwal mencoba solusi lain yang disediakan di utas ini, selain ini saya tidak tahu
DeltaCap019
8

menurut panduan Pengguna GSON , Anda tidak bisa.

Keterbatasan Koleksi

Dapat membuat serial koleksi benda yang sewenang-wenang tetapi tidak dapat membatalkan deserialisasi darinya. Karena tidak ada cara bagi pengguna untuk menunjukkan jenis objek yang dihasilkan

njzk2
sumber
7
Dia tidak memiliki koleksi objek yang berubah-ubah, dia memiliki koleksi satu jenis objek spesifik yang Gsondengan senang hati akan berurusan dengannya
Brian Roach
sebenarnya, saya mulai dengan menulis jawaban dengan TypeToken seperti yang Anda lakukan, tetapi karena tipe generik tidak tertanam pada saat runtime, saya tidak melihat bagaimana itu bisa bekerja. (meskipun saya belum mengujinya).
njzk2
3

Ini terlihat seperti daftar array Json. Oleh karena itu yang terbaik digunakan ArrayListuntuk menangani data. Di titik akhir api Anda, tambahkan daftar array seperti ini

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

Anda perlu memberi tahu Gson jenis respons tambahan seperti di bawah ini

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);
Pravin
sumber
1

Saya tidak yakin apakah ini cara terbaik untuk menggunakan GSON, tetapi bekerja untuk saya. Anda dapat menggunakan beberapa seperti ini di 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());
    }
}

Anda hanya memiliki string, tetapi jika Anda memiliki dobel atau int, Anda bisa memasukkan getDoubleatau getIntjuga.

Metode IOHelperkelas adalah yang berikutnya (Di sini, path disimpan di Penyimpanan internal):

 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;
    }
}

Jika Anda ingin informasi lebih lanjut tentang ini, Anda dapat melihat video ini , tempat saya mendapatkan kode readJson(); dan utas ini tempat saya mendapatkan kode getData().

PJ Alzab
sumber
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)
Abhay kumar bhumihar
sumber
Saya tidak mengungguli atau menurunkan suara apa pun, hanya diedit.
Shredator