【Android】Reading a NULL string not supported here. Expected BEGIN_OBJECT but was STRING...

Problem Description

I encountered a problem when using Retrofit to initiate network requests. The console became popular and the following error message was continuously output:

Parcel: Reading a NULL string not supported here.


Cause Analysis

In the request callback processing Retrofit, use System.out.println(t.getMessage()) to print exception information.

@Override
public void onFailure(Call<Result<List<Animal>>> call, Throwable t) {
    
    
    System.out.println(t.getMessage());
}

By printing exception information, the following errors are found:

java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 230 path $.data[0].updateTime
java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 195 path $.data[0].createTime

According to the error message analysis, the problem occurs when using Retrofit combined with GsonConverterFactory to parse JSON data containing LocalDateTime type createTime and updateTime. This error usually means that the JSON data does not conform to the data structure expected by the code. The code expected an object (BEGIN_OBJECT) but actually encountered a string (STRING).

Entity class

json

Since LocalDateTime is not a type supported by Gson by default, a custom adapter needs to be used to solve this problem.


solution

  1. Create a custom Gson adapter to handle the LocalDateTime type. This can be achieved by extending Gson's TypeAdapter. Create a LocalDateTimeAdapter class.
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class LocalDateTimeAdapter extends TypeAdapter<LocalDateTime> {
    
    

    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE_TIME;

    @Override
    public void write(JsonWriter out, LocalDateTime value) throws IOException {
    
    
        if (value != null) {
    
    
            out.value(FORMATTER.format(value));
        } else {
    
    
            out.nullValue();
        }
    }

    @Override
    public LocalDateTime read(JsonReader in) throws IOException {
    
    
        if (in.hasNext()) {
    
    
            String value = in.nextString();
            return LocalDateTime.parse(value, FORMATTER);
        } else {
    
    
            return null;
        }
    }
}

  1. When creating Retrofit, use GsonBuilder to register the custom adapter into Gson. You can create a RetrofitBuilder class that is used to create Retrofit instances.
import com.example.pawprint.adapter.LocalDateTimeAdapter;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import java.time.LocalDateTime;

import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class RetrofitBuilder {
    
    
    public static Retrofit build(String baseUrl) {
    
    
        // 创建 Gson 实例
        Gson gson = new GsonBuilder()
                .registerTypeAdapter(LocalDateTime.class, new LocalDateTimeAdapter())
                .create();

        // 创建 Retrofit 实例
        return new Retrofit.Builder()
                .baseUrl(baseUrl)
                .addConverterFactory(GsonConverterFactory.create(gson))
                .build();

    }
}
  1. Just call the build static method of RetrofitBuilder directly where you need to create a Retrofit instance.
 String baseUrl = getString(R.string.base_url);
 retrofit = RetrofitBuilder.build(baseUrl);

After the above processing, the problem is solved, Retrofit no longer reports an error, and the data of createTime and updateTime can be obtained normally.

Guess you like

Origin blog.csdn.net/qq_34988204/article/details/135005631