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响应不匹配,具体表现:
OrderingOrderInfoResponseStruct中的deliveryAddresses字段,JSON实际嵌套了OrderingDeliveryAddressStruct数组,但DeliveryAddresses类未对应该嵌套结构;orderingGroups字段对应JSON嵌套了OrderingOrderingGroupStruct数组,OrderingGroups类也未正确映射;- 更深层级的
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
相关产品推荐
相关产品推荐

