I get the following error with the code below:
"An object reference is required for the non-static field, method, or property 'Response.PropName'"
Code:
public class Response<T> : Response
{
private string PropName
{
get
{
return typeof(T).Name;
}
}
[JsonProperty(PropName)]
public T Data { get; set; }
}
So you can do: A<String> a = new A<String>() {}; a now refers to a subclass of A<String> , so by getting a. getClass().
The short answer is, that there is no way to find out the runtime type of generic type parameters in Java. A solution to this is to pass the Class of the type parameter into the constructor of the generic type, e.g.
Compares the specified string to the name of this property. Provides a string representation of the property for debugging purposes. Writes the property to the provided writer as a named JSON object property.
What you're trying to do is possible, but not trivial, and can't be done with only the built-in attributes from JSON.NET. You'll need a custom attribute, and a custom contract resolver.
Here's the solution I came up with:
Declare this custom attribute:
[AttributeUsage(AttributeTargets.Property)]
class JsonPropertyGenericTypeNameAttribute : Attribute
{
public int TypeParameterPosition { get; }
public JsonPropertyGenericTypeNameAttribute(int position)
{
TypeParameterPosition = position;
}
}
Apply it to your Data
property
public class Response<T> : Response
{
[JsonPropertyGenericTypeName(0)]
public T Data { get; set; }
}
(0 is the position of T
in Response<T>
's generic type parameters)
Declare the following contract resolver, which will look for the JsonPropertyGenericTypeName
attribute and get the actual name of the type argument:
class GenericTypeNameContractResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var prop = base.CreateProperty(member, memberSerialization);
var attr = member.GetCustomAttribute<JsonPropertyGenericTypeNameAttribute>();
if (attr != null)
{
var type = member.DeclaringType;
if (!type.IsGenericType)
throw new InvalidOperationException($"{type} is not a generic type");
if (type.IsGenericTypeDefinition)
throw new InvalidOperationException($"{type} is a generic type definition, it must be a constructed generic type");
var typeArgs = type.GetGenericArguments();
if (attr.TypeParameterPosition >= typeArgs.Length)
throw new ArgumentException($"Can't get type argument at position {attr.TypeParameterPosition}; {type} has only {typeArgs.Length} type arguments");
prop.PropertyName = typeArgs[attr.TypeParameterPosition].Name;
}
return prop;
}
}
Serialize with this resolver in your serialization settings:
var settings = new JsonSerializerSettings { ContractResolver = new GenericTypeNameContractResolver() };
string json = JsonConvert.SerializeObject(response, settings);
This will give the following output for Response<Foo>
{
"Foo": {
"Id": 0,
"Name": null
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With