1

I have a class:

using System;

[Serializable]
public class GameMessage
{
    public string cmd;
    public object data;
    public string seedId;
    public string peerId;

    public GameMessage( string cmd, object data, string seedId = null, string peerId = null )
    {
        this.cmd = cmd;
        this.data = data;
        this.seedId = seedId;
        this.peerId = peerId;
    }
}

And in some place at the code I calling:

JsonUtility.ToJson(new GameMessage("chat/say", "hello!"));

After this operation, I don't have data property in result JSON. The result is: {"cmd":"chat/say","seedId":"","peerId":""}

What's wrong? Why data doesn't appear in final JSON structure.

data has any type. (possible string, custom object, float, array, etc...)

EDIT: I'm looking for some workaround solution for my data with serialization and deserialization because JsonUtility doesn't support all primitive data types as root for data and require only to parse UnityEngine.Object object.

xercool
  • 883
  • 1
  • 8
  • 24
  • try your data as string instead. convert to byte array and then convert to string – Everts Sep 19 '17 at 14:38
  • but how to deserialize `byte []` data type? If It could be please provide snippet with your answer – xercool Sep 19 '17 at 14:40
  • my bad I edited the comment. It should be string. – Everts Sep 19 '17 at 14:41
  • the string is not okay because `JsonUtility` can't deserialize string to an array for example... I tried – xercool Sep 19 '17 at 14:42
  • *"data has any type. (possible string, custom object, float, array, etc...)"* ... `JsonUtility` cannot serialize/deserialize `object` type. You must give the type of that object. – Programmer Sep 19 '17 at 14:43
  • But once you got your string, this is where you convert to array. Use Convert.BaseToString64 and Encoding.ASCII.GetBytes(); – Everts Sep 19 '17 at 14:43
  • `JsonUtility` can't deserialize string to arrays, objects, floats... It supports only `UnityEngine.Object` as I said before. but I'd like to implement data as the mixed datatype. Well, I'm looking for some workaround solution... – xercool Sep 19 '17 at 14:46
  • ok it cannot but can't YOU? After your deserialize, your GameMessage contains a string. But the consumer class accesses a Data property that converts public byte [] Data{ get { return Encoding.ASCII.GetBytes(this.dataStr); } } – Everts Sep 19 '17 at 14:48
  • Could you clarify your idea with the full answer? :) – xercool Sep 19 '17 at 14:52

2 Answers2

1

So JSONUtility does not support object serialization. Makes sense when you think that an object type reference is just a four bytes address with no knowledge of the actual size of the object. So the serializer has no way to know what is the data to serialize.

You can turn your byte [] into a string64. That string can be serialized by the JsonUtility. Here is how your class would look:

[Serializable]
public class GameMessage
{
    public string cmd;
    public string data;
    public string seedId;
    public string peerId;
    public byte [] Data{ get { return Encoding.ASCII.GetBytes(this.data); } }

    public GameMessage( string cmd, byte[] data, string seedId = null, string peerId = null )
    {
        this.cmd = cmd;
        this.data = Convert.BaseToString64(data);
        this.seedId = seedId;
        this.peerId = peerId;
    }
}

Here is how you use the class ctor, considering any type can be the data, you can use this method (Convert any object to a byte[]):

byte[] ObjectToByteArray(object obj)
byte[] ObjectToByteArray(object obj)
{
    if(obj == null)
        return null;
    BinaryFormatter bf = new BinaryFormatter();
    using (MemoryStream ms = new MemoryStream())
    {
        bf.Serialize(ms, obj);
        return ms.ToArray();
    }
}
object ByteArrayToObject(byte[] buffer)
{
    MemoryStream ms = new MemoryStream (buffer);
    BinaryFormatter bf = new BinaryFormatter ();
    return bf.Deserialize (ms);
}

Now let's say you have a float of value 5.12f

float f = 5.12f;
GameMessage gm = new GameMessage("chat/say", ObjectToByteArray((object)f));
string json = JsonUtility.ToJson(gm);

Now you want to retrieve it:

var gm = JsonUtility.FromJson<GameMessage> (json);
byte[] array = gm.Data;
object f = ByteArrayToObject (array);
Debug.Log (f);

The return item is of type object. If you need to know its type (since you said it can be any type, you may want to know what it was before serialization), just use:

f.GetType();

this will tell you what it actually is. There is no straightforward way to cast using a Type reference. You'd have to go through reflection or dynamic.

C# is a strongly typed language (as opposed to languages like Javascript or Php where you can somehow switch type of a variable). For this reason, when you end up like in your situation, where any given type is welcome, this is no good design and will lead to issues or huge code, hard to maintain. You should probably restrict the possibilities.

Everts
  • 10,408
  • 2
  • 34
  • 45
  • But I have Node.js on the backend and it also should read that serialized base64 string. I guess It will not work... – xercool Sep 19 '17 at 19:46
0

Solved by using Unity Newtonsoft.Json library.

xercool
  • 883
  • 1
  • 8
  • 24