You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否使用单个类通过Retrofit解析不同JSON响应?如何构建该类?

Single POJO to Parse Multiple API Responses in Java (with Gson)

Since you're using Gson for deserialization (evident from @SerializedName and @Expose annotations), there are two clean approaches to handle both JSON response types with a single JsonResponse class. Let's break them down:

Approach 1: Type-Safe Generic Response + Custom Deserializer

This method keeps your existing DataSync class intact and pairs it with a corresponding DataWeather class, using a generic JsonResponse and custom deserializer to automatically pick the correct data type during parsing.

Step 1: Create Generic JsonResponse Class

Replace your specific JsonResponse classes with a generic version that works for any data type:

public class JsonResponse<T> {
    @SerializedName("success")
    @Expose
    private Boolean success;
    @SerializedName("data")
    @Expose
    private T data;

    // Getters and Setters
    public Boolean getSuccess() {
        return success;
    }

    public void setSuccess(Boolean success) {
        this.success = success;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}

Step 2: Add DataWeather Class for the First Response

Keep your existing DataSync class, and create a DataWeather class to map the first JSON structure:

// DataWeather.java
public class DataWeather {
    @SerializedName("weather")
    @Expose
    private List<Weather> weather;
    @SerializedName("total")
    @Expose
    private Integer total;

    // Getters and Setters
    public List<Weather> getWeather() {
        return weather;
    }

    public void setWeather(List<Weather> weather) {
        this.weather = weather;
    }

    public Integer getTotal() {
        return total;
    }

    public void setTotal(Integer total) {
        this.total = total;
    }

    // Inner class for weather items
    public static class Weather {
        @SerializedName("location")
        @Expose
        private String location;
        @SerializedName("condition")
        @Expose
        private String condition;

        // Getters and Setters
        public String getLocation() {
            return location;
        }

        public void setLocation(String location) {
            this.location = location;
        }

        public String getCondition() {
            return condition;
        }

        public void setCondition(String condition) {
            this.condition = condition;
        }
    }
}

Step 3: Implement Custom Deserializer

Create a deserializer that checks the fields in the data object to determine which data class to use:

public class JsonResponseDeserializer implements JsonDeserializer<JsonResponse<?>> {
    @Override
    public JsonResponse<?> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        JsonObject rootObject = json.getAsJsonObject();
        JsonResponse<?> response = new JsonResponse<>();
        
        // Parse success flag
        response.setSuccess(rootObject.get("success").getAsBoolean());
        
        // Check data fields to decide which type to parse
        JsonObject dataObject = rootObject.getAsJsonObject("data");
        if (dataObject.has("weather")) {
            DataWeather weatherData = context.deserialize(dataObject, DataWeather.class);
            response.setData(weatherData);
        } else if (dataObject.has("syncRequired")) {
            DataSync syncData = context.deserialize(dataObject, DataSync.class);
            response.setData(syncData);
        } else {
            throw new JsonParseException("Unrecognized data structure in API response");
        }
        
        return response;
    }
}

Step 4: Register Deserializer and Parse

Initialize Gson with the deserializer, then parse and handle your response:

// Set up Gson with custom deserializer
Gson gson = new GsonBuilder()
        .registerTypeAdapter(JsonResponse.class, new JsonResponseDeserializer())
        .create();

// Parse JSON string
JsonResponse<?> apiResponse = gson.fromJson(yourJsonString, JsonResponse.class);

// Handle data based on type
if (apiResponse.getData() instanceof DataWeather) {
    DataWeather weatherData = (DataWeather) apiResponse.getData();
    // Work with weather list and total count
} else if (apiResponse.getData() instanceof DataSync) {
    DataSync syncData = (DataSync) apiResponse.getData();
    // Check sync requirement and location count
}

Approach 2: Single Data Class with Optional Fields

If you prefer a simpler setup (at the cost of slightly less type safety), create a single Data class that includes all possible fields from both responses. Gson automatically ignores missing fields during parsing.

Step 1: Create Unified Data Class

public class Data {
    @SerializedName("weather")
    @Expose
    private List<Weather> weather;
    @SerializedName("total")
    @Expose
    private Integer total;
    @SerializedName("syncRequired")
    @Expose
    private Boolean syncRequired;
    @SerializedName("totalOfLocations")
    @Expose
    private Integer totalOfLocations;

    // Getters and Setters for all fields
    public List<Weather> getWeather() { return weather; }
    public void setWeather(List<Weather> weather) { this.weather = weather; }
    public Integer getTotal() { return total; }
    public void setTotal(Integer total) { this.total = total; }
    public Boolean isSyncRequired() { return syncRequired; }
    public void setSyncRequired(Boolean syncRequired) { this.syncRequired = syncRequired; }
    public Integer getTotalOfLocations() { return totalOfLocations; }
    public void setTotalOfLocations(Integer totalOfLocations) { this.totalOfLocations = totalOfLocations; }

    // Inner Weather class
    public static class Weather {
        @SerializedName("location")
        @Expose
        private String location;
        @SerializedName("condition")
        @Expose
        private String condition;

        // Getters and Setters
        public String getLocation() { return location; }
        public void setLocation(String location) { this.location = location; }
        public String getCondition() { return condition; }
        public void setCondition(String condition) { this.condition = condition; }
    }
}

Step 2: Simplified JsonResponse Class

public class JsonResponse {
    @SerializedName("success")
    @Expose
    private Boolean success;
    @SerializedName("data")
    @Expose
    private Data data;

    // Getters and Setters
    public Boolean getSuccess() { return success; }
    public void setSuccess(Boolean success) { this.success = success; }
    public Data getData() { return data; }
    public void setData(Data data) { this.data = data; }
}

Step 3: Parse and Handle Data

Gson gson = new Gson();
JsonResponse response = gson.fromJson(yourJsonString, JsonResponse.class);

// Check which fields are present to determine response type
if (response.getData().getWeather() != null) {
    // Handle weather response
} else if (response.getData().isSyncRequired() != null) {
    // Handle sync response
}

Which Approach to Choose?

  • Approach 1 is better for type safety and scalability, especially if you expect more response types in the future. It keeps your data models clean and separated.
  • Approach 2 is quicker to implement for simple cases where you only have two response types and don't mind checking for null fields.

内容的提问来源于stack exchange,提问作者Harith Haziq

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 06:56:40