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

如何将含空值为false的复杂JSON反序列化为C#对象?

问题描述

从外部API获取JSON数据时,空值统一用false表示,但非空字段的类型多样:

  • 如product_id非空时是数组([7800,"Bananenblad Naturel - 484"]),空值时为false
  • picking_date非空时是日期字符串("2023-08-11 10:10:39"),空值时为false
  • entrepreneur非空时是字符串,空值时为false
  • product_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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 02:07:33