如何将含空值为false的复杂JSON反序列化为C#对象?
问题描述
从外部API获取JSON数据时,空值统一用false表示,但非空字段的类型多样:
- 如
product_id非空时是数组([7800,"Bananenblad Naturel - 484"]),空值时为false picking_date非空时是日期字符串("2023-08-11 10:10:39"),空值时为falseentrepreneur非空时是字符串,空值时为falseproduct_uom_qty非空时是数值,空值时为false
尝试过常规JSON转换器配置、反序列化忽略错误等方法,仍无法完成正常反序列化,求可行方案。
完整响应示例:
{ "jsonrpc": "2.0", "id": null, "result": [{ "id": 3529, "product_id": [ 6000, "484" ], "entrepreneur": false, "deceased_name": false, "case_number": false, "product_uom_qty": 1.0, "picking_date_to": false, "picking_date_from": false, "write_date": "2023-08-11 10:10:39", "create_date": "2021-03-06 16:38:57", "partner_id": [ 1000, "Zeeland" ], "picking_id": [ 57, "00045" ], "picking_state": "cancel", "batch_id": false }, { "id": 3710, "product_id": [ 7244, "143 (Inwendig 195 cm, Inwendig 56 cm, Nova - 23 Ongebleekt katoen met koord)" ], "entrepreneur": false, "deceased_name": false, "case_number": false, "product_uom_qty": 1.0, "picking_date_to": false, "picking_date_from": false, "write_date": "2023-08-11 10:10:39", "create_date": "2021-03-11 21:33:06", "partner_id": [ 108116, "Afgehaald" ], "picking_id": [ 78, "00054" ], "picking_state": "cancel", "batch_id": false } ] }
解决方案
核心思路是自定义字段级别的反序列化逻辑,针对每个字段的类型,判断值是否为false,如果是则映射为对应类型的空值(如None、null),否则按正常类型解析。
1. Python(使用Pydantic)
Pydantic支持自定义字段验证器,适配这种场景:
from pydantic import BaseModel, validator from typing import Optional, List, Union from datetime import datetime class ApiItem(BaseModel): id: int product_id: Optional[List[Union[int, str]]] entrepreneur: Optional[str] deceased_name: Optional[str] case_number: Optional[str] product_uom_qty: Optional[float] picking_date_to: Optional[datetime] picking_date_from: Optional[datetime] write_date: datetime create_date: datetime partner_id: List[Union[int, str]] picking_id: List[Union[int, str]] picking_state: str batch_id: Optional[List[Union[int, str]]] # 通用验证器:处理false转空值 @validator('product_id', 'entrepreneur', 'deceased_name', 'case_number', 'product_uom_qty', 'picking_date_to', 'picking_date_from', 'batch_id', pre=True) def handle_false_as_null(cls, v): if v is False: return None return v # 日期字段额外处理格式 @validator('picking_date_to', 'picking_date_from', 'write_date', 'create_date', pre=True) def parse_datetime(cls, v): if isinstance(v, str): return datetime.strptime(v, "%Y-%m-%d %H:%M:%S") return v # 解析示例 import json response_json = """上述完整JSON字符串""" data = json.loads(response_json) items = [ApiItem(**item) for item in data['result']]
2. C#(使用Newtonsoft.Json)
自定义JsonConverter处理字段逻辑:
using Newtonsoft.Json; using System; using System.Collections.Generic; public class ApiItem { public int Id { get; set; } [JsonConverter(typeof(FalseToNullConverter<List<object>>))] public List<object> ProductId { get; set; } [JsonConverter(typeof(FalseToNullConverter<string>))] public string Entrepreneur { get; set; } [JsonConverter(typeof(FalseToNullConverter<string>))] public string DeceasedName { get; set; } [JsonConverter(typeof(FalseToNullConverter<string>))] public string CaseNumber { get; set; } [JsonConverter(typeof(FalseToNullConverter<double>))] public double? ProductUomQty { get; set; } [JsonConverter(typeof(FalseToNullDateTimeConverter))] public DateTime? PickingDateTo { get; set; } [JsonConverter(typeof(FalseToNullDateTimeConverter))] public DateTime? PickingDateFrom { get; set; } [JsonConverter(typeof(CustomDateTimeConverter))] public DateTime WriteDate { get; set; } [JsonConverter(typeof(CustomDateTimeConverter))] public DateTime CreateDate { get; set; } public List<object> PartnerId { get; set; } public List<object> PickingId { get; set; } public string PickingState { get; set; } [JsonConverter(typeof(FalseToNullConverter<List<object>>))] public List<object> BatchId { get; set; } } // 通用false转空值转换器 public class FalseToNullConverter<T> : JsonConverter<T> { public override T ReadJson(JsonReader reader, Type objectType, T existingValue, bool hasExistingValue, JsonSerializer serializer) { if (reader.Value is bool boolVal && boolVal == false) { return default; } return serializer.Deserialize<T>(reader); } public override void WriteJson(JsonWriter writer, T value, JsonSerializer serializer) { serializer.Serialize(writer, value); } } // 日期字段专用转换器 public class FalseToNullDateTimeConverter : JsonConverter<DateTime?> { public override DateTime? ReadJson(JsonReader reader, Type objectType, DateTime? existingValue, bool hasExistingValue, JsonSerializer serializer) { if (reader.Value is bool boolVal && boolVal == false) { return null; } if (reader.Value is string str) { return DateTime.ParseExact(str, "yyyy-MM-dd HH:mm:ss", null); } return null; } public override void WriteJson(JsonWriter writer, DateTime? value, JsonSerializer serializer) { serializer.Serialize(writer, value?.ToString("yyyy-MM-dd HH:mm:ss")); } } public class CustomDateTimeConverter : JsonConverter<DateTime> { public override DateTime ReadJson(JsonReader reader, Type objectType, DateTime existingValue, bool hasExistingValue, JsonSerializer serializer) { return DateTime.ParseExact(reader.Value.ToString(), "yyyy-MM-dd HH:mm:ss", null); } public override void WriteJson(JsonWriter writer, DateTime value, JsonSerializer serializer) { writer.WriteValue(value.ToString("yyyy-MM-dd HH:mm:ss")); } } // 解析示例 string jsonStr = "上述完整JSON字符串"; var response = JsonConvert.DeserializeObject<ApiResponse>(jsonStr); public class ApiResponse { public string Jsonrpc { get; set; } public object Id { get; set; } public List<ApiItem> Result { get; set; } }
3. Java(使用Jackson)
通过自定义JsonDeserializer实现:
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.List; public class ApiResponse { private String jsonrpc; private Object id; private List<ApiItem> result; // getters and setters } public class ApiItem { private int id; @JsonDeserialize(using = FalseToNullListDeserializer.class) private List<Object> productId; @JsonDeserialize(using = FalseToNullStringDeserializer.class) private String entrepreneur; @JsonDeserialize(using = FalseToNullStringDeserializer.class) private String deceasedName; @JsonDeserialize(using = FalseToNullStringDeserializer.class) private String caseNumber; @JsonDeserialize(using = FalseToNullDoubleDeserializer.class) private Double productUomQty; @JsonDeserialize(using = FalseToNullLocalDateTimeDeserializer.class) private LocalDateTime pickingDateTo; @JsonDeserialize(using = FalseToNullLocalDateTimeDeserializer.class) private LocalDateTime pickingDateFrom; @JsonDeserialize(using = CustomLocalDateTimeDeserializer.class) private LocalDateTime writeDate; @JsonDeserialize(using = CustomLocalDateTimeDeserializer.class) private LocalDateTime createDate; private List<Object> partnerId; private List<Object> pickingId; private String pickingState; @JsonDeserialize(using = FalseToNullListDeserializer.class) private List<Object> batchId; // getters and setters } // 字符串类型的false转空值反序列化器 class FalseToNullStringDeserializer extends JsonDeserializer<String> { @Override public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { String value = p.getText(); if ("false".equals(value)) { return null; } return value; } } // 数值类型的false转空值反序列化器 class FalseToNullDoubleDeserializer extends JsonDeserializer<Double> { @Override public Double deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { String value = p.getText(); if ("false".equals(value)) { return null; } return Double.parseDouble(value); } } // List类型的false转空值反序列化器 class FalseToNullListDeserializer extends JsonDeserializer<List<Object>> { @Override public List<Object> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { String value = p.getText(); if ("false".equals(value)) { return null; } return ctxt.readValue(p, List.class); } } // 日期类型的false转空值反序列化器 class FalseToNullLocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> { private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); @Override public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { String value = p.getText(); if ("false".equals(value)) { return null; } return LocalDateTime.parse(value, FORMATTER); } } // 常规日期解析器 class CustomLocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> { private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); @Override public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { return LocalDateTime.parse(p.getText(), FORMATTER); } } // 解析示例 public class Main { public static void main(String[] args) throws IOException { String jsonStr = "上述完整JSON字符串"; ObjectMapper mapper = new ObjectMapper(); ApiResponse response = mapper.readValue(jsonStr, ApiResponse.class); } }
内容的提问来源于stack exchange,提问作者Robin De Clercq
相关产品推荐
相关产品推荐

