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

Kotlin中Retrofit响应无法映射到数据类返回Null问题

Retrofit调用API数据类返回Null问题

问题描述

使用Retrofit调用API时,日志中能看到完整的响应JSON,但数据类SolServices始终返回Null,Logcat无任何错误提示。

现有代码

Retrofit实例与接口

private val logger = HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)    

val client = OkHttpClient.Builder()
    .addInterceptor(logger)
    .connectTimeout(Duration.ZERO)
    .writeTimeout(5, TimeUnit.MINUTES)
    .readTimeout(5, TimeUnit.MINUTES)
    .build()    

private val retrofit = Retrofit.Builder()
    //.addConverterFactory(MoshiConverterFactory.create(moshi))
    .addConverterFactory(GsonConverterFactory.create())
    .baseUrl(BASE_URL)
    .client(client)
    .build()
   
interface OrderInfoApiService {
    @Headers("Content-Type: application/json; charset=utf-8")
    @POST("OrderInfo")
    suspend fun getOrderInfo(@Body orderInfoRequest: OrderingRequest): SolServices
}

object OrderInfoApi {
    val retrofitService: OrderInfoApiService by lazy {
        retrofit.create(OrderInfoApiService::class.java)
    }
}

数据类定义

SolServices.java

@Generated("jsonschema2pojo")
public class SolServices {

   @SerializedName("OrderingOrderInfoResponseStruct")
   @Expose
   private OrderingOrderInfoResponseStruct orderingOrderInfoResponseStruct;

   public OrderingOrderInfoResponseStruct getOrderingOrderInfoResponseStruct() {
       return orderingOrderInfoResponseStruct;
   }

   public void setOrderingOrderInfoResponseStruct(OrderingOrderInfoResponseStruct 
    orderingOrderInfoResponseStruct) {
    this.orderingOrderInfoResponseStruct = orderingOrderInfoResponseStruct;
  }
}

OrderingOrderInfoResponseStruct.java

@Generated("jsonschema2pojo")
public class OrderingOrderInfoResponseStruct {

    @SerializedName("deliveryAddresses")
    @Expose
    private DeliveryAddresses deliveryAddresses;
    @SerializedName("orderingGroups")
    @Expose
    private OrderingGroups orderingGroups;

    public DeliveryAddresses getDeliveryAddresses() {
        return deliveryAddresses;
    }

    public void setDeliveryAddresses(DeliveryAddresses deliveryAddresses) {
        this.deliveryAddresses = deliveryAddresses;
    }

    public OrderingGroups getOrderingGroups() {
        return orderingGroups;
    }

    public void setOrderingGroups(OrderingGroups orderingGroups) {
        this.orderingGroups = orderingGroups;
    }    
}

ViewModel调用代码

class LoginViewModel : ViewModel() {

    private val _orderData = MutableLiveData<SolServices>()
    val orderData: LiveData<SolServices> get() = _orderData

    fun getOrderInfo(orderSessionKey: OrderingRequest) {
        viewModelScope.launch {
            _orderInfoData.value = OrderInfoApi.retrofitService.getOrderInfo(orderInfoRequest = orderSessionKey)
        }
    }
}

API返回的JSON响应

{
  "OrderingOrderInfoResponseStruct": {
    "deliveryAddresses": {
      "OrderingDeliveryAddressStruct": [
        {
          "deliveryAddressNo": 5800009,
          "deliveryAddressName": "BASILDON & THURROCK NHS",
          "pointsOfService": {
            "OrderingPointOfServiceStruct": [
              {
                "pointOfServiceNo": 1,
                "pointOfServiceName": "A & E",
                "pointOfServiceDescription": "A & E 12",
                "pointOfServiceOrderingGroupNo": "580-1",
                "orders": {
                  "OrderingOrderStruct": [
                    {
                      "orderType": "inventory",
                      "orderDate": "2023-07-07",
                      "deliveryDate": "2023-07-07",
                      "orderStatus": 0,
                      "articles": {
                        "OrderingArticleStruct": [
                          {
                            "articleNo": 109842,
                            "articleDescription": "ESSENTIALS TOP SHEET S",
                            "articleSize": "",
                            "articleTargetQty": 385,
                            "articleMinQty": 0,
                            "articleMaxQty": 0,
                            "articleIntervalQty": 0
                          },
                          {
                            "articleNo": 103046,
                            "articleDescription": "ESSENTIALS PILLOWCASE",
                            "articleSize": "",
                            "articleTargetQty": 15,
                            "articleMinQty": 0,
                            "articleMaxQty": 0,
                            "articleIntervalQty": 0
                          },
                          {
                            "articleNo": 106856,
                            "articleDescription": "ESSENTIALS BATH TOWEL",
                            "articleSize": "",
                            "articleTargetQty": 24,
                            "articleMinQty": 0,
                            "articleMaxQty": 0,
                            "articleIntervalQty": 0
                          },
                          {
                            "articleNo": 106482,
                            "articleDescription": "ESSENTIALS BLANKET THERMAL BLUE",
                            "articleSize": "",
                            "articleTargetQty": 130,
                            "articleMinQty": 0,
                            "articleMaxQty": 0,
                            "articleIntervalQty": 0
                          },
                          {
                            "articleNo": 106812,
                            "articleDescription": "ESSENTIALS PATIENT MODESTY GOWN",
                            "articleSize": "",
                            "articleTargetQty": 65,
                            "articleMinQty": 0,
                            "articleMaxQty": 0,
                            "articleIntervalQty": 0
                          },
                          {
                            "articleNo": 106420,
                            "articleDescription": "ESSENTIALS PLASTIC BAGS WHITE",
                            "articleSize": "",
                            "articleTargetQty": 75,
                            "articleMinQty": 0,
                            "articleMaxQty": 0,
                            "articleIntervalQty": 0
                          },
                          {
                            "articleNo": 106458,
                            "articleDescription": "ESSENTIALS BAGS WATER SOLUBLE",
                            "articleSize": "",
                            "articleTargetQty": 25,
                            "articleMinQty": 0,
                            "articleMaxQty": 0,
                            "articleIntervalQty": 0
                          }
                        ]
                      }
                    }
                  ]
                }
              }
            ]
          }
        }
      ]
    },
    "orderingGroups": {
      "OrderingOrderingGroupStruct": [
        {
          "orderingGroupNo": "580-1",
          "orderingGroupDescription": "58000009 BASILDON OPD 1"
        },
        {
          "orderingGroupNo": "580-2",
          "orderingGroupDescription": "58000009 BASILDON OPD 2"
        },
        {
          "orderingGroupNo": "580-3",
          "orderingGroupDescription": "58000009 BASILDON OPD 3"
        },
        {
          "orderingGroupNo": "580-4",
          "orderingGroupDescription": "ROYALFREE TOWER BLOCK"
        },
        {
          "orderingGroupNo": "580-5",
          "orderingGroupDescription": "5800024 ROYAL FREE OPD 2"
        },
        {
          "orderingGroupNo": "580-6",
          "orderingGroupDescription": "5800024 ROYAL FREE OPD 3"
        }
      ]
    }
  }
}

问题原因

核心问题是数据类结构与JSON响应不匹配,具体表现:

  1. OrderingOrderInfoResponseStruct中的deliveryAddresses字段,JSON实际嵌套了OrderingDeliveryAddressStruct数组,但DeliveryAddresses类未对应该嵌套结构;
  2. orderingGroups字段对应JSON嵌套了OrderingOrderingGroupStruct数组,OrderingGroups类也未正确映射;
  3. 更深层级的pointsOfService、orders、articles存在同样的嵌套数组映射问题。

Gson解析时,若找不到字段映射关系会默认设为Null,且默认不抛出错误,这就是日志有响应但数据类全Null的原因。

修复步骤

1. 修正DeliveryAddresses类

对应JSON中的OrderingDeliveryAddressStruct数组:

@Generated("jsonschema2pojo")
public class DeliveryAddresses {

    @SerializedName("OrderingDeliveryAddressStruct")
    @Expose
    private List<OrderingDeliveryAddressStruct> orderingDeliveryAddressStruct;

    public List<OrderingDeliveryAddressStruct> getOrderingDeliveryAddressStruct() {
        return orderingDeliveryAddressStruct;
    }

    public void setOrderingDeliveryAddressStruct(List<OrderingDeliveryAddressStruct> orderingDeliveryAddressStruct) {
        this.orderingDeliveryAddressStruct = orderingDeliveryAddressStruct;
    }
}

同时创建OrderingDeliveryAddressStruct类映射数组对象:

@Generated("jsonschema2pojo")
public class OrderingDeliveryAddressStruct {

    @SerializedName("deliveryAddressNo")
    @Expose
    private Integer deliveryAddressNo;
    @SerializedName("deliveryAddressName")
    @Expose
    private String deliveryAddressName;
    @SerializedName("pointsOfService")
    @Expose
    private PointsOfService pointsOfService;

    // Getters and Setters
    public Integer getDeliveryAddressNo() {
        return deliveryAddressNo;
    }

    public void setDeliveryAddressNo(Integer deliveryAddressNo) {
        this.deliveryAddressNo = deliveryAddressNo;
    }

    public String getDeliveryAddressName() {
        return deliveryAddressName;
    }

    public void setDeliveryAddressName(String deliveryAddressName) {
        this.deliveryAddressName = deliveryAddressName;
    }

    public PointsOfService getPointsOfService() {
        return pointsOfService;
    }

    public void setPointsOfService(PointsOfService pointsOfService) {
        this.pointsOfService = pointsOfService;
    }
}

2. 修正OrderingGroups类

对应JSON中的OrderingOrderingGroupStruct数组:

@Generated("jsonschema2pojo")
public class OrderingGroups {

    @SerializedName("OrderingOrderingGroupStruct")
    @Expose
    private List<OrderingOrderingGroupStruct> orderingOrderingGroupStruct;

    public List<OrderingOrderingGroupStruct> getOrderingOrderingGroupStruct() {
        return orderingOrderingGroupStruct;
    }

    public void setOrderingOrderingGroupStruct(List<OrderingOrderingGroupStruct> orderingOrderingGroupStruct) {
        this.orderingOrderingGroupStruct = orderingOrderingGroupStruct;
    }
}

创建OrderingOrderingGroupStruct类:

@Generated("jsonschema2pojo")
public class OrderingOrderingGroupStruct {

    @SerializedName("orderingGroupNo")
    @Expose
    private String orderingGroupNo;
    @SerializedName("orderingGroupDescription")
    @Expose
    private String orderingGroupDescription;

    // Getters and Setters
    public String getOrderingGroupNo() {
        return orderingGroupNo;
    }

    public void setOrderingGroupNo(String orderingGroupNo) {
        this.orderingGroupNo = orderingGroupNo;
    }

    public String getOrderingGroupDescription() {
        return orderingGroupDescription;
    }

    public void setOrderingGroupDescription(String orderingGroupDescription) {
        this.orderingGroupDescription = orderingGroupDescription;
    }
}

3. 补全深层级映射类

按相同逻辑,补全PointsOfService、OrderingPointOfServiceStruct、Orders、OrderingOrderStruct、Articles、OrderingArticleStruct等类,确保每个嵌套数组都有对应的List<T>字段和实体类。

4. (可选)开启Gson严格模式排查问题

若后续仍有映射问题,可开启Gson严格模式让解析时抛出错误,方便定位:

val gson = GsonBuilder()
    .setStrictness(Strictness.STRICT)
    .create()

private val retrofit = Retrofit.Builder()
    .addConverterFactory(GsonConverterFactory.create(gson))
    .baseUrl(BASE_URL)
    .client(client)
    .build()

5. 修正ViewModel变量名错误

ViewModel中_orderData与赋值用的_orderInfoData变量名不一致,需修正:

fun getOrderInfo(orderSessionKey: OrderingRequest) {
    viewModelScope.launch {
        _orderData.value = OrderInfoApi.retrofitService.getOrderInfo(orderInfoRequest = orderSessionKey)
    }
}

验证方法

修复后重新调用API,可添加日志打印确认数据是否正常:

viewModelScope.launch {
    val result = OrderInfoApi.retrofitService.getOrderInfo(orderInfoRequest = orderSessionKey)
    Log.d("OrderInfo", "收货地址名称: ${result.getOrderingOrderInfoResponseStruct()?.getDeliveryAddresses()?.getOrderingDeliveryAddressStruct()?.get(0)?.getDeliveryAddressName()}")
    _orderData.value = result
}

内容的提问来源于stack exchange,提问作者Dean Ball

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 06:17:03