当前位置: 首页 > 面试题库 >

JSON.NET中特定对象的自定义转换

许正平
2023-03-14
问题内容

我正在使用JSON.NET序列化一些对象,并且我想知道是否有一种简单的方法可以仅针对特定对象覆盖默认json.net转换器?

目前我有以下课程:

public class ChannelContext : IDataContext
{
    public int Id { get; set; }
    public string Name { get; set; }
    public IEnumerable<INewsItem> Items { get; set; }
}

JSON.NET当前将上述序列化为:

{
    "Id": 2,
    "Name": "name value",
    "Items": [ item_data_here ]
}

是否可以仅通过特定方式将其格式化为:

"Id_2":
{
    "Name": "name value",
    "Items": [ item data here ]
}

我对JSON.NET有点陌生。我想知道上面是否与编写自定义转换器有关。我找不到任何有关如何编写示例的具体示例。如果有人可以指出我的具体信息,我将不胜感激。

我需要找到一个使特定类始终转换相同的解决方案,因为上述上下文是更大上下文的一部分,JSON.NET默认转换器可以很好地转换该上下文。

希望我的问题很清楚…

更新:

我发现了如何创建新的自定义转换器(通过创建从JsonConverter继承并覆盖其抽象方法的新类),我重写了WriteJson方法,如下所示:

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        ChannelContext contextObj = value as ChannelContext;

        writer.WriteStartObject();
        writer.WritePropertyName("id_" + contextObj.Id);
        writer.WriteStartObject();
        writer.WritePropertyName("Name");
        serializer.Serialize(writer, contextObj.Name);

        writer.WritePropertyName("Items");
        serializer.Serialize(writer, contextObj.Items);
        writer.WriteEndObject();
        writer.WriteEndObject();
    }

这确实可以成功完成工作,但是…我很感兴趣是否有一种方法可以通过重用默认的JsonSerializer(或相应的转换器)来序列化其余对象属性,而不是使用jsonwriter手动“写入”对象方法。

更新2: 我试图获得一个更通用的解决方案,并提出了以下内容:

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        writer.WriteStartObject();

        // Write associative array field name
        writer.WritePropertyName(m_FieldNameResolver.ResolveFieldName(value));

        // Remove this converter from serializer converters collection
        serializer.Converters.Remove(this);

        // Serialize the object data using the rest of the converters
        serializer.Serialize(writer, value);

        writer.WriteEndObject();
    }

手动将转换器添加到序列化器时,这种方法可以正常工作,如下所示:

jsonSerializer.Converters.Add(new AssociativeArraysConverter<DefaultFieldNameResolver>());
jsonSerializer.Serialize(writer, channelContextObj);

但是在使用[JsonConverter()]属性设置为ChannelContext类上方的自定义掩体时不起作用,因为在执行时会发生自引用循环

serializer.Serialize(writer, value)

这显然是因为自定义转换器现在被视为使用JsonConverterAttribute设置的类的默认转换器,所以我得到了无限循环。为了解决这个问题,我唯一想到的就是从一个基本的jsonconverter类继承,然后调用base.serialize()方法…但是,这样的JsonConverter类是否存在?

非常感谢!

米奇


问题答案:

如果有人对我的解决方案感兴趣:

在序列化某些集合时,我想创建一个关联的json数组而不是标准的json数组,因此我的同事客户端开发人员可以使用它们的名称(或相应的键)来有效地访问这些字段,而不是遍历它们。

考虑以下:

public class ResponseContext
{
    private List<ChannelContext> m_Channels;

    public ResponseContext()
    {
        m_Channels = new List<ChannelContext>();
    }

    public HeaderContext Header { get; set; }

    [JsonConverter(
        typeof(AssociativeArraysConverter<ChannelContextFieldNameResolver>))]
    public List<ChannelContext> Channels
    {
        get { return m_Channels; }
    }

}

[JsonObject(MemberSerialization = MemberSerialization.OptOut)]
public class ChannelContext : IDataContext
{
    [JsonIgnore]
    public int Id { get; set; }

    [JsonIgnore]
    public string NominalId { get; set; }

    public string Name { get; set; }

    public IEnumerable<Item> Items { get; set; }
}

响应上下文包含整个响应,该响应被写回到客户端,如您所见,它包含一个称为“通道”的部分,并且我不想在常规数组中输出channelcontext,而是希望在以下方式:

"Channels"
{
"channelNominalId1":
{
  "Name": "name value1"
  "Items": [ item data here ]
},
"channelNominalId2":
{
  "Name": "name value2"
  "Items": [ item data here ]
}
}

由于我也想将以上内容用于其他上下文,并且我可能会决定使用其他属性作为其“键”,甚至可能选择创建自己的唯一名称,而该名称与任何属性都没有关系,我需要某种通用解决方案,因此我编写了一个名为AssociativeArraysConverter的通用类,该类以以下方式从JsonConverter继承:

public class AssociativeArraysConverter<T> : JsonConverter
    where T : IAssociateFieldNameResolver, new()
{
    private T m_FieldNameResolver;

    public AssociativeArraysConverter()
    {
        m_FieldNameResolver = new T();
    }

    public override bool CanConvert(Type objectType)
    {
        return typeof(IEnumerable).IsAssignableFrom(objectType) &&
                !typeof(string).IsAssignableFrom(objectType);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        IEnumerable collectionObj = value as IEnumerable;

        writer.WriteStartObject();

        foreach (object currObj in collectionObj)
        {
            writer.WritePropertyName(m_FieldNameResolver.ResolveFieldName(currObj));
            serializer.Serialize(writer, currObj);
        }

        writer.WriteEndObject();
    }
}

并声明以下接口:

public interface IAssociateFieldNameResolver
{
    string ResolveFieldName(object i_Object);
}

现在要做的就是创建一个类,该类实现IAssociateFieldNameResolver的单个函数,该函数接受集合中的每个项目,并返回基于该对象的字符串,该字符串将用作该项目的关联对象的键。

这样的类的示例是:

public class ChannelContextFieldNameResolver : IAssociateFieldNameResolver
{
    public string ResolveFieldName(object i_Object)
    {
        return (i_Object as ChannelContext).NominalId;
    }
}


 类似资料:
  • 问题内容: 我正在尝试为Json.NET创建一个自定义ValueProvider,它将跳过序列化所有对象的过程,并将仅返回Guid类型的属性来表示其主键(作为参考)。 例: 应成为: 这是我到目前为止编写的代码。我非常接近使其工作,但是就我而言,我似乎无法获取对象值。我怎样才能做到这一点? 问题答案: 您希望将值从嵌套对象内部提升到父对象。为此,您需要将两个价值提供者链接在一起: 一个外部值提供者

  • 问题内容: 说我的课很简单 我希望将此类s 的集合存储在People类的属性中,该属性是类型为Person的数组 也许我做到这一点如下 问题:请问我如何检查people.list是否包含实例alex? 我很想尝试的简单尝试 称一个错误 问题答案: 有两个功能: 编译器在抱怨是因为编译器知道不是,因此需要一个谓词,但不是谓词。 如果阵列中的人员是(不是),则可以使用: 由于它们不相等,因此可以将第二

  • 问题内容: 我在解析给定的JSON数据时遇到了一个奇怪的问题。我有这个JSON结构: 如何使用Newtonsoft JSON.NET库解析此结构?我尝试使用自己的JsonConverter类: 但我有一个例外: 编辑:我也试图将其保存到字典: 但我还有一个例外: 我做错了什么?谢谢您的回答。 问题答案: 您似乎想要在JSON中将a表示为对象数组,其中每个嵌套对象都有一个来自字典的键和值。您可以使用

  • 使用代替和代替 然后在请求属性中添加 但是当我在javascript中检索它时,我得到了jsonObject的值 我在我的项目中已经使用了下面的库,如果需要,可以使用任何新的库

  • 我正在努力找出如何使用Java流从对象值等于x的自定义对象列表中收集自定义对象。 这没有编译,但我不认为我离得很远--有人能指出我在哪里出错吗?

  • 我将springboot控制器与@RequestBody一起使用。我有以下json请求正文 我有一个对应的POJO 我有控制器就像 显然它不起作用,因为是请求中的字符串,而它在MyObject中是布尔值。我希望它有一个逻辑,所以如果在请求中,它将在MyObject中转换为布尔值。Spring有什么机制来实现这一点?