Retrofit结合RxJava时Json序列化异常,RouteSchedule模型为空求助
route-schedule Array with Retrofit & RxJava Hey there! Let's work through this empty RouteSchedule model issue you're facing. The root problem here is almost certainly Gson not correctly locating the nested route-schedule array in your API response to map it to your model. Here are a few practical solutions to get your data loading properly:
1. Define an Outer Response Wrapper Class (Simplest Approach)
First, let's assume your API returns a structure like this (common for nested data):
{ "meta": { /* some metadata */ }, "route-schedule": [ { "stop-id": "123", "arrival-time": "08:00", ... } ] }
Your current Retrofit interface is probably trying to return Single<RouteSchedule> directly, but Gson can't skip the outer wrapper to reach the array. Instead, create a dedicated class to represent the full API response:
public class RouteScheduleApiResponse { // Use @SerializedName to match the exact key from the API (including hyphens) @SerializedName("route-schedule") private List<RouteSchedule> routeScheduleList; // Getter for the schedule list public List<RouteSchedule> getRouteScheduleList() { return routeScheduleList; } }
Then update your Retrofit interface to return this wrapper class:
public interface TransitApi { @GET("your-endpoint") Single<RouteScheduleApiResponse> getRouteSchedule(); }
When you subscribe, you can extract the array directly from the wrapper:
transitApi.getRouteSchedule() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(response -> { List<RouteSchedule> schedules = response.getRouteScheduleList(); // Use your schedule data here }, error -> { // Handle error });
2. Use a Custom Gson Deserializer (No Wrapper Class Needed)
If you don't want to add a wrapper class, you can create a custom deserializer to tell Gson exactly where to find the route-schedule array:
public class RouteScheduleDeserializer implements JsonDeserializer<List<RouteSchedule>> { @Override public List<RouteSchedule> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { // Navigate to the nested "route-schedule" array in the response JsonObject rootObject = json.getAsJsonObject(); JsonArray scheduleArray = rootObject.getAsJsonArray("route-schedule"); // Let Gson handle mapping the array items to RouteSchedule objects return context.deserialize(scheduleArray, new TypeToken<List<RouteSchedule>>(){}.getType()); } }
Next, register this deserializer when building your Retrofit instance:
// Build Gson with the custom deserializer Gson customGson = new GsonBuilder() .registerTypeAdapter( new TypeToken<List<RouteSchedule>>(){}.getType(), new RouteScheduleDeserializer() ) .create(); // Create Retrofit with the custom Gson converter Retrofit retrofit = new Retrofit.Builder() .baseUrl(YOUR_BASE_URL) .addConverterFactory(GsonConverterFactory.create(customGson)) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build();
Now your Retrofit interface can return Single<List<RouteSchedule>> directly, and Gson will automatically extract the nested array:
public interface TransitApi { @GET("your-endpoint") Single<List<RouteSchedule>> getRouteSchedule(); }
3. Double-Check Your RouteSchedule Model Annotations
Don't overlook the basics! Make sure every field in your RouteSchedule class uses @SerializedName to match the exact key names from the API (especially those with hyphens, like stop-name or departure-time). Gson won't automatically map hyphenated keys to camelCase variable names unless you explicitly configure it:
public class RouteSchedule { @SerializedName("stop-id") private String stopId; @SerializedName("arrival-time") private String arrivalTime; // Add other fields with matching @SerializedName annotations // Getters and setters }
If you have a lot of hyphenated keys, you can also configure Gson to handle this automatically:
Gson gson = new GsonBuilder() .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_DASHES) .create();
But using @SerializedName is more explicit and less error-prone if your API has mixed naming conventions.
Quick Debugging Tip
Add the HttpLoggingInterceptor to your Retrofit setup to print the raw API response. This will let you confirm that the route-schedule array actually exists in the response and matches the structure you're expecting:
HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); logging.setLevel(HttpLoggingInterceptor.Level.BODY); OkHttpClient client = new OkHttpClient.Builder() .addInterceptor(logging) .build(); // Add this client to your Retrofit builder Retrofit retrofit = new Retrofit.Builder() .client(client) // ... other configs .build();
Any of these approaches should fix the empty model issue. Start with the wrapper class if you want a straightforward solution, or use the custom deserializer if you prefer to keep your interface clean.
内容的提问来源于stack exchange,提问作者Beraki

