Xamarin c# can not call Google Gson FromJson - c#

I am trying to call the method "fromJSon" of Google Gson (in C#, Xamarin), but I am receiving following Error : "Arguement 2, cannot convert Java.Lang.Object to Java.Lang.Class".
Here is my Source code of the relevant Part :
...
HomePojo mHomePojo = null;
Gson mGson = new Gson();
try
{
GoogleGson.JsonObject dataObject = jObject.GetAsJsonObject(AppGlobal.TAG_JSON_DATA_OBJECT);
Java.Lang.Object clazz = Java.Lang.Class.FromType(typeof(HomePojo));
mHomePojo = mGson.FromJson(dataObject.AsJsonObject, clazz);
}
catch (JSONException e)
{
Console.WriteLine(e.ToString());
Console.Write(e.StackTrace);
}
return mHomePojo;
...
It is showing "Arguement 2, cannot convert Java.Lang.Object to Java.Lang.Class".

You need to create a ObjectTypeHelper class.
public static class ObjectTypeHelper
{
public static T Cast<T>(this Java.Lang.Object obj) where T : class
{
var propertyInfo = obj.GetType().GetProperty("Instance");
return propertyInfo == null ? null : propertyInfo.GetValue(obj, null) as T;
}
}
And HomePojo class Should inherit from ObjectTypeHelper ,then have a try with follow code:
GoogleGson.JsonObject dataObject = jObject.GetAsJsonObject(AppGlobal.TAG_JSON_DATA_OBJECT);
mHomePojo = mGson.FromJson(dataObject.AsJsonObject, Java.Lang.Class.FromType(typeof(HomePojo)).Cast<HomePojo>();;
If not working, maybe Gson is still compatible with xamarin android.
WorkaRound :
Using Newtonsoft.Json to deserialize your json object.
public class RootObject
{
public int id { get; set; }
public string name { get; set; }
public Type type { get; set; }
public List<string> options { get; set; }
}
Then you should be able to deserialize your json:
List<RootObject> myData = JsonConvert.DeserializeObject<List<RootObject>>(json);

You need to declare your variable as Java.Lang.Class so that it matches the parameter type.

Related

Deserialising JSON files in C#

I keep getting following error:
Object reference not set to an instance of an object
This is my Json string in a file at C:\part_param.json
{
"part_parameters" : {
"bar_diameter" : 300.4,
"core_height" : 132,
"roughing_offset" : 0.3
}
}
and the code I am using is as follows:
public class PLMpartParameter
{
public class Parameters
{
public float bar_diameter;
public float core_height;
public float roughing_offset;
public Parameters(float barD, float coreH, float roughingO)
{
bar_diameter = barD;
core_height = coreH;
roughing_offset = roughingO;
}
}
public Parameters parameters;
public PLMpartParameter(Parameters param)
{
parameters = param;
}
}
public static void LoadJson()
{
using (System.IO.StreamReader r = new System.IO.StreamReader(#"C:\part_param.json"))
{
string json = r.ReadToEnd();
_logger.Info(string.Format("Read entire file complete. File Values: {0}", json));
try
{
PLMpartParameter part = Newtonsoft.Json.JsonConvert.DeserializeObject<PLMpartParameter>(json);
}
catch (Exception e)
{
_logger.Info(string.Format("Read Json failed {0}", e.Message));
}
}
What am I missing here?
I think the problem is your property is called 'parameters' but in your json it's 'part_parameters'.
You must add a JSON attribute above your property, so that your properties are recognized when deserializing your object.
you will find an example just below
public class Parameters
{
[JsonProperty("bar_diameter")]
public float bar_diameter;
[JsonProperty("core_height")]
public float core_height;
[JsonProperty("roughing_offset")]
public float roughing_offset;
public Parameters(float barD, float coreH, float roughingO)
{
bar_diameter = barD;
core_height = coreH;
roughing_offset = roughingO;
}
}
Quoting Prasad Telkikar's answer as that fixed it right away
Use json2csharp to get model for your json file, then deserialize your
json. You can use visual studio in build function to create class i.e.
Edit -> Paste special -> Paste JSON as Class
Here is class
> public class PartParameters {
> public double bar_diameter { get; set; }
> public int core_height { get; set; }
> public double roughing_offset { get; set; } }
>
> public class RootObject {
> public PartParameters part_parameters { get; set; } }
To deserialize, use below code
PLMpartParameter part =
Newtonsoft.Json.JsonConvert.DeserializeObject(json);
My final code looks like this, and its working!!
public class PartParameters
{
public double bar_diameter { get; set; }
public int core_height { get; set; }
public double roughing_offset { get; set; }
}
public class RootObject
{
public PartParameters part_parameters { get; set; }
}
public static void LoadJson()
{
using (System.IO.StreamReader r = new System.IO.StreamReader(#"C:\part_param.json"))
{
string json = r.ReadToEnd();
try
{
RootObject part = Newtonsoft.Json.JsonConvert.DeserializeObject<RootObject>(json);
_logger.Info(string.Format("list values : bardiameter: {0}, coreHeight: {1}, roughingOffset: {2}",
part.part_parameters.bar_diameter,part.part_parameters.core_height, part.part_parameters.roughing_offset));
}
catch (Exception e)
{
_logger.Info(string.Format("Read Json failed {0}", e.Message));
}
}
}
You have a few issues with your code:
You need to have default constructors for the classes (this is due to how serializers work with types - they are not going to understand your class-specific paramaterised constructor).
Your fields need to be settable properties (Just add {get;set;} and you should be good to go).
I would suggest you decorate the parameters property with [JsonProperty("part_parameters")] to get the deserialization
behaviour you're expecting.

DeserializeObject<T>(string s) in generic method in C# using Newtonsoft.JSON is not working

Currently I am just returning the json string to corresponding file from where Test1() is called and Deserializing there as ResponseClass r = JsonConvert.DeserializeObject(response_json)
Send part I forget to make a class [Serializable].Its working fine now.
Part1:
public class Movie
{
public string Name { get; set; }
public string Description { get; set; }
public string Classification { get; set; }
public string Studio { get; set; }
public DateTime? ReleaseDate { get; set; }
public List<string> Genres{ get; set; }
}
public class ResponseClass
{
public string SuccessStatus{ get; set; }
public string next_link { get; set; }
}
private void Test1<T,Q>()
{
string json = #"{
'Name': 'Bad Boys',
'ReleaseDate': '1995-4-7T00:00:00',
'Genres': [
'Action',
'Comedy'
]
}";
//Here making network call with above json and getting correct response_josn
Q response_obj = JsonConvert.DeserializeObject<Q>(reponse_json);
print(response_obj);
}
I am calling Test1() as follows on button click:
Test1<Movie, ResponseClass>();
For the above example I am getting print log as ClassName+Movie (T FullName).
I want to deserialize the string into that class. How to achieve that?
Part2 : If I have class as:
[Serializable]
public class Movie
{
public string Name;
public string Description;
public string Classification;
public string Studio;
public DateTime ReleaseDate;
public SubClass subClass;
public List<SubClass> lsubclass;
}
[Serializable] //This was the mistake.
public class SubClass
{
public string a;
public string b;
public List<string> ReleaseCountries;
}
private Movie createValidMovieJson()
{
Movie m = new Movie();
SubClass sc = new SubClass();
sc.a = "aaa";
sc.b = "bbb";
sc.ReleaseCountries = new List<string>();
sc.ReleaseCountries.Add("Japan");
sc.ReleaseCountries.Add("India");
List<SubClass> lsC = new List<SubClass>();
lsC.Add(sc);
lsC.Add(sc);
m.Name = "Bad Boys";
m.Studio = "Pixa";
m.subClass = sc;
m.lsubclass = lsC;
Debug.Log(JsonUtility.ToJson(m)); // value n log = {"Name":"Bad Boys","Description":"","Classification":"","Studio":"Pixa"}
return m;
}
JsonUtility is returning empty value in place of subclass after using ToJson() as shown in above function.
Based on the screenshot you added I think you are expecting to be able to treat the deserialized type as a Movie. This is the way to achieve that:
var movie = JsonConvert.DeserializeObject<Movie>(json);
Currently your deserialized object is being treated as type T - which could be anything since you have no generic type constraints on your method.
Like I said in the comment section, JsonUtility should do it.
I just replaced T m = JsonConvert.DeserializeObject(json); with T
m = JsonUtility.FromJson(json); it gives an error
ArgumentException: JSON parse error: Missing a name for object member.
Your json is invalid for JsonUtility. I believe you are using ' instead of ". This is why you are getting this error.
Use the function below to generate a valid json:
void createValidMovieJson()
{
Movie m = new Movie();
m.Name = "Bad Boys";
m.ReleaseCountries = new List<string>();
m.ReleaseCountries.Add("Japan");
m.Studio = "Pixa";
Debug.Log(JsonUtility.ToJson(m));
}
You will get:
{"Name":"Bad Boys","Description":"","Classification":"","Studio":"Pixa","ReleaseCountries":["Japan"]}
When ecaped for testing, you will get:
{\"Name\":\"Bad Boys\",\"Description\":\"\",\"Classification\":\"\",\"Studio\":\"Pixa\",\"ReleaseCountries\":[\"Japan\"]}
For JsonUtility to work, you must add [Serializable] to the class and remove { get; set; } from them class variables.
If your goal is to convert any json to any data type then you have to return generic type then use Convert.ChangeType to convert it to that type.
It should look something like this:
// Use this for initialization
void Start()
{
string json = "{\"Name\":\"Bad Boys\",\"Description\":\"\",\"Classification\":\"\",\"Studio\":\"Pixa\",\"ReleaseCountries\":[\"Japan\"]}";
Movie movie = Load<Movie>(json);
print(movie.Name);
}
[Serializable]
public class Movie
{
public string Name;
public string Description;
public string Classification;
public string Studio;
public DateTime? ReleaseDate;
public List<string> ReleaseCountries;
}
private T Load<T>(string json)
{
object resultValue = JsonUtility.FromJson<T>(json);
return (T)Convert.ChangeType(resultValue, typeof(T));
}

Handling generic properties via reflection

If I have the following wrapper class:
public class Wrapper<T>
{
public T Data { get; set; }
public string[] Metadata { get;set;
}
and another class then exposes that value without generics:
public class SomeOtherClass
{
public object WrappedData { get;set };
}
, how can I get at the original unwrapped data?
I can test for it, using something like:
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Wrapper<>))
{
dynamic originalValue = someOtherClass.WrappedData;
}
but I can't then call the .Data property on originalValue, getting a RuntimeBinderException.
Update
A little more context might help. I am working on a WebAPI where I am wanting to implement HATEOAS. So my wrapper class is containing the data that will be returned plus metadata, and I am writing an action filter that will unwrap the data, returning it in the response body, and put the metadata into response headers. The action filter is currently implemented as follows:
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
if (actionExecutedContext.Request.Method == HttpMethod.Get)
{
var objectContent = actionExecutedContext.Response.Content as ObjectContent;
if (objectContent != null)
{
var type = objectContent.ObjectType;
var formatter = actionExecutedContext
.ActionContext
.ControllerContext
.Configuration
.Formatters
.First(f => f.SupportedMediaTypes
.Contains(new MediaTypeHeaderValue(actionExecutedContext
.Response
.Content
.Headers
.ContentType
.MediaType)));
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Wrapper<>))
{
dynamic value = objectContent.Value;
actionExecutedContext.Response.Content = new ObjectContent(value.Data.GetType(), value.Data, formatter);
}
}
}
base.OnActionExecuted(actionExecutedContext);
}
Obviously not all my API endpoints currently wrap their data, so if the response is not returning a Wrapper<T> instance, I want to exit the action filter without modifying the response. If it is, then pull out the value of .Data and rewrite the response body with it.
It's not clear from the posted code what objectContent.ObjectType is, so I would modify the code to check the actual value:
object value = objectContent.Value;
if (value != null && value.GetType().IsGenericType && value.GetType().GetGenericTypeDefinition() == typeof(Wrapper<>))
{
object data = ((dynamic)value).Data;
actionExecutedContext.Response.Content = new ObjectContent(data.GetType(), data, formatter);
}
But you can avoid reflection and dynamic calls and make your life much easier if you backup your generic class with a non generic interface. For instance
public interface IWrapper
{
object Data { get; }
string[] Metadata { get; }
}
public class Wrapper<T> : IWrapper
{
public T Data { get; set; }
object IWrapper.Data { get { return Data; } }
public string[] Metadata { get; set; }
}
Then you can do simple
var wrapper = objectContent.Value as IWrapper;
if (wrapper != null)
{
actionExecutedContext.Response.Content = new ObjectContent(wrapper.Data.GetType(), wrapper.Data, formatter);
}
The following code works:
using System;
namespace ConsoleApplication1
{
class Program
{
public class Wrapper<T>
{
public T Data { get; set; }
public string[] Metadata
{
get; set;
}
}
public class SomeOtherClass
{
public object WrappedData { get; set; }
}
static void Main(string[] args)
{
var wrappedData = new Wrapper<int> { Data = 3 };
var someObject = new SomeOtherClass { WrappedData = wrappedData };
dynamic d = someObject.WrappedData;
Console.WriteLine(d.Data);
}
}
}
So, It isn't clear what your problem is!
Would it help if you added the type to your wrapper?
public class Wrapper<T>
{
public Type MyType{get;set;}
public T Data { get; set; }
public string[] Metadata { get;set;}
public Wrapper(T data){
MyType = data.GetType();
Data = data;
}
}
Unclear exactly what you are trying to do:
object obj = new Wrapper<SomeOtherClass> { Data = new SomeOtherClass { WrappedData = "Hello" } };
Type type = obj.GetType();
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Wrapper<>))
{
dynamic data = ((dynamic)obj).Data;
dynamic wrappedData = data.WrappedData;
}
Note that there is no guarantee that there is a WrappedData property inside the Data property: WrappedData is a property of SomeOtherClass, but for example obj could be:
object obj = new Wrapper<string> { Data = "Hello" };

Serializing object with interface as property type in MessagePack

I am trying to use MessagePack to serialize an object that has a property of an interface type. When I call Pack, it throws SerializationException that says a serializer is not defined for the interface.
Code example:
namespace ConsoleApplication1
{
// interfaces and classes declaration
public interface IDummyInterface { }
public class DummyObject : IDummyInterface
{
public string Value { get; set; }
}
public class SmartObject
{
public string Name { get; set; }
IDummyInterface DummyOne { get; set; }
}
// in main
var mySmartObject = new SmartObject() { Name = "Yosy", DummyOne = new DummyObject() { Value = "Value"} };
using(var stream = new MemoryStream())
{
var serializer = MessagePackSerializer.Create<SmartObject>();
serializer.Pack(mySmartObject, stream); // => This code throws the exception
}
}
Can I tell MessagePack which serializer to use for IDummyInterface and tell it to act as DummyObject?
It seems to me you are using msgpack-cli. To make it work, basically there are two ways to do it.
1. Use MessagePackKnownTypeAttribute
This one is easy and straightforward.
public class SmartObject
{
public string Name { get; set; }
[MessagePackKnownType("d", typeof(DummyObject))]
public IDummyInterface DummyOne { get; set; } // Need to make this property public
}
2. Implement custom serializer
If you want a clean model class without reference to MsgPack library, you can do the following, but you need to figure out a way to serialize/deserialize SmartObject (efficiently).
public class SmartObjectSerializer : MessagePackSerializer<SmartObject>
{
public SmartObjectSerializer(SerializationContext ownerContext) : base(ownerContext)
{
}
protected override void PackToCore(Packer packer, SmartObject objectTree)
{
var str = ToString(objectTree); // TODO: Just an example
packer.Pack(str);
}
protected override SmartObject UnpackFromCore(Unpacker unpacker)
{
var str = unpacker.LastReadData.AsStringUtf8(); // TODO: Just an example
return new SmartObject
{
// TODO: Initialize based on str value
};
}
}
// In main
var context = new SerializationContext();
context.Serializers.RegisterOverride(new SmartObjectSerializer(context));
var serializer = MessagePackSerializer.Get<SmartObject>(context);
// The rest is the same
There are some sample codes you may be interested to take a look.
CustomSerializer
Polymorphism

How to ensure that the serialization and deserialization with WebServices is symmetric?

I have a couple of standard ASP.NET web methods that I'm calling from javascript with a parameter that is of a custom class in form
[DataContract]
[KnownType(typeof(MyOtherSubclass))]
public class MyClass
{
[DataMember]
public MyOtherClass MyMember { get; set; }
}
where MyOtherClass is a class marked with Serializable but not with DataContract attribute (I don't have a control over its generation). There is a couple of subclasses of MyOtherClass, e.g. MyOtherSubclass :
[Serializable]
public class MyOtherSubClass : MyOtherClass
{
private string valueField;
public string Value
{
get { return valueField; }
set { valueField = value; }
}
}
When I use the DataContractJsonSerializer to serialize an object of MyClass directly, I get a result similar to
{ "MyMember" : { "__type" : "MyOtherSubClass:#Namespace", "valueField" : "xxx" } }
However, when I pass such a JSON into the web method request from javascript, I get an exception while deserializing. I have experimented a little bit and found that when using the following one instead
{ "MyMember" : { "___type" : "Namespace.MyOtherSubClass", "Value" : "xxx" } }
the deserialization works without any problems.
Is there any way to configure the DataContractJsonSerializer in such a way that it would produce the JSON in the second form, so that the web method arguments deserialization would work ?
ASP.NET WebMethods use JavaScriptSerializer, so try serializing with it. You might need a custom type resolver in order to include this property:
public class Parent
{
public string ParentProp { get; set; }
}
public class Child: Parent
{
public string ChildProp { get; set; }
}
public class CustomResolver : JavaScriptTypeResolver
{
public override Type ResolveType(string id)
{
return Type.GetType(id);
}
public override string ResolveTypeId(Type type)
{
return type.ToString();
}
}
class Program
{
static void Main(string[] args)
{
var o = new Child
{
ParentProp = "parent prop",
ChildProp = "child prop",
};
var serializer = new JavaScriptSerializer(new CustomResolver());
var s = serializer.Serialize(o);
Console.WriteLine(s);
}
}

Categories