Skip to content
This repository has been archived by the owner on Oct 6, 2023. It is now read-only.

JsonConverter type of: UnixDateTimeConverter throws exception #8

Closed
FunkeeDan opened this issue Oct 21, 2019 · 5 comments · Fixed by #72
Closed

JsonConverter type of: UnixDateTimeConverter throws exception #8

FunkeeDan opened this issue Oct 21, 2019 · 5 comments · Fixed by #72
Labels
misconfigured Can be resolved by change in the configuration/usage
Milestone

Comments

@FunkeeDan
Copy link

FunkeeDan commented Oct 21, 2019

C# Destination types

[JsonConverter(typeof(UnixDateTimeConverter))]
public DateTime startdate;
[JsonConverter(typeof(UnixDateTimeConverter))]
public DateTime enddate;

Source JSON

{"data":[{"startdate":1568067791,"enddate":1577836800}],"state":""}

Expected behavior

The Json.NET package should deserialise the unix timestamp in the json data to System.DateTime instead of as an integer/string/other. This value deserialises correctly in Editor.

Actual behavior

When running an iOS build on iPhone this code throws exceptions:

JsonException: No parameterless constructor defined for 'Newtonsoft.Json.Converters.UnixDateTimeConverter'.
 at Newtonsoft.Json.Serialization.JsonTypeReflector+<>c__DisplayClass22_0.<GetCreator>b__0 (System.Object[] parameters) [0x00000] in <00000000000000000000000000000000>:0 
 at Newtonsoft.Json.Serialization.JsonTypeReflector.GetJsonConverter (System.Object attributeProvider) [0x00000] in <00000000000000000000000000000000>:0 
 at Newtonsoft.Json.Serialization.DefaultContractResolver.SetPropertySettingsFromAttributes (Newtonsoft.Json.Serialization.JsonProperty property, System.Object attributeProvider, System.String name, System.Type declaringType, Newtonsoft.Json.MemberSerialization memberSerialization, System.Boolean& allowNonPublicAccess) [0x00000] in <00000000000000000000000000000000>:0 
 at Newtonsoft.Json.Serialization.DefaultContractResolver.CreateProperty (System.Reflection.MemberInfo member, Newtonsoft.Json.MemberSerialization memberSerialization) [0x00000] in <00000000000000000000000000000000>:0 
 at Newtonsoft.Json.Serialization.DefaultContractResolver.CreateProperties (System.Type type, Newtonsoft.Json.MemberSerialization memberSerialization) [0x00000] in <00000000000000000000000000000000>:0 
 at Newtonsoft.Json.Serialization.DefaultContractResolver.CreateObjectContract (System.Type objectType) [0x00000] in <00000000000000000000000000000000>:0 
 at Newtonsoft.Json.Serialization.DefaultContractResolver.CreateContract (System.Type objectType) [0x00000] in <00000000000000000000000000000000>:0 
 at System.Collections.Concurrent.ConcurrentDictionary`2[TKey,TValue].GetOrAdd (TKey key, System.Func`2[T,TResult] valueFactory) [0x00000] in <00000000000000000000000000000000>:0 
 at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateList (System.Collections.IList list, Newtonsoft.Json.JsonReader reader, Newtonsoft.Json.Serialization.JsonArrayContract contract, Newtonsoft.Json.Serialization.JsonProperty containerProperty, System.String id) [0x00000] in <00000000000000000000000000000000>:0 
 at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList (Newtonsoft.Json.JsonReader reader, System.Type objectType, Newtonsoft.Json.Serialization.JsonContract contract, Newtonsoft.Json.Serialization.JsonProperty member, System.Object existingValue, System.String id) [0x00000] in <00000000000000000000000000000000>:0 
 at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue (Newtonsoft.Json.Serialization.JsonProperty property, Newtonsoft.Json.JsonConverter propertyConverter, Newtonsoft.Json.Serialization.JsonContainerContract containerContract, Newtonsoft.Json.Serialization.JsonProperty containerProperty, Newtonsoft.Json.JsonReader reader, System.Object target) [0x00000] in <00000000000000000000000000000000>:0 
 at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject (System.Object newObject, Newtonsoft.Json.JsonReader reader, Newtonsoft.Json.Serialization.JsonObjectContract contract, Newtonsoft.Json.Serialization.JsonProperty member, System.String id) [0x00000] in <00000000000000000000000000000000>:0 
 at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject (Newtonsoft.Json.JsonReader reader, System.Type objectType, Newtonsoft.Json.Serialization.JsonContract contract, Newtonsoft.Json.Serialization.JsonProperty member, Newtonsoft.Json.Serialization.JsonContainerContract containerContract, Newtonsoft.Json.Serialization.JsonProperty containerMember, System.Object existingValue) [0x00000] in <00000000000000000000000000000000>:0 
 at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize (Newtonsoft.Json.JsonReader reader, System.Type objectType, System.Boolean checkAdditionalContent) [0x00000] in <00000000000000000000000000000000>:0 
 at Newtonsoft.Json.JsonSerializer.DeserializeInternal (Newtonsoft.Json.JsonReader reader, System.Type objectType) [0x00000] in <00000000000000000000000000000000>:0 
 at Newtonsoft.Json.JsonConvert.DeserializeObject (System.String value, System.Type type, Newtonsoft.Json.JsonSerializerSettings settings) [0x00000] in <00000000000000000000000000000000>:0 
 at Newtonsoft.Json.JsonConvert.DeserializeObject[T] (System.String value, Newtonsoft.Json.JsonSerializerSettings settings) [0x00000] in <00000000000000000000000000000000>:0 
 at ProductGenius.Utilities.ServerFunctions+<>c__DisplayClass4_0`1[T].<GetData>b__0 (System.String json) [0x00000] in <00000000000000000000000000000000>:0 
 at ProductGenius.Utilities.ServerFunctions+<RetrieveTextData>d__5.MoveNext () [0x00000] in <00000000000000000000000000000000>:0 
 at UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) [0x00000] in <00000000000000000000000000000000>:0 
Rethrow as JsonException: Error creating 'Newtonsoft.Json.Converters.UnixDateTimeConverter'.
 at Newtonsoft.Json.Serialization.JsonTypeReflector+<>c__DisplayClass22_0.<GetCreator>b__0 (System.Object[] parameters) [0x00000] in <00000000000000000000000000000000>:0 
 at Newtonsoft.Json.Serialization.JsonTypeReflector.GetJsonConverter (System.Object attributeProvider) [0x00000] in <00000000000000000000000000000000>:0 
 at Newtonsoft.Json.Serialization.DefaultContractResolver.SetPropertySettingsFromAttributes (Newtonsoft.Json.Serialization.JsonProperty property, System.Object attributeProvider, System.String name, System.Type declaringType, Newtonsoft.Json.MemberSerialization memberSerialization, System.Boolean& allowNonPublicAccess) [0x00000] in <00000000000000000000000000000000>:0 
 at Newtonsoft.Json.Serialization.DefaultContractResolver.CreateProperty (System.Reflection.MemberInfo member, Newtonsoft.Json.MemberSerialization memberSerialization) [0x00000] in <00000000000000000000000000000000>:0 
 at Newtonsoft.Json.Serialization.DefaultContractResolver.CreateProperties (System.Type type, Newtonsoft.Json.MemberSerialization memberSerialization) [0x00000] in <00000000000000000000000000000000>:0 
 at Newtonsoft.Json.Serialization.DefaultContractResolver.CreateObjectContract (System.Type objectType) [0x00000] in <00000000000000000000000000000000>:0 
 at Newtonsoft.Json.Serialization.DefaultContractResolver.CreateContract (System.Type objectType) [0x00000] in <00000000000000000000000000000000>:0 
 at System.Collections.Concurrent.ConcurrentDictionary`2[TKey,TValue].GetOrAdd (TKey key, System.Func`2[T,TResult] valueFactory) [0x00000] in <00000000000000000000000000000000>:0 
 at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateList (System.Collections.IList list, Newtonsoft.Json.JsonReader reader, Newtonsoft.Json.Serialization.JsonArrayContract contract, Newtonsoft.Json.Serialization.JsonProperty containerProperty, System.String id) [0x00000] in <00000000000000000000000000000000>:0 
 at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList (Newtonsoft.Json.JsonReader reader, System.Type objectType, Newtonsoft.Json.Serialization.JsonContract contract, Newtonsoft.Json.Serialization.JsonProperty member, System.Object existingValue, System.String id) [0x00000] in <00000000000000000000000000000000>:0 
 at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue (Newtonsoft.Json.Serialization.JsonProperty property, Newtonsoft.Json.JsonConverter propertyConverter, Newtonsoft.Json.Serialization.JsonContainerContract containerContract, Newtonsoft.Json.Serialization.JsonProperty containerProperty, Newtonsoft.Json.JsonReader reader, System.Object target) [0x00000] in <00000000000000000000000000000000>:0 
 at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject (System.Object newObject, Newtonsoft.Json.JsonReader reader, Newtonsoft.Json.Serialization.JsonObjectContract contract, Newtonsoft.Json.Serialization.JsonProperty member, System.String id) [0x00000] in <00000000000000000000000000000000>:0 
 at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject (Newtonsoft.Json.JsonReader reader, System.Type objectType, Newtonsoft.Json.Serialization.JsonContract contract, Newtonsoft.Json.Serialization.JsonProperty member, Newtonsoft.Json.Serialization.JsonContainerContract containerContract, Newtonsoft.Json.Serialization.JsonProperty containerMember, System.Object existingValue) [0x00000] in <00000000000000000000000000000000>:0 
 at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize (Newtonsoft.Json.JsonReader reader, System.Type objectType, System.Boolean checkAdditionalContent) [0x00000] in <00000000000000000000000000000000>:0 
 at Newtonsoft.Json.JsonSerializer.DeserializeInternal (Newtonsoft.Json.JsonReader reader, System.Type objectType) [0x00000] in <00000000000000000000000000000000>:0 
 at Newtonsoft.Json.JsonConvert.DeserializeObject (System.String value, System.Type type, Newtonsoft.Json.JsonSerializerSettings settings) [0x00000] in <00000000000000000000000000000000>:0 
 at Newtonsoft.Json.JsonConvert.DeserializeObject[T] (System.String value, Newtonsoft.Json.JsonSerializerSettings settings) [0x00000] in <00000000000000000000000000000000>:0 
 at ApplicationNameRedacted.Utilities.ServerFunctions+<>c__DisplayClass4_0`1[T].<GetData>b__0 (System.String json) [0x00000] in <00000000000000000000000000000000>:0 
 at ApplicationNameRedacted.Utilities.ServerFunctions+<RetrieveTextData>d__5.MoveNext () [0x00000] in <00000000000000000000000000000000>:0 
 at UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) [0x00000] in <00000000000000000000000000000000>:0 

Steps to reproduce

  1. Create a C# class that includes DateTime types and add the JsonConverter attribute above a field:
    [JsonConverter(typeof(UnixDateTimeConverter))]
  2. Provide some valid Json which includes a unix timestamp value e.g.:
    "startdate":1568067791
  3. Set up code to deserialise your Json to a class of the type created in step 1 using:
    Newtonsoft.Json.JsonConvert.DeserializeObject<T>
  4. 'Build And Run' while targeting iOS.
  5. When the code is executed in your build, the above exception is thrown and is visible in the XCode console.
@FunkeeDan FunkeeDan changed the title JsonConverter for UnixTimestampConverter JsonConverter type of: UnixDateTimeConverter throws exception Oct 21, 2019
@applejag
Copy link
Owner

Assuming this works on other platforms such as in the editor, and since you're targeting iOS specifically which has stricter stripping rules than other AOT platforms, I'm assuming this is due to bytecode stripping removing the UnixDateTimeConverter.

Perhaps just referring to the type is not good enough.

To fix, add this link.xml file to your Assets folder (anywhere):

<linker>
    <assembly fullname="Newtonsoft.Json">
        <type fullname="Newtonsoft.Json.Converters.UnixDateTimeConverter" preserve="all"/>
    </assembly>
</linker>

@applejag applejag added bug Something isn't working bug:aot Troubles with Ahead Of Time compilation misconfigured Can be resolved by change in the configuration/usage and removed bug Something isn't working bug:aot Troubles with Ahead Of Time compilation labels Oct 21, 2019
@FunkeeDan
Copy link
Author

Assuming this works on other platforms such as in the editor, and since you're targeting iOS specifically which has stricter stripping rules than other AOT platforms, I'm assuming this is due to bytecode stripping removing the UnixDateTimeConverter.

Perhaps just referring to the type is not good enough.

To fix, add this link.xml file to your Assets folder (anywhere):

<linker>
    <assembly fullname="Newtonsoft.Json">
        <type fullname="Newtonsoft.Json.Converters.UnixDateTimeConverter" preserve="all"/>
    </assembly>
</linker>

This worked. Thanks for the workaround.

@applejag
Copy link
Owner

Cool!

Keeping this issue open as a future note to myself to add documentation about adding link.xml files.

@FunkeeDan
Copy link
Author

The call stack above for UnixDateTimeConverter looks like it is using some reflection. I'm guessing that's why it's getting code stripped despite being referenced in my managed code. There will probably be similar issues with other JsonConverter types.

@applejag
Copy link
Owner

Yes this is a very common and known issue. What I may do instead is force the linker to include all converters by default. Instead of having to specify it explicitly.

Problem with that is then there wont be a way to strip them anymore. A price we all can pay I presume. Talking few small classes either way.

applejag added a commit that referenced this issue Jan 10, 2021
applejag added a commit that referenced this issue Jan 10, 2021
- Moved link.xml into Newtonsoft.Json.csproj as embedded resource

- Fixed LogicalName

- Added preservations for the NullableAttribute and NullableContextAttribute to resolve #54

- Added some more preservations for some converters to resolve #8 and #65

- Updated CHANGELOG.md
@applejag applejag added this to the 12.0.302 milestone Jan 10, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
misconfigured Can be resolved by change in the configuration/usage
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants