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

Android Retrofit响应解析错误求助:两种响应格式适配问题

Hey there! Let's tackle this Retrofit response parsing issue you're facing. The core problem here is that your API returns two different formats for the message field—an object on success, a plain string on error—which breaks fixed POJO parsing. Here are two practical, clean approaches to handle this:

Approach 1: Use JsonElement for Flexible Message Parsing

This is the simplest quick fix. We'll define the message field as a JsonElement (from Gson) to accept both object and string types, then manually parse it based on the response's code or status.

Step 1: Create a Unified Response POJO

import com.google.gson.JsonElement;

public class ApiResponse {
    private Results results;

    public Results getResults() {
        return results;
    }

    public static class Results {
        private JsonElement message; // Accepts any JSON type
        private String status;
        private int code;

        // Getters for all fields
        public JsonElement getMessage() { return message; }
        public String getStatus() { return status; }
        public int getCode() { return code; }
    }
}

// Separate POJO for the success message object
public class SuccessMessage {
    private long en;
    private String ete;
    private String vto;
    private boolean er;

    // Getters for all fields
}

Step 2: Parse the Response Conditionally

When handling the Retrofit callback, check the response status/code to decide how to parse the message:

call.enqueue(new Callback<ApiResponse>() {
    @Override
    public void onResponse(Call<ApiResponse> call, Response<ApiResponse> response) {
        if (response.isSuccessful()) {
            ApiResponse.Results results = response.body().getResults();
            
            if (results.getCode() == 200 && "Success".equals(results.getStatus())) {
                // Parse message as the success object
                SuccessMessage successMsg = new Gson().fromJson(results.getMessage(), SuccessMessage.class);
                // Do something with successMsg (e.g., access successMsg.getEn())
            } else if (results.getCode() == 204 && "No Content".equals(results.getStatus())) {
                // Parse message as a string
                String errorMsg = results.getMessage().getAsString();
                // Handle the error case
            }
        }
    }

    @Override
    public void onFailure(Call<ApiResponse> call, Throwable t) {
        // Handle network failures
    }
});
Approach 2: Custom Gson TypeAdapter (Automated Parsing)

For a more elegant, automated solution, create a custom TypeAdapter that detects the message type and parses it into the appropriate class. This avoids manual parsing in every callback.

Step 1: Define a Sealed Message Class & TypeAdapter

import com.google.gson.*;
import java.io.IOException;

public class MessageTypeAdapter extends TypeAdapter<Message> {
    private final Gson gson = new Gson();

    @Override
    public void write(JsonWriter out, Message value) throws IOException {
        // Only needed if you're sending requests with this type; skip if not
        gson.toJson(value, Message.class, out);
    }

    @Override
    public Message read(JsonReader in) throws IOException {
        JsonToken token = in.peek();
        if (token == JsonToken.STRING) {
            // Error case: message is a string
            return new ErrorMessage(in.nextString());
        } else if (token == JsonToken.BEGIN_OBJECT) {
            // Success case: message is an object
            return gson.fromJson(in, SuccessMessage.class);
        }
        throw new JsonParseException("Unexpected token type for 'message' field: " + token);
    }

    // Abstract base class for messages
    public abstract static class Message {}

    // Success message implementation
    public static class SuccessMessage extends Message {
        private long en;
        private String ete;
        private String vto;
        private boolean er;

        // Getters for all fields
    }

    // Error message implementation
    public static class ErrorMessage extends Message {
        private final String message;

        public ErrorMessage(String message) {
            this.message = message;
        }

        public String getMessage() {
            return message;
        }
    }
}

Step 2: Register the TypeAdapter with Retrofit

Add the custom Gson instance to your Retrofit setup:

Gson customGson = new GsonBuilder()
        .registerTypeAdapter(MessageTypeAdapter.Message.class, new MessageTypeAdapter())
        .create();

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl(YOUR_BASE_URL)
        .addConverterFactory(GsonConverterFactory.create(customGson))
        .build();

Step 3: Update the Response POJO

Now you can use the Message type directly in your response class:

public class ApiResponse {
    private Results results;

    public Results getResults() {
        return results;
    }

    public static class Results {
        private MessageTypeAdapter.Message message;
        private String status;
        private int code;

        // Getters for all fields
    }
}

Step 4: Handle the Response Cleanly

No more manual parsing—just check the message type:

call.enqueue(new Callback<ApiResponse>() {
    @Override
    public void onResponse(Call<ApiResponse> call, Response<ApiResponse> response) {
        if (response.isSuccessful()) {
            ApiResponse.Results results = response.body().getResults();
            
            if (results.getMessage() instanceof MessageTypeAdapter.SuccessMessage) {
                MessageTypeAdapter.SuccessMessage successMsg = (MessageTypeAdapter.SuccessMessage) results.getMessage();
                // Handle success
            } else if (results.getMessage() instanceof MessageTypeAdapter.ErrorMessage) {
                MessageTypeAdapter.ErrorMessage errorMsg = (MessageTypeAdapter.ErrorMessage) results.getMessage();
                // Handle error
            }
        }
    }

    @Override
    public void onFailure(Call<ApiResponse> call, Throwable t) {
        // Handle network failures
    }
});

A quick note: If you have control over the backend, it's always better to standardize the response format (e.g., make message always an object with a text field for errors) to avoid these parsing hoops. But if that's not an option, either of these methods will work perfectly.

内容的提问来源于stack exchange,提问作者mavilla vishnu vardhan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 07:41:25