GSON throwing “Expected Expected a name but was NUMBER at line 1 column 8”?

后端 未结 3 1686
心在旅途
心在旅途 2021-01-11 23:11

I\'m trying to parse a JSON string like this one ( generated URL with http://www.json-generator.com)

{
\"total\": 86, 
\"jsonrpc\": \"2.0\", 
\"id\": 1, 
\         


        
相关标签:
3条回答
  • 2021-01-11 23:38

    I am also face the same problem. I found that, issue was every if condition I am getting the jsonReader.nextName(). It is not correct way. I think your also doing the same way.

    From your code these two lines create the problem.

      // here the jsonReader moving one step.
      Log.d("nextName", jsonReader.nextName());
    
      //again your trying to getting the "jsonReader.nextName()" it is wrong in the above line already you got the name and reader move to next line. So  Exception may be comes here.                                    
       String name = jsonReader.nextName();   
    

    we should use "jsonReader.nextName()" one time only for each iteration in while loop like

     while (reader.hasNext())
     {
    
                String name=reader.nextName();
                if(name.equals(Constants.AUTH)){
                    authDetails.setAuth(reader.nextString());
    
                }else if(name.equals(Constants.STATUS)){
                    authDetails.setStatus(reader.nextInt());
                }else if(name.equals(Constants.MESSAGE)){
                    authDetails.setMessage(reader.nextString());
                }else {
                    reader.skipValue();
                }
    
        }
    
    0 讨论(0)
  • 2021-01-11 23:55

    The problem in your code was that you loop on names (json keys):

    while (jsonReader.hasNext()) {
    

    you get the next name:

    String name = jsonReader.nextName();
    

    but then you consume the value only if this name is equal to result.

    Think of the JsonReader as a way to move a cursor forward in your json: reading it token by token. Every command you give to it either read what the cursor is pointing to or move the cursor, sometimes you can move the cursor and read the value with a single command (like with nextName()).

    When the name is not result the jsonReader stay in the position where you left it: the name or key you just read with nextName().

    So the next time it calls nextName() the cursor move from the key to the value (next) and it expect to find a name and instead it found the value of the previous name, in your case NUMBER because the first value in your json is a number (name: "total", value: 56).

    if you are not reading the value because you don't care about it you should call

    jsonReader.skipValue();
    

    meaning you should change your code in

    if (name.equals("result")) {
      // read it
    } else {
      jsonReader.skipValue();
    }
    

    That said: you should either use annotation or, if you can't for some reason, register one or more TypeAdapter for the job of parsing your custom objects.

    The code inside those adapter is very similar to the one you wrote but it is limited to a single part of the json that match your object.

    So for example, if you create a class CountriesResult containing your total, and result of type List<Country>

    public class CountriesResult {
      private int total;
      @SerializedName("result")
      private List<Country> countries;
    }
    

    You already have a class for Country with the fields you need.

    Then you ask GSon to parse your CountriesResult object it will automatically parse it.

    gson.fromJson(jsonString, CountriesResult.class);
    

    If you need to parse Country in a custom way you just need a TypeAdatper for Country, see this example. And to register the type adapter or use the @JsonAdapter annotation.

    0 讨论(0)
  • 2021-01-11 23:55

    If you're going to use JsonReader and parse the stream manually, you don't use the automatic deserialization via Gson.fromJson().

    You either need to extract the fields from each object while traversing that array once you're in your loop, or simply use the automatic deserialization with an appropriate class (which, honestly, is what you should be doing):

    class Response {
        private int total;
        private String jsonrpc;
        private int id;
        private List<Country> result;
    
       // getters and setters ...
    }
    

    And then simply:

    InputStreamReader isr = new InputStreamReader(response.getEntity()
                                    .getContent(), "UTF-8"));
    Response r = gson.fromJson(isr, Response.class);
    
    0 讨论(0)
提交回复
热议问题