如何使Jackson和JSON.net的引用处理语法兼容? [英] How can I make reference handling syntax from Jackson and JSON.net compatible?

查看:105
本文介绍了如何使Jackson和JSON.net的引用处理语法兼容?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个服务器,该服务器使用Jackson生成以下JSON.

I have a server that produces the following JSON with Jackson.

{
  "$id" : 1,
  "employees" : [
    {
        "$id" : 2,
        "name" : "John Rambo",
    },
    2                     // Jackson: reference by ID only
  ]
}

员工列表包含两次相同的员工.杰克逊第二次通过其ID正确引用了该对象.

The list of employees contains the same employee twice. Jackson correctly references the object by it's ID the second time.

我想在使用JSON.net的客户端中反序列化此操作,但这将不起作用,因为JSON.net希望我将引用包装在具有$ ref属性的json对象中,如下所示:

I want to deserialize this in a client that uses JSON.net, but this won't work because JSON.net expects me to have the reference wrapped in a json object with a $ref property like this:

{
  "$id": "1",
  "employees" : [
    {
      "$id": "2",
      "name": "John Rambo"
    },
    {
     "$ref": "2"              // JSON.net: reference wrapped in JSON object
    }
  ]
}

是否可以通过配置或实现自定义反序列化器使JSON.net正确使用Jackson语法?

Is there a way to make JSON.net correctly consume the Jackson syntax either by configuration or by implementing a custom deserializer?

推荐答案

这是一个应该起作用的自定义转换器:

Here's a custom converter that should work:

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

    public override object ReadJson(
        JsonReader reader, 
        Type objectType, 
        object existingValue, 
        JsonSerializer serializer)
    {
        List<Employee> employees = null;

        if (reader.TokenType == JsonToken.StartArray)
        {
            JArray arr = serializer.Deserialize<JArray>(reader);

            employees = new List<Employee>(arr.Count);

            var employeeMap = new Dictionary<int, Employee>();

            foreach (var item in arr)
            {
                if (item.Type == JTokenType.Object)
                {
                    var employee = item.ToObject<Employee>();
                    employees.Add(employee);

                    int id = item["$id"].ToObject<int>();
                    employeeMap.Add(id, employee);
                }
                else if (item.Type == JTokenType.Integer)
                {
                    Employee employee = null;

                    int id = item.ToObject<int>();

                    if (employeeMap.TryGetValue(id, out employee))
                    {
                        employees.Add(employee);
                    }
                }
            }
        }

        return employees;
    }

    public override bool CanRead
    {
        get { return true; }
    }

    public override bool CanConvert(Type objectType)
    {
        return false;
    }
}

...,这是您的使用方式:

... and here's how you'd use it:

public class Company
{
    public Company()
    {
        this.Employees = new List<Employee>();
    }

    [JsonConverter(typeof(EmployeeConverter))]
    public List<Employee> Employees { get; set; }
}

示例: https://dotnetfiddle.net/XooyQC

基本上使用自定义转换器对整个数组进行反序列化.首先,将数组反序列化为JArray,然后检查JArray的每个元素以查看它是引用还是新对象.

Basically use a custom converter to deserialize the entire array. First, deserialize the array to a JArray, then inspect each element of the JArray to see if it's a reference or a new object.

这篇关于如何使Jackson和JSON.net的引用处理语法兼容?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆