如何设置Newtonsoft.Json以使用旧成员名称反序列化对象,但使用当前成员名称序列化该对象?
编辑:一项要求是将过时的成员从要序列化/反序列化的类中删除。
这是一个需要序列化和反序列化的示例对象。我给了一个属性一个属性,该属性包含过去可能已序列化过的名称的列表。
[DataContract]
class TestObject {
[LegacyDataMemberNames("alpha", "omega")]
[DataMember(Name = "a")]
public int A { get; set; }
}
我想始终使用名称“ a”对json进行序列化,但能够从任何旧名称(包括“ alpha”和“ omega”)以及当前名称“ a”反序列化为一个属性
这可以通过custom来完成,可以IContractResolver
通过扩展现有的解析器之一来创建,例如DefaultContractResolver
:
[System.AttributeUsage(System.AttributeTargets.Property | System.AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
public class LegacyDataMemberNamesAttribute : Attribute
{
public LegacyDataMemberNamesAttribute() : this(new string[0]) { }
public LegacyDataMemberNamesAttribute(params string[] names)
{
this.Names = names;
}
public string [] Names { get; set; }
}
public class LegacyPropertyResolver : DefaultContractResolver
{
// As of 7.0.1, Json.NET suggests using a static instance for "stateless" contract resolvers, for performance reasons.
// http://www.newtonsoft.com/json/help/html/ContractResolver.htm
// http://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Serialization_DefaultContractResolver__ctor_1.htm
// "Use the parameterless constructor and cache instances of the contract resolver within your application for optimal performance."
static LegacyPropertyResolver instance;
static LegacyPropertyResolver() { instance = new LegacyPropertyResolver(); }
public static LegacyPropertyResolver Instance { get { return instance; } }
protected LegacyPropertyResolver() : base() { }
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var properties = base.CreateProperties(type, memberSerialization);
for (int i = 0, n = properties.Count; i < n; i++)
{
var property = properties[i];
if (!property.Writable)
continue;
var attrs = property.AttributeProvider.GetAttributes(typeof(LegacyDataMemberNamesAttribute), true);
if (attrs == null || attrs.Count == 0)
continue;
// Little kludgy here: use MemberwiseClone to clone the JsonProperty.
var clone = property.GetType().GetMethod("MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
foreach (var name in attrs.Cast<LegacyDataMemberNamesAttribute>().SelectMany(a => a.Names))
{
if (properties.Any(p => p.PropertyName == name))
{
Debug.WriteLine("Duplicate LegacyDataMemberNamesAttribute: " + name);
continue;
}
var newProperty = (JsonProperty)clone.Invoke(property, new object[0]);
newProperty.Readable = false;
newProperty.PropertyName = name;
properties.Add(newProperty);
}
}
return properties;
}
}
请注意,此实现不需要类具有显式的数据协定属性注释。如果愿意,可以添加该限制。
然后将其与以下内容一起使用JsonSerializerSettings
:
var settings = new JsonSerializerSettings { ContractResolver = LegacyPropertyResolver.Instance };
例如:
[DataContract]
class TestObject
{
[LegacyDataMemberNames("alpha", "omega")]
[DataMember(Name = "a")]
public int A { get; set; }
}
public static class JsonExtensions
{
public static void RenameProperty(this JObject obj, string oldName, string newName)
{
if (obj == null)
throw new NullReferenceException();
var property = obj.Property(oldName);
if (property != null)
{
property.Replace(new JProperty(newName, property.Value));
}
}
}
public class TestClass
{
public static void Test()
{
try
{
TestInner();
}
catch (Exception ex)
{
Debug.Assert(false, ex.ToString()); // No assert
throw;
}
}
public static void TestInner()
{
var test = new TestObject { A = 42 };
var settings = new JsonSerializerSettings { ContractResolver = LegacyPropertyResolver.Instance };
var json = JObject.FromObject(test, JsonSerializer.CreateDefault(settings));
if (json.SelectToken("alpha") != null || json.SelectToken("omega") != null)
throw new InvalidOperationException("Failed serialization");
Test(test, json);
json.RenameProperty("a", "alpha");
Test(test, json);
json.RenameProperty("alpha", "omega");
Test(test, json);
}
private static void Test(TestObject test, JObject json)
{
var test1 = json.ToObject<TestObject>(JsonSerializer.CreateDefault(new JsonSerializerSettings { ContractResolver = LegacyPropertyResolver.Instance }));
if (test1.A != test.A)
throw new InvalidOperationException("Failed deserialization");
Console.WriteLine("Successfully deserialized: " + json.ToString(Formatting.None));
Debug.WriteLine("Successfully deserialized: " + json.ToString(Formatting.None));
}
}
问题内容: 是否可能:在类中有一个字段,而在Jackson库中进行序列化/反序列化时却为其使用不同的名称? 例如,我有“ Coordiantes”类。 对于从JSON反序列化,希望具有以下格式: 但是当我序列化对象时,结果应该是这样的: 我试图通过在getter和setter上都应用注释(具有不同的值)来实现此目的: 但我有一个例外: org.codehaus.jackson.map.exc.Un
问题内容: 我有以下从外部方收到的JSON字符串。 我的映射类: 现在的问题是,我不喜欢的 类名 和 字段名 的类。相反,我希望它被命名,并且还希望从字段名称中删除并提供适当的名称。 我可以重命名为,但是如果我更改了字段名(在类中),它将无法正确地反序列化并提供给我。我该如何克服呢? 问题答案: Json.NET具有允许您指定JSON属性名称的名称,因此您的代码应为: 文档: 序列化属性
假设我们有以下JSON, 在Java类中,我们有与上述JSON匹配的所有字段。 每次要反序列化的字段列表取决于发送信息的客户。 例如,对于customer 1,我们只想读回以下值,(并且跳过其他属性,即使在JSON中提供) 例如,对于客户2,我们希望读取以下值(并跳过其他属性,即使在JSON中提供) 使用Jackson反序列化JSON时,是否可以提供上面的数组,其中包括需要反序列化的字段, 更新:
问题内容: 我想将一个简单的对象序列化为JSON: 但是只要我这样做: 属性名称不作为指定部分,但类似于那些直接定义在类如的情况下它不是,但。 我究竟做错了什么? 问题答案: 我通过使用此问题答案中提供的技术解决了这个问题: 这是我上的课: 用法: 我还必须修改初始类:
问题内容: 我想序列化一个对象,以便根据字段的类型对字段之一进行不同的命名。例如: 在这里,我希望将字段序列化为类似的内容,而不是总是根据情况包含一个称为不同类型的字段。 使用Jackson怎么能达到这样的目的? 问题答案: 使用自定义。 然后,假设您要序列化以下两个对象: 第一个将打印: 第二个: 我使用了包装对象的名称,因为它仅用作花边固定器。如果要删除它,则必须为 整个 类编写一个自定义序列
问题内容: 使用Jackson 2,我正在寻找一种 通用的 方式将对象序列化为单个值(然后序列化它们,然后再填充该单个字段),而不必重复创建JsonSerializer / JsonDeserializer来处理每种情况。@JsonIdentityInfo批注非常接近,但由于我知道,它将始终对完整的子对象进行序列化,因此略微遗漏了该标记。 这是我想做的一个例子。给定的类: 我希望Order可以序列