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

Trying to use the message formatter throws "Unable to format value of type Microsoft.FSharp.Core.FSharpValueOption`1" for optional types #19

Open
marner2 opened this issue Oct 5, 2022 · 1 comment

Comments

@marner2
Copy link

marner2 commented Oct 5, 2022

This happens when trying to use the JsonFormatter for types with any optional fields.

Simple proto file:

message TestMessage {
  optional string TestField = 1;
}

Simple test:

let x = { TestMessage.empty() with TestField = ValueSome "hello" }
let string = Google.Protobuf.JsonFormatter.Default.Format(x)

Result:

  Message: 
System.ArgumentException : Unable to format value of type Microsoft.FSharp.Core.FSharpValueOption`1[System.String]

  Stack Trace: 
JsonFormatter.WriteValue(TextWriter writer, Object value)
JsonFormatter.WriteMessageFields(TextWriter writer, IMessage message, Boolean assumeFirstFieldWritten)
JsonFormatter.WriteMessage(TextWriter writer, IMessage message)
JsonFormatter.Format(IMessage message, TextWriter writer)
JsonFormatter.Format(IMessage message)
@marner2
Copy link
Author

marner2 commented Oct 5, 2022

You probably need something like this integrated into an FSharp version of the JsonFormatter (but for valueoptions):

type OptionConverter() =
  inherit JsonConverter()

  override x.CanConvert(t) = t.IsGenericType && t.GetGenericTypeDefinition() = typedefof<option<_>>

  override x.WriteJson(writer, outer, serializer) =

    let inner =
      if outer = null then
        null
      else
        let _, fields = FSharpValue.GetUnionFields(outer, outer.GetType())
        fields[0]

    if outer <> null && inner = null then
      writer.WriteStartObject()
      writer.WritePropertyName("Case")
      writer.WriteValue("None")
      writer.WriteEndObject()
    else
      serializer.Converters.Remove(x) |> ignore
      serializer.Serialize(writer, inner)
      serializer.Converters.Add(x)

  override x.ReadJson(reader, t, _existingValue, serializer) =
    let innerType = t.GetGenericArguments().[0]

    let innerType = if innerType.IsValueType then typedefof<Nullable<_>>.MakeGenericType [| innerType |] else innerType

    serializer.Converters.Remove(x) |> ignore
    let value = serializer.Deserialize(reader, innerType)
    serializer.Converters.Add(x)

    let cases = FSharpType.GetUnionCases(t)
    FSharpValue.MakeUnion(cases[1], [| value |])

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

1 participant