Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JsonConverterAttribute applied to a record field is ignored #148

Open
kyryloboiev opened this issue Jan 18, 2023 · 4 comments
Open

JsonConverterAttribute applied to a record field is ignored #148

kyryloboiev opened this issue Jan 18, 2023 · 4 comments

Comments

@kyryloboiev
Copy link

kyryloboiev commented Jan 18, 2023

I have a Robot type with a string property Model
I get an json that has a Model type with Name and Version
for this I create a ModelConverter and expect to process and return string

module Tests

open System
open System.Text.Json
open System.Text.Json.Serialization
open Xunit

[<JsonFSharpConverter>]
type Model = { Name:string; Version:string }

[<Sealed>]
type ModelConverter ()  =
    inherit JsonConverter<string> ()
    override __.CanConvert(t) = t = typeof<Model>
    override __.Write(_, _, _) = raise (NotImplementedException())
    override __.Read (reader, _, _) =
        match reader.TokenType with
        | JsonTokenType.Number -> reader.GetInt32() |> string
        | JsonTokenType.String -> reader.GetString()
        | JsonTokenType.StartObject ->
            let result = JsonSerializer.Deserialize<{| Name:string; Version:string|}>(&reader)
            result.Name + result.Version
        | _ -> raise <| JsonException("Unexpected token type")

type Robot = {
     Code : int
     [<JsonConverter(typeof<ModelConverter >)>]
     Model : string
}

let r2d2 = { Code = 123; Model = "R2D2v1.0" } }

let options = JsonSerializerOptions()
options.Converters.Add(ModelConverter ())

[<Fact>]
let ``**should return string** Model`` () =
    Assert.Equal(r2d2, JsonSerializer.Deserialize<Robot>( """{"Code":123,"Model":{"Name":"R2D2","Version":"v1.0"}}""", options))

System.InvalidOperationException
The converter specified on 'Tests+Robot.Model' is not compatible with the type 'System.String'.
   at System.Text.Json.ThrowHelper.ThrowInvalidOperationException_SerializationConverterOnAttributeNotCompatible(Type classTypeAttributeIsOn, MemberInfo memberInfo, Type typeToConvert)
   at System.Text.Json.Serialization.Metadata.DefaultJsonTypeInfoResolver.GetConverterFromAttribute(JsonConverterAttribute converterAttribute, Type typeToConvert, MemberInfo memberInfo, JsonSerializerOptions options)
   at System.Text.Json.Serialization.Metadata.DefaultJsonTypeInfoResolver.GetCustomConverterForMember(Type typeToConvert, MemberInfo memberInfo, JsonSerializerOptions options)
   at System.Text.Json.Serialization.Metadata.ReflectionJsonTypeInfo`1.CreateProperty(Type typeToConvert, MemberInfo memberInfo, JsonSerializerOptions options, Boolean shouldCheckForRequiredKeyword)
   at System.Text.Json.Serialization.Metadata.ReflectionJsonTypeInfo`1.CacheMember(Type typeToConvert, MemberInfo memberInfo, Boolean& propertyOrderSpecified, Dictionary`2& ignoredMembers, Boolean shouldCheckForRequiredKeyword)
   at System.Text.Json.Serialization.Metadata.ReflectionJsonTypeInfo`1.LateAddProperties()
   at System.Text.Json.Serialization.Metadata.JsonTypeInfo.InitializePropertyCache()
   at System.Text.Json.Serialization.Metadata.JsonTypeInfo.Configure()
   at System.Text.Json.Serialization.Metadata.JsonTypeInfo.<EnsureConfigured>g__ConfigureLocked|143_0()
   at System.Text.Json.Serialization.Metadata.JsonTypeInfo.EnsureConfigured()
   at System.Text.Json.JsonSerializerOptions.GetTypeInfoInternal(Type type, Boolean ensureConfigured, Boolean resolveIfMutable)
   at System.Text.Json.JsonSerializer.GetTypeInfo(JsonSerializerOptions options, Type inputType)
   at System.Text.Json.JsonSerializer.Deserialize[TValue](String json, JsonSerializerOptions options)
   at Tests.should return number code() in C:\TestProject1\Tests.fs:line 36
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
   at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)```
@kyryloboiev kyryloboiev changed the title FSharp.SystemTextJson ignoring converters JsonConverterAttribute applied to a record field is ignored Jan 19, 2023
@xperiandri
Copy link
Contributor

@Tarmil do you agree that this has to work?

@mishun
Copy link

mishun commented Nov 22, 2023

I've tested the code above a bit, and it seems that it works if you replace CanConvert with:

override __.CanConvert(t) = t = typeof<string>

at least since version 1.0.7 (which, judging from date in nuget was actual when this issue was raised)

@mishun
Copy link

mishun commented Nov 22, 2023

Also peculiar fact: if you add [<JsonFSharpConverter>] attribute to Robot record then it still works under version 1.0.7, but throws

Unhandled exception. System.Text.Json.JsonException: The JSON value could not be converted to System.String. Path: $ | LineNumber: 0 | BytePositionInLine: 1.

under 1.1.23 and later versions, which may be a bug.

@xperiandri
Copy link
Contributor

@Tarmil can this be fixed?
I tried to figure out myself how to do that but had no luck.
Or maybe you at least suggest what to do?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants