Reputation: 571
I have a JSON string returned from API that sometimes like this, in which the "result"
key only has an empty object :
{
"_meta": {
"status": "SUCCESS",
"count": 0
},
"result": {}
}
or this, in which the "result"
key has an array of object:
{
"_meta": {
"status": "SUCCESS",
"count": 0
},
"result": [
{ ... },
{ ... }
]
}
I've tried implementing custom JsonConverter
from this question, but I guess I got no luck. Here is my implementation:
class EmptyObjectJsonConverter<T> : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return true;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
object retObj = new Object();
if (reader.TokenType == JsonToken.StartArray)
{
retObj = serializer.Deserialize<List<T>>(reader);
}
else if (reader.TokenType == JsonToken.StartObject)
{
retObj = new List<T>();
}
return retObj;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
And I use it this way:
public class ApiReturn
{
public ApiMeta _Meta { get; set; }
[JsonConverter(typeof(EmptyObjectJsonConverter<ApiResult>))]
public List<ApiResult> Result { get; set; }
}
What I want to achieve from above implementation is: if the token is start array, then deserialize it in a normal way, but if the token is start object, then just return an empty list of object.
But then, when I tried running the program with the "result"
key having an empty object, it throws exception: Additional text found in JSON string after finishing deserializing object.
, and the resulting ApiReturn.Result
is null.
Did I implement it in a wrong way? Any help would be appreciated.
UPDATE based on @A. Chiesa answer: Please look at my implementation of GetApiResult
:
[JsonProperty("result")]
public JToken Result { get; set; }
public T GetResultAs<T>()
{
var objectReturned = default(T);
try
{
if (Result.Type == JTokenType.Array)
{
objectReturned = Result.ToObject<T>();
}
else if (Result.Type == JTokenType.Object)
{
// Should it return an empty List<ApiResult> if I use type List<ApiResult> ?
objectReturned = default(T);
}
}
catch
{
objectReturned = default(T);
}
return objectReturned;
}
Why I get null when the JSON node token is object? Should it return an empty List<ApiResult>
when I use GetResultAs<List<ApiResult>>
?
Upvotes: 2
Views: 2236
Reputation: 571
Here is my full working implementation of @A. Chiesa's answer that fits my needs if you want to know.
At first I thought that default(T)
is the same as creating a new instance 😂
So here I use instantiation of generic type (it's new for me: C# Create New T()):
public class ApiReturn
{
[JsonProperty("_meta")]
public ApiMeta Meta { get; set; }
[JsonProperty("result")]
public JToken Result { get; set; }
public T GetResultAs<T>() where T : new()
{
var objectReturned = default(T);
try
{
if (Result.Type == JTokenType.Array)
{
objectReturned = Result.ToObject<T>();
}
else if (Result.Type == JTokenType.Object)
{
objectReturned = new T();
}
}
catch
{
objectReturned = new T();
}
return objectReturned;
}
}
Upvotes: 0
Reputation: 7360
I like to use a JToken
property, abstracted by the deserialization class.
A really naive implementation would be:
public enum MetaStatus
{
SUCCESS
// FAILURE,
// ... etc
}
public class Meta
{
public MetaStatus Status { get; set; }
public long Count { get; set; }
}
public class ApiResponse
{
[JsonProperty("_meta")]
public Meta Meta { get; set; }
[JsonProperty("result")]
public JToken JsonResult { get; set; }
public T GetResultAs<T>()
{
// put in place some error handling logic, depending upon what's really an error
// in this method.
try
{
return JsonResult.ToObject<T>();
}
catch
{
return default(T);
}
}
}
In short: you ask Json.Net to keep the result as a Json object, then, after the deserialization is performed, you can try deserializing the JToken
every way you want, just calling a typed GetResultAs
, like GetResultAs<List<ApiLineObj>>()
.
The code is not meant to be used as-is (probably you want to handle some check), but the basic deserialization mechanic is there.
Upvotes: 1
Reputation: 109
You can try to deserialize the JSON to an Object right away. I used json2sharp to generate the classes from your JSON code.
public class Meta
{
public string status { get; set; }
public int count { get; set; }
}
public class Result
{
<Add whatever field you are expecting>
}
public class RootObject
{
public Meta _meta { get; set; }
public Result result { get; set; }
}
Then you can use the line below to deserialze the JSON to an Object right away.
RootObject root = JsonConvert.DeserializeObject<RootObject>("YOUR JSON");
If the result array is empty the list in the RootObject class will just be empty.
Upvotes: 0