SaladLab / Json.Net.Unity3D

Forked Newtonsoft.Json to support Unity3D
MIT License
917 stars 170 forks source link

Unity iOS (De)SerializeObject<T>() doesnt work #7

Open dlapcenko opened 8 years ago

dlapcenko commented 8 years ago

Hi, thanks for your work!

Your fork works very good on my backend and performs well when sending data to frontend desktop Unity client. However on iOS it does not do anything at all. I don't have much data yet, since I'm not really sure how to debug it (and i can't access my project right now but it keeps boggling my mind so thought I'd ask now anyway).

There are no exceptions happening on the iOS. The JSON string is simply empty whenever iOS tries to de-/serialize. Either serializes into empty string or deserializes into empty object. I have the link.xml in /Assets, I did setup scripting backend to IL2CPP. Have tried .NET 2.0 and .NET 2.0 Subset as well but made no difference.

I guess actually seeing what iOS serializes object into would help, will try that in couple days when get the access.

Would you have any clue as to why this is happening?

Regards, D

KellanHiggins commented 8 years ago

If you can't get it working and are using Unity 5.3, you could use Unity's Json.net serializer. JSONUtility.FromJson(...). It's not as extensive as this fork but it will work for simple objects.

dlapcenko commented 8 years ago

Thanks. I was quite happy this fork gave the generic dictionary serialization functionality so I'd love to stick with it. Hopefully something could be done to fix the issue. I'll be trying to gather more debug info as soon as I get my hands on it.

KellanHiggins commented 8 years ago

Oh yeah, if you need that then unity's solution won't work.

veblush commented 8 years ago

Could you show me error message on iOS error case? There might be jit issues on this case and it's quite easy to fix this if this is related with jit problem. Check this article and part The game crashes with the error message "ExecutionEngineException: Attempting to JIT compile method ‘SometType`1:.ctor ()’ while running with –aot-only.

dlapcenko commented 8 years ago

Funnily enough there is no error message whatsoever. If I print the unserialized received object it is in correct JSON format, but when i try to deserialize it just does not work whatsoever, the lines with JSONConvert.Deserialize do not do anything, as well as the *.Serialize ones. and there is no exception whatsoever. I am sure your .dll is in the correct place, since it works on desktop client build. But this weird behaviour on iOS is concerning.. :/

dlapcenko commented 8 years ago
screen shot 2016-07-11 at 7 10 41 pm

Top debug line is the JSON object that I am receiving. second line (which states NULL) is trying to access the NAME field post-deserialization. No exception whatsoever.. simply a null object.

Any idea? :/ same behaviour in iOS simulator as well. possibly the binary is not being included properly? Or because I have not set up the JSON flags on any serialized class or property? (didn't do it before since for desktop everything works flawlessly without it)

Thanks for your time!

dlapcenko commented 8 years ago

SOLVED! the problem was with my object fields having {get; set;} accessors. as soon as i removed them - everything works.

issue could be closed, but perhaps not deleted, since someone else might experience same issue? Up to you, veblush. In any case - thanks for your fork!

veblush commented 8 years ago

Good to hear that it's solved. :smile: It's suspicious that IL2CPP striped out ctor of T or setter or name property. For further investigation, could you show me the definition of T which holds name property.

dlapcenko commented 8 years ago
    [System.Serializable]
    public class CharacterListItem
    {
        public int Id;
        public string Name;
        public int Level;
        public string Class;
        public string Sex;
    }

there you go, simple, but them getter-setters made all the difference. By your accounts, it should've been working with setters?

veblush commented 8 years ago

Thanks for sharing it. BTW following code was tested on Unity 5.3.5f1 targeting to iOS and worked successfully. There should be some differences between mine and yours.

[System.Serializable]
public class CharacterListItem
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Level { get; set; }
    public string Class { get; set; }
    public string Sex { get; set; }
}

void TestJson()
{
    var json = "{\"Id\":51,\"Name\":\"padre\",\"Level\":0,\"Class\":\"Vampire\",\"Sex\":\"F\"}";
    var c = JsonConvert.DeserializeObject<CharacterListItem>(json);
    WriteLine(c.Id + " " + c.Name);
}

Unity strips out some codes that are thought to be unnecessary by heuristic rules which have been changed a few times. Could you tell me your unity version and any idea around this code?

tmpsantos commented 7 years ago

Had the same issue with Unity 5.4. Removing { get; set; } and making attributes public fields partially solved the problem.

I think @veblush is right about IL2CPP wrongly stripping code. Adding the assemblies containing the serializable classes to link.xml telling IL2CPP to preserve it fixed for me.

diff --git a/example/playground/Assets/Plugins/link.xml b/example/playground/Assets/Plugins/link.xml
index 0e3e596..ae3ada0 100644
--- a/example/playground/Assets/Plugins/link.xml
+++ b/example/playground/Assets/Plugins/link.xml
@@ -1,4 +1,6 @@
 <linker>
+  <assembly fullname="MyAssembly" preserve="all"/>
   <assembly fullname="System">
     <type fullname="System.ComponentModel.TypeConverter" preserve="all"/>
     <type fullname="System.ComponentModel.ArrayConverter" preserve="all"/>
blake-r commented 7 years ago

@tmpsantos I had enough preserve Newtonsoft.Json assembly only. I tried preserve only ContainerWrapper and DictionaryWrapper, but it was unsufficient.

<assembly fullname="Newtonsoft.Json" preserve="all"/>

AngelKyriako commented 5 years ago

@veblush Any news on this ?

I am seeing this behaviour as well in webGL build with either unity 2017.4 or 2018.2.

While the AOT newtonsoft assembly works as expected within the editor, in a webGL build a simple class with public get; set; properties always serializes to empty object.

I will do some more tests on an empty project to check it out, but I was wondering if anything has been done to resolve this.

Harriet92 commented 5 years ago

Hi guys! I have this strange issue only on iOS - when I'm trying to serialize an object with an interface array it just stops without throwing any errors - I have debug logs before and after serialization and the first log always appears on console, and the other one only when I do not have the IInterface[] field in the dto object.

[code=CSharp]private JsonSerializerSettings allNameHandlingSettings = new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.All, NullValueHandling = NullValueHandling.Ignore };

public string Serialize<T>(T objectToSerialize)
{
    Debug.Log("Serializing...");
    var str = JsonConvert.SerializeObject(objectToSerialize, Formatting.Indented, allNameHandlingSettings);
    Debug.Log("Finished serializing");
    return str;
}[/code]

works for

[code=CSharp][Serializable] private class DtoTest { public string TestString; }[/code]

silently fails before writing the second log for:

[code=CSharp][Serializable] private class DtoTest { public string TestString; public IComponent[] components; }[/code]

Do you have any ideas? Apart from that it works perfectly...