applejag / Newtonsoft.Json-for-Unity

Newtonsoft.Json (Json.NET) 10.0.3, 11.0.2, 12.0.3, & 13.0.1 for Unity IL2CPP builds, available via Unity Package Manager
https://github.com/jilleJr/Newtonsoft.Json-for-Unity
MIT License
1.15k stars 128 forks source link

Help: ApiException: Error Creating 'Newtonsoft.Json.Converters.StringEnumConverter' #38

Closed realworld666 closed 4 years ago

realworld666 commented 4 years ago

Expected behavior

JSON.net should deserialize by data into an enum

Actual behavior

Exception at runtime

Steps to reproduce

I'm trying to convert a string to an enum. My enum is tagged as follows

/// <summary>
        /// Defines Type
        /// </summary>
        [JsonConverter(typeof(StringEnumConverter))]
        public enum TypeEnum
        {

            /// <summary>
            /// Enum FuzzNet for value: FuzzNet
            /// </summary>
            [EnumMember(Value = "FuzzNet")]
            FuzzNet = 1,

            /// <summary>
            /// Enum TUB for value: TUB
            /// </summary>
            [EnumMember(Value = "TUB")]
            TUB = 2
        }

Upon trying to deserialize my object I get the error in the title

Details

Compiles and runs in the editor (Windows 2018.4.12) Compiles and throws an exception on Android and iOS Newtonsoft.Json-for-Unity package version 👉 12.0.201 I was using Unity version 👉 2018.4.12

realworld666 commented 4 years ago

Answering my own question, it looks like this might be a code stripping issue. Just calling new StringEnumConverter(); from somewhere in the codebase gets past this issue

applejag commented 4 years ago

Thanks for taking time to report the issue, even if you found a solution right after. I'd like to add to the topic though:

This can be solved by as you noticed calling the constructor in the code base, or use AotHelper to ensure the constructor without having it to actually run.

Read more about AotHelper over at the wiki

using Newtonsoft.Json.Utilities;
using Newtonsoft.Json.Converters;
using UnityEngine;

public class AotTypeEnforcer : MonoBehaviour
{
    public void Awake()
    {
        AotHelper.EnsureType<StringEnumConverter>();
    }
}

Another alternative is by specifying the constructor of the type to not get stripped away using a link.xml

<linker>
    <assembly fullname="Newtonsoft.Json">
        <type fullname="Newtonsoft.Json.Converters.StringEnumConverter">
            <method signature="System.Void .ctor()"/>
        </type>
    </assembly>
</linker>

Read more about link.xml over at the wiki

dh-pt commented 2 years ago

This is a breaking bug when compiling with Unity IL2CPP.

applejag commented 2 years ago

This is a breaking bug when compiling with Unity IL2CPP.

@dh-pt could you elaborate? Are you not able to use the workaround?

dh-pt commented 2 years ago

Ah apologies, I saw the workaround above and it did work. However, this is pretty niche knowledge. Is there a possibility of a more permanent solution?

applejag commented 2 years ago

Sorry but this is the permanent solution. The technical limitations of not allowing just-in-time compiled code is a major drawback of Unity's IL2CPP compiler, but the IL2CPP made it possible to run high-performant .NET code on platforms that doesn't support JIT, such as iOS, WebAssembly, smart-TVs, etc.

Can recommend the What even is AOT wiki page to learn more.

Some serializers, such as the Odin Serializer, generates similar link.xml and AotHelper equivalent files for you by inspecting your code, which is a really sophisticated solution.

If you're not locked to using Newtonsoft.Json, then I'd suggest digging into Odin, it's allegedly really good and fast, and is tailored to Unity both code wise and documentation wise.