0
\$\begingroup\$

It seems JsonUtility.FromJson does not work for MonoBehaviour classes (and I can't get Newtonsoft to parse strings to Vector3s)

Suppose you have a MonoBehaviour class like this (so that the values can be easily specified in inspector in editor)


public class PropertyClass:MonoBehaviour{
  public Vector3 location;  

  public string name; 
}

Suppose you have json data downloaded as a string called text, that you try to convert to PropertyClass[] format via using an JSONHelper around JSONUtility.FromJson(text);

How do you have it autopopulate?

If you specify a FromJsonOverwrite solution - how do you have that work with JSONHelper?

using System;
using UnityEngine;
using System.Collections;

public static class JSONHelper
{
    public static T[] FromJson<T>(string json)
    {
        Wrapper<T> wrapper = UnityEngine.JsonUtility.FromJson<Wrapper<T>>(json);
        return wrapper.Items;
    }

    public static string ToJson<T>(T[] array)
    {
        Wrapper<T> wrapper = new Wrapper<T>();
        wrapper.Items = array;
        return UnityEngine.JsonUtility.ToJson(wrapper);
    }

    [Serializable]
    private class Wrapper<T>
    {
        public T[] Items;
    }
}
```
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Typically, you don't.

MonoBehaviour is not (de)serializable by JsonUtility.FromJson. Components only make sense when attached to GameObjects, so you can't serialize a collection of them then deserialize them into free-floating blobs unlinked from your scene and game object hierarchy.

This behaviour is described in the documentation, so be sure to consult the docs for the methods you're using:

Internally, this method uses the Unity serializer; therefore the type you are creating must be supported by the serializer. It must be a plain class/struct marked with the Serializable attribute. Fields of the object must have types supported by the serializer. Fields that have unsupported types, as well as private fields or fields marked with the NonSerialized attribute, will be ignored.

Only plain classes and structures are supported; classes derived from UnityEngine.Object (such as MonoBehaviour or ScriptableObject) are not.

JsonUtility.FromJsonOverwrite, however, will give you the ability to deserialize JSON into the serialized fields of an existing MonoBehaviour or ScriptableObject instance. So you can't load new scene content or a whole game object hierarchy this way, but you can update the properties of an object or collection of objects that already exists, while keeping their existing relationships to your various objects/scene graph intact.

Another strategy you can use is to give yourself a little serializable class or struct to hold your data, then pack that into a MonoBehaviour.

[System.Serializable]
public class PropertyClassData {
    public Vector3 location;
    public string name;
}

public class PropertyClass : MonoBehaviour { 
    public PropertyClassData data; 
}

Now you can use JSON, XML, BinaryWriters, etc. to serialize and deserialize collections of PropertyClassData, which is just a "Plain Old Data Structure" with no extra methods or entanglements in your scene hierarchy that need to be navigated. That keeps the (de)serialization simple and efficient, and lets you use the FromJson method without a pre-existing object to overwrite into. This also removes your dependency on the built-inUnity serializer, so you're free to drop in other solutions if you need different formats than it supports

Once you have those values, you can choose to construct GameObjects in your scene or Assets folder with PropertyClass components to hold the data items. Or you can read the data members from a collection of existing components into a serializable collection.

The trick here is to only ask to serialize the data payload you actually want, not all the complexity that the full MonoBehaviour type brings along for the ride.

\$\endgroup\$
5
  • \$\begingroup\$ Okay, wish i knew this limitation for monobehaviour before i manually added a bunch of values in inspector to a few hundred gameobjects... had thought jsonOverwrite could work here \$\endgroup\$
    – ina
    Nov 4, 2020 at 20:43
  • \$\begingroup\$ ok for now i'm just using kind of a cheap/fast trick - making ClasssnameData clones with properties only of all the previous monobehaviour classes used only for the deserialization step \$\endgroup\$
    – ina
    Nov 4, 2020 at 20:51
  • 1
    \$\begingroup\$ JsonOverwrite does support MonoBehaviours, as described in the docs: "Internally, this method uses the Unity serializer; therefore the object you pass in must be supported by the serializer: it must be a MonoBehaviour, ScriptableObject, or plain class/struct with the Serializable attribute applied." - but that's not what you showed in your question, so that's not the use case I wrote this answer for. \$\endgroup\$
    – DMGregory
    Nov 4, 2020 at 21:10
  • \$\begingroup\$ So why not use FromJsonOverwrite to de/serialize a MonoBehaviour to prevent having a redundant serialized data-only class? \$\endgroup\$
    – ina
    Nov 4, 2020 at 22:10
  • \$\begingroup\$ Read the answer and find out! 😉 \$\endgroup\$
    – DMGregory
    Nov 4, 2020 at 22:12

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .