java stdserializerprovider_自定义对象序列化与PreserveReferencesHandling

以下转换器为此提供了一个模板:

public abstract class ReferenceHandlingCustomCreationConverter : JsonConverter where T : class

{

const string refProperty = "$ref";

const string idProperty = "$id";

public override bool CanConvert(Type objectType)

{

return typeof(T).IsAssignableFrom(objectType);

}

protected virtual T Create(Type objectType, T existingValue, JsonSerializer serializer, JObject obj)

{

return existingValue ?? (T)serializer.ContractResolver.ResolveContract(objectType).DefaultCreator();

}

protected abstract void Populate(JObject obj, T value, JsonSerializer serializer);

protected abstract void WriteProperties(JsonWriter writer, T value, JsonSerializer serializer, JsonObjectContract contract);

public override sealed object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)

{

var contract = serializer.ContractResolver.ResolveContract(objectType);

if (!(contract is JsonObjectContract))

{

throw new JsonSerializationException(string.Format("Invalid non-object contract type {0}", contract));

}

if (!(existingValue == null || existingValue is T))

{

throw new JsonSerializationException(string.Format("Converter cannot read JSON with the specified existing value. {0} is required.", typeof(T)));

}

if (reader.MoveToContent().TokenType == JsonToken.Null)

return null;

var obj = JObject.Load(reader);

var refId = (string)obj[refProperty].RemoveFromLowestPossibleParent();

var objId = (string)obj[idProperty].RemoveFromLowestPossibleParent();

if (refId != null)

{

var reference = serializer.ReferenceResolver.ResolveReference(serializer, refId);

if (reference != null)

return reference;

}

var value = Create(objectType, (T)existingValue, serializer, obj);

if (objId != null)

{

// Add the empty array into the reference table BEFORE poppulating it, to handle recursive references.

serializer.ReferenceResolver.AddReference(serializer, objId, value);

}

Populate(obj, value, serializer);

return value;

}

public override sealed void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)

{

var contract = serializer.ContractResolver.ResolveContract(value.GetType());

if (!(contract is JsonObjectContract))

{

throw new JsonSerializationException(string.Format("Invalid non-object contract type {0}", contract));

}

if (!(value is T))

{

throw new JsonSerializationException(string.Format("Converter cannot read JSON with the specified existing value. {0} is required.", typeof(T)));

}

writer.WriteStartObject();

if (serializer.ReferenceResolver.IsReferenced(serializer, value))

{

writer.WritePropertyName(refProperty);

writer.WriteValue(serializer.ReferenceResolver.GetReference(serializer, value));

}

else

{

writer.WritePropertyName(idProperty);

writer.WriteValue(serializer.ReferenceResolver.GetReference(serializer, value));

WriteProperties(writer, (T)value, serializer, (JsonObjectContract)contract);

}

writer.WriteEndObject();

}

}

public static partial class JsonExtensions

{

public static JsonReader MoveToContent(this JsonReader reader)

{

if (reader.TokenType == JsonToken.None)

reader.Read();

while (reader.TokenType == JsonToken.Comment && reader.Read())

;

return reader;

}

public static JToken RemoveFromLowestPossibleParent(this JToken node)

{

if (node == null)

return null;

var contained = node.AncestorsAndSelf().Where(t => t.Parent is JContainer && t.Parent.Type != JTokenType.Property).FirstOrDefault();

if (contained != null)

contained.Remove();

// Also detach the node from its immediate containing property -- Remove() does not do this even though it seems like it should

if (node.Parent is JProperty)

((JProperty)node.Parent).Value = null;

return node;

}

}

实现转换器需要实现两个抽象方法:

protected abstract void Populate(JObject obj, T value, JsonSerializer serializer);

protected abstract void WriteProperties(JsonWriter writer, T value, JsonSerializer serializer, JsonObjectContract contract);

一个默认的通用实现可能如下所示:

public class DefaultReferenceHandlingCustomCreationConverter : ReferenceHandlingCustomCreationConverter where T : class

{

protected override void Populate(JObject obj, T value, JsonSerializer serializer)

{

using (var reader = obj.CreateReader())

serializer.Populate(reader, value);

}

protected override void WriteProperties(JsonWriter writer, T value, JsonSerializer serializer, JsonObjectContract contract)

{

foreach (var property in contract.Properties.Where(p => p.Writable && !p.Ignored))

{

// TODO: handle JsonProperty attributes including

// property.Converter, property.IsReference, property.ItemConverter, property.ItemReferenceLoopHandling,

// property.ItemReferenceLoopHandling, property.ObjectCreationHandling, property.ReferenceLoopHandling, property.Required

var itemValue = property.ValueProvider.GetValue(value);

writer.WritePropertyName(property.PropertyName);

serializer.Serialize(writer, itemValue);

}

}

}

使用它,然后您将序列化如下:

var settings = new JsonSerializerSettings

{

Converters = { new DefaultReferenceHandlingCustomCreationConverter() },

ReferenceLoopHandling = ReferenceLoopHandling.Serialize,

};

var json = JsonConvert.SerializeObject(parent, Formatting.Indented, settings);

笔记:

转换器在反序列化期间拆分了创建和填充对象的任务,因此不能使用仅带参数化构造函数的对象 . 这是使递归自引用正确解析所必需的 .

需要使用 ReferenceLoopHandling.Serialize 进行序列化 .

样本小提琴here .

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值