gpt4 book ai didi

c# - 反序列化hal+json为复杂模型

转载 作者:太空狗 更新时间:2023-10-29 17:47:36 25 4
gpt4 key购买 nike

我有以下 HAL+JSON示例:

{
"id": "4a17d6fe-a617-4cf8-a850-0fb6bc8576fd",
"country": "DE",
"_embedded": {
"company": {
"name": "Apple",
"industrySector": "IT",
"owner": "Klaus Kleber",
"_embedded": {
"emailAddresses": [
{
"id": "4a17d6fe-a617-4cf8-a850-0fb6bc8576fd",
"value": "test2@consoto.com",
"type": "Business",
"_links": {
"self": {
"href": "https://any-host.com/api/v1/customers/1234"
}
}
}
],
"phoneNumbers": [
{
"id": "4a17d6fe-a617-4cf8-a850-0fb6bc8576fd",
"value": "01670000000",
"type": "Business",
"_links": {
"self": {
"href": "https://any-host.com/api/v1/customers/1234"
}
}
}
],
},
"_links": {
"self": {
"href": "https://any-host.com/api/v1/customers/1234"
},
"phoneNumbers": {
"href": "https://any-host.com/api/v1/customers/1234"
},
"addresses": {
"href": "https://any-host.com/api/v1/customers/1234"
},
}
},
},
"_links": {
"self": {
"href": "https://any-host.com/api/v1/customers/1234"
},
"legalPerson": {
"href": "https://any-host.com/api/v1/customers/1234"
},
"naturalPerson": {
"href": "https://any-host.com/api/v1/customers/1234"
}
}
}

以及以下模型:

public class Customer
{
public Guid Id { get; set; }
public string Country { get; set; }
public LegalPerson Company { get; set; }
}
public class LegalPerson
{
public string Name { get; set; }
public string IndustrySector { get; set; }
public string Owner { get; set; }
public ContactInfo[] EmailAddresses { get; set; }
public ContactInfo[] PhoneNumbers { get; set; }
}
public class ContactInfo
{
public Guid Id { get; set; }
public string Type { get; set; }
public string Value { get; set; }
}

现在,由于 _embbeded,我无法使用 Newtonsoft.Json 进行开箱即用的序列化,因为 Company 将为 null

我希望看到 native hal+json support由 Json.NET 开发,但它只有一项建议使用自定义 JsonConverter

我开始自己创建一个定制的,但对我来说感觉像是“重新发明轮子”。

那么,有人知道解决这个问题的聪明方法吗?

更新:

  • 重要的是不要更改模型/类。我可以添加属性,但永远不会改变它的结构。

最佳答案

最可能的解决方案是建议您创建一个自定义转换器来解析所需的模型。

在这种情况下,自定义转换器需要能够读取嵌套路径。

这应该提供一个简单的解决方法。

public class NestedJsonPathConverter : JsonConverter {

public override object ReadJson(JsonReader reader, Type objectType,
object existingValue, JsonSerializer serializer) {
JObject jo = JObject.Load(reader);
var properties = jo.Properties();
object targetObj = existingValue ?? Activator.CreateInstance(objectType);
var resolver = serializer.ContractResolver as DefaultContractResolver;

foreach (PropertyInfo propertyInfo in objectType.GetProperties()
.Where(p => p.CanRead && p.CanWrite)) {

var attributes = propertyInfo.GetCustomAttributes(true).ToArray();

if (attributes.OfType<JsonIgnoreAttribute>().Any())
continue;

var jsonProperty = attributes.OfType<JsonPropertyAttribute>().FirstOrDefault();

var jsonPath = (jsonProperty != null ? jsonProperty.PropertyName : propertyInfo.Name);

if (resolver != null) {
jsonPath = resolver.GetResolvedPropertyName(jsonPath);
}

JToken token = jo.SelectToken(jsonPath) ?? GetTokenCaseInsensitive(properties, jsonPath);

if (token != null && token.Type != JTokenType.Null) {
object value = token.ToObject(propertyInfo.PropertyType, serializer);
propertyInfo.SetValue(targetObj, value, null);
}
}
return targetObj;
}

JToken GetTokenCaseInsensitive(IEnumerable<JProperty> properties, string jsonPath) {
var parts = jsonPath.Split('.');

var property = properties.FirstOrDefault(p =>
string.Equals(p.Name, parts[0], StringComparison.OrdinalIgnoreCase)
);

for (var i = 1; i < parts.Length && property != null && property.Value is JObject; i++) {
var jo = property.Value as JObject;
property = jo.Properties().FirstOrDefault(p =>
string.Equals(p.Name, parts[i], StringComparison.OrdinalIgnoreCase)
);
}

if (property != null && property.Type != JTokenType.Null) {
return property.Value;
}

return null;
}

public override bool CanConvert(Type objectType) {
//Check if any JsonPropertyAttribute has a nested property name {name}.{sub}
return objectType
.GetProperties()
.Any(p =>
p.CanRead
&& p.CanWrite
&& p.GetCustomAttributes(true)
.OfType<JsonPropertyAttribute>()
.Any(jp => (jp.PropertyName ?? p.Name).Contains('.'))
);
}

public override bool CanWrite {
get { return false; }
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
throw new NotImplementedException();
}
}

原来的类结构现在不需要改变,只有需要自定义路径的属性需要用JsonPropertyAttribute装饰,指示填充属性的路径。

在这个例子中

public class Customer {
public Guid Id { get; set; }
public string Country { get; set; }
[JsonProperty("_embedded.company")]
public LegalPerson Company { get; set; }
}
public class LegalPerson {
public string Name { get; set; }
public string IndustrySector { get; set; }
public string Owner { get; set; }
[JsonProperty("_embedded.emailAddresses")]
public ContactInfo[] EmailAddresses { get; set; }
[JsonProperty("_embedded.phoneNumbers")]
public ContactInfo[] PhoneNumbers { get; set; }
}

只需根据需要包含转换器。

var settings = new JsonSerializerSettings {
ContractResolver = new DefaultContractResolver {
NamingStrategy = new CamelCaseNamingStrategy()
}
};
settings.Converters.Add(new NestedJsonPathConverter());

var customer = JsonConvert.DeserializeObject<Customer>(json, settings);

代码的两个重要部分是 GetTokenCaseInsensitive 方法,它搜索请求的 token 并允许不区分大小写的嵌套路径。

JToken GetTokenCaseInsensitive(IEnumerable<JProperty> properties, string jsonPath) {
var parts = jsonPath.Split('.');

var property = properties.FirstOrDefault(p =>
string.Equals(p.Name, parts[0], StringComparison.OrdinalIgnoreCase)
);

for (var i = 1; i < parts.Length && property != null && property.Value is JObject; i++) {
var jo = property.Value as JObject;
property = jo.Properties().FirstOrDefault(p =>
string.Equals(p.Name, parts[i], StringComparison.OrdinalIgnoreCase)
);
}

if (property != null && property.Type != JTokenType.Null) {
return property.Value;
}

return null;
}

和覆盖的 CanConvert 将检查任何具有嵌套路径的属性

public override bool CanConvert(Type objectType) {
//Check if any JsonPropertyAttribute has a nested property name {name}.{sub}
return objectType
.GetProperties()
.Any(p =>
p.CanRead
&& p.CanWrite
&& p.GetCustomAttributes(true)
.OfType<JsonPropertyAttribute>()
.Any(jp => (jp.PropertyName ?? p.Name).Contains('.'))
);
}

关于c# - 反序列化hal+json为复杂模型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54129403/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com