How to tell JSON.NET to deserialize JArray to a List<object> when object type is provided?
Solution 1
Your answer is probably here
Your [5]
is an array. All you have to do is to cast it to a list.
You could also create your own converter, like described here
Solution 2
Currently, I have mocked the following solution:
public class MyObjectConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(object);
}
public override object ReadJson(Newtonsoft.Json.JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
switch (reader.TokenType)
{
case Newtonsoft.Json.JsonToken.StartArray:
return JToken.Load(reader).ToObject<List<object>>();
case Newtonsoft.Json.JsonToken.StartObject:
return JToken.Load(reader).ToObject<Dictionary<string, object>>();
default:
if (reader.ValueType == null && reader.TokenType != Newtonsoft.Json.JsonToken.Null)
throw new NotImplementedException("MyObjectConverter");
return reader.Value;
}
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotSupportedException("MyObjectConverter");
}
}
Problem of this solution is that it must handle the other types as well. It could fail when reader.TokenType is neither StartArray
nor StartObject
and reader.ValueType is null. Hopefully someone will provide a better solution.
Abimael López
Updated on July 01, 2020Comments
-
Abimael López almost 4 years
Let's have the following class:
class Foo { public object Any; }
This class accepts anything in the field
Any
.When I call:
JsonConvert.DeserializeObject<Foo>("{any: 5}")
Any
containsSystem.Int64
.However, when I call:
JsonConvert.DeserializeObject<Foo>("{any: [5]}")
Any
containsNewtonsoft.Json.Linq.JArray
.How to configure JSON.NET so that in this case
Any
would containList<object>
?CLARIFICATION:
There could be anything, I can call:
JsonConvert.DeserializeObject<Foo>("{any: 'c'}")
or
JsonConvert.DeserializeObject<Foo>("{any: ['c', 5]}")
More clarification:
I would like to tell somehow to JSON.NET (maybe using JsonSerializerSettings):
When you encounter
object
and JSON contains an array, deserialize that to (for instance)List<object>
.-
Andrew Whitaker almost 9 yearspossible duplicate of How to handle both a single item and an array for the same property using JSON.net
-
Abimael López almost 9 years@AndrewWhitaker see update
-
Daniel Möller almost 9 yearsIf
Any
is just5
and not[5]
, would you like it to be aList<System.Int64>
too? -
Abimael López almost 9 years@Daniel No, since there could be [5, 'x']. (Therefore, I have put
object
there.) -
Chris almost 9 yearsYou can mark a constructor with JsonConstructorAttribute (newtonsoft.com/json/help/html/…) which will tell it to use that constructor when deserializing the object. You could then put any logic you want in there. Would that work for you?
-
Abimael López almost 9 years@Chris I cannot annotate the particular classes, I need to specify that as a 'global' behavior. See "more clarification".
-
Chris almost 9 years@TN.: I had a suspicion that might be the case. There are overloads of DeserializeObject that take JsonConverters that might do what you want but I've not used them. In general JsonConverters override read/write behaviour so should be able to do what you want but I can't tell you much more on how to use them. (Apologies if you've already checked if these overloads will help you) stackoverflow.com/questions/2254872/… may be of interest on this topic (may even be a duplicate)
-
Abimael López almost 9 years@Chris I have already written few converters, however I do not know, how to specify that it should be invoked only when JSON contains an array (and type of member is object). Or how to fallback to the default behavior when JSON contains (for instance) a string.
-
-
Abimael López almost 9 yearsI do not want to retraverse the structure and check and cast all fields with object type.
-
Abimael López almost 9 yearsHow to specify that a convert should be invoked only when JSON contains an array (and type of member is object)? Or how to fallback to the default behavior when JSON contains (for instance) a string?
-
Abimael López almost 9 yearsThank you for your code, but the
Foo
is just an example. I cannot hardwire the converter for a particular class (Foo
) and property (Any
). -
Daniel Möller almost 9 yearsDo you mean, you want that to work with any kind of object? Like Foo1, Foo2, Foo3 and any other?
-
Abimael López almost 9 years@Daniel Yes, I have tried to mock the solution here: stackoverflow.com/a/31131934/121968.
-
Daniel Möller almost 9 yearsYou don't need to conver all types. You just need to convert the types you desire. If I understood it well, you just need to implement the
Array
case, any other case you just return the object as it is and JSON will do the rest. (It was able to manage those types without a converter, right?) -
Abimael López almost 9 yearsHowever, where I get 'the object' for the other cases?
-
Abimael López almost 9 yearsToObject<object> does not deserialize the nested arrays properly (e.g.
[1, [5, 3]]
or[1, {bar: [4]}]
). The same problem has currently the solution above. -
Daniel Möller almost 9 yearsDo you get any exceptions if you just remove that
if
? -
Abimael López almost 9 yearsMaybe not, but want to know whether reader contains
null
inValue
, because it should be there or not. But you can just ignore that if. Problem is thatJToken.Load(reader).ToObject<List<object>>()
does not process the nested array and maybe other JsonConvertors which are configured.