如何正确处理 empty、null 和 valid JSON?
How to properly handle empty, null and valid JSON?
我需要在 Rust 中将 JSON 文件反序列化为 None
或 Some(T)
。当没有值时,我们使用的来源将提供 null
或空的“{}”,JSON 字段。我想将两者都作为 None
情况处理,并且仅在 JSON 字段不为空或为空时才反序列化。
input: {"test": null} -> output: {"test": None}
input: {"test": {}} -> output: {"test": None}
input: {"test": {"valid_json": 42}} -> output: {"test": {"valid_json": 42}}
我能找到的所有答案都解决了一个或另一个问题,但不能同时解决这两个问题。
use serde::{Deserialize, Deserializer};
#[derive(Deserialize, Debug, PartialEq)]
struct Foo {
#[serde(deserialize_with = "object_empty_as_none")]
bar: Option<Bar>,
}
#[derive(Deserialize, Debug, PartialEq)]
struct Bar {
inner: u32,
}
pub fn object_empty_as_none<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
where
D: Deserializer<'de>,
for<'a> T: Deserialize<'a>,
{
#[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)]
struct Empty {}
#[derive(Deserialize, Debug)]
#[serde(untagged)]
enum Aux<T> {
T(T),
Empty(Empty),
Null,
}
match Deserialize::deserialize(deserializer)? {
Aux::T(t) => Ok(Some(t)),
Aux::Empty(_) | Aux::Null => Ok(None),
}
}
fn main() {
let data = r#"{"bar": null}"#;
let v: Foo = serde_json::from_str(data).unwrap();
assert_eq!(v, Foo { bar: None });
let data = r#"{"bar": {}}"#;
let v: Foo = serde_json::from_str(data).unwrap();
assert_eq!(v, Foo { bar: None });
let data = r#"{"bar": {"inner": 42}}"#;
let v: Foo = serde_json::from_str(data).unwrap();
assert_eq!(
v,
Foo {
bar: Some(Bar { inner: 42 })
}
);
let data = r#"{"bar": {"not_inner": 42}}"#;
let v: Result<Foo, _> = serde_json::from_str(data);
assert!(v.is_err());
}
大多数情况下应该足够了。如果需要,请删除 Empty
上的 #[serde(deny_unknown_fields)]
。
This page tells you how to implement a custom map deserializer, which requires customizing how visit_map
produces key-value pairs from the input data. I've basically copied that page and produced a minimal example that implements what you're looking for. Link to playground.
use std::fmt;
use std::marker::PhantomData;
use serde::de::{Deserialize, Deserializer, MapAccess, Visitor};
use serde_json::Value as JsonValue;
use std::collections::HashMap;
#[derive(Debug)]
struct MyMap(HashMap<String, JsonValue>);
impl MyMap {
fn with_capacity(capacity: usize) -> Self {
Self(HashMap::with_capacity(capacity))
}
}
struct MyMapVisitor {
marker: PhantomData<fn() -> MyMap>,
}
impl MyMapVisitor {
fn new() -> Self {
MyMapVisitor {
marker: PhantomData,
}
}
}
impl<'de> Visitor<'de> for MyMapVisitor {
// The type that our Visitor is going to produce.
type Value = MyMap;
// Format a message stating what data this Visitor expects to receive.
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a very special map")
}
// Deserialize MyMap from an abstract "map" provided by the
// Deserializer. The MapAccess input is a callback provided by
// the Deserializer to let us see each entry in the map.
fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
where
M: MapAccess<'de>,
{
let mut map = MyMap::with_capacity(access.size_hint().unwrap_or(0));
// While there are entries remaining in the input, add them
// into our map. Empty Objects get turned into Null.
while let Some((key, value)) = access.next_entry()? {
let value = match value {
JsonValue::Object(o) if o.is_empty() => JsonValue::Null,
_ => value,
};
map.0.insert(key, value);
}
Ok(map)
}
}
// This is the trait that informs Serde how to deserialize MyMap.
impl<'de> Deserialize<'de> for MyMap {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
// Instantiate our Visitor and ask the Deserializer to drive
// it over the input data, resulting in an instance of MyMap.
deserializer.deserialize_map(MyMapVisitor::new())
}
}
fn main() -> serde_json::Result<()> {
let json_str = r#"{"a": null, "b": {}, "c": {"valid_json": 42}}"#;
let v: MyMap = serde_json::from_str(json_str)?;
println!("{:?}", v);
Ok(())
}
这会打印出 MyMap({"b": Null, "c": Object({"valid_json": Number(42)}), "a": Null})
,我相信这就是您想要的。
我需要在 Rust 中将 JSON 文件反序列化为 None
或 Some(T)
。当没有值时,我们使用的来源将提供 null
或空的“{}”,JSON 字段。我想将两者都作为 None
情况处理,并且仅在 JSON 字段不为空或为空时才反序列化。
input: {"test": null} -> output: {"test": None}
input: {"test": {}} -> output: {"test": None}
input: {"test": {"valid_json": 42}} -> output: {"test": {"valid_json": 42}}
我能找到的所有答案都解决了一个或另一个问题,但不能同时解决这两个问题。
use serde::{Deserialize, Deserializer};
#[derive(Deserialize, Debug, PartialEq)]
struct Foo {
#[serde(deserialize_with = "object_empty_as_none")]
bar: Option<Bar>,
}
#[derive(Deserialize, Debug, PartialEq)]
struct Bar {
inner: u32,
}
pub fn object_empty_as_none<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
where
D: Deserializer<'de>,
for<'a> T: Deserialize<'a>,
{
#[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)]
struct Empty {}
#[derive(Deserialize, Debug)]
#[serde(untagged)]
enum Aux<T> {
T(T),
Empty(Empty),
Null,
}
match Deserialize::deserialize(deserializer)? {
Aux::T(t) => Ok(Some(t)),
Aux::Empty(_) | Aux::Null => Ok(None),
}
}
fn main() {
let data = r#"{"bar": null}"#;
let v: Foo = serde_json::from_str(data).unwrap();
assert_eq!(v, Foo { bar: None });
let data = r#"{"bar": {}}"#;
let v: Foo = serde_json::from_str(data).unwrap();
assert_eq!(v, Foo { bar: None });
let data = r#"{"bar": {"inner": 42}}"#;
let v: Foo = serde_json::from_str(data).unwrap();
assert_eq!(
v,
Foo {
bar: Some(Bar { inner: 42 })
}
);
let data = r#"{"bar": {"not_inner": 42}}"#;
let v: Result<Foo, _> = serde_json::from_str(data);
assert!(v.is_err());
}
大多数情况下应该足够了。如果需要,请删除 Empty
上的 #[serde(deny_unknown_fields)]
。
This page tells you how to implement a custom map deserializer, which requires customizing how visit_map
produces key-value pairs from the input data. I've basically copied that page and produced a minimal example that implements what you're looking for. Link to playground.
use std::fmt;
use std::marker::PhantomData;
use serde::de::{Deserialize, Deserializer, MapAccess, Visitor};
use serde_json::Value as JsonValue;
use std::collections::HashMap;
#[derive(Debug)]
struct MyMap(HashMap<String, JsonValue>);
impl MyMap {
fn with_capacity(capacity: usize) -> Self {
Self(HashMap::with_capacity(capacity))
}
}
struct MyMapVisitor {
marker: PhantomData<fn() -> MyMap>,
}
impl MyMapVisitor {
fn new() -> Self {
MyMapVisitor {
marker: PhantomData,
}
}
}
impl<'de> Visitor<'de> for MyMapVisitor {
// The type that our Visitor is going to produce.
type Value = MyMap;
// Format a message stating what data this Visitor expects to receive.
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a very special map")
}
// Deserialize MyMap from an abstract "map" provided by the
// Deserializer. The MapAccess input is a callback provided by
// the Deserializer to let us see each entry in the map.
fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
where
M: MapAccess<'de>,
{
let mut map = MyMap::with_capacity(access.size_hint().unwrap_or(0));
// While there are entries remaining in the input, add them
// into our map. Empty Objects get turned into Null.
while let Some((key, value)) = access.next_entry()? {
let value = match value {
JsonValue::Object(o) if o.is_empty() => JsonValue::Null,
_ => value,
};
map.0.insert(key, value);
}
Ok(map)
}
}
// This is the trait that informs Serde how to deserialize MyMap.
impl<'de> Deserialize<'de> for MyMap {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
// Instantiate our Visitor and ask the Deserializer to drive
// it over the input data, resulting in an instance of MyMap.
deserializer.deserialize_map(MyMapVisitor::new())
}
}
fn main() -> serde_json::Result<()> {
let json_str = r#"{"a": null, "b": {}, "c": {"valid_json": 42}}"#;
let v: MyMap = serde_json::from_str(json_str)?;
println!("{:?}", v);
Ok(())
}
这会打印出 MyMap({"b": Null, "c": Object({"valid_json": Number(42)}), "a": Null})
,我相信这就是您想要的。