-
-
Notifications
You must be signed in to change notification settings - Fork 39
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
Extra encoder doesn't get called for type with generic params #169
Extra encoder doesn't get called for type with generic params #169
Comments
I think the problem is coming from how we identify custom coders: Lines 11 to 16 in ca5930a
We are using Supporting your case will require to find a way to identify types with generic not filled and also change some mechanism in how we resolve the auto encoder and decoder. I don't know if detecting types with generic not provided is doable or not |
What about instead of always getting the full name of the provided type exactly as is, we get the generic version of the type, both when inserting into the map and when retrieving it? Something like this: let inline internal withCustomAndKey (encoder: Encoder<'Value>) (decoder: Decoder<'Value>)
(extra: ExtraCoders): ExtraCoders =
let theType = typeof<'Value>
// Get the type with any concrete generic parameters reset so that no matter what the specific type parameters are set, this returns the generic type
let genericVersionOfType = theType.GetGenericTypeDefinition ()
{ extra with
Hash = System.Guid.NewGuid().ToString()
Coders =
extra.Coders |> Map.add genericVersionOfType.FullName (Encode.boxEncoder encoder, Decode.boxDecoder decoder) } and similarly at the point where we look for extra coders, instead of Lines 441 to 443 in ca5930a
we could do something like: and private autoEncoder (extra: Map<string, ref<BoxedEncoder>>) caseStrategy (skipNullField : bool) (t: System.Type) : BoxedEncoder =
let genericVersionOfType = t.GetGenericTypeDefinition ()
let fullname = genericVersionOfType.FullName
match Map.tryFind fullname extra with
| Some encoderRef -> fun v -> encoderRef.contents v That way we can make a type name for the map key that doesn't include the type set in a generic parameter, both at the point of creating the coder and at the point of determining which coder should be used. |
One question that arises with the above is whether we want to include logic for supporting different coders for the same type if it has different type parameters set. I.e. do we want to let the user define different encoders for Personally I don't think this is necessary because if the user really wants to encode/decode different things differently they should just create a discriminated union containing different types in each variant and add different coders for each of the different types in the variants. So I think the initial idea of using the type-parameter-less name of the type is all that's needed to make this work. |
I will see if this breaks any tests or not.
I think that if the user want different representation depending on the "context" then he should use DUs or manual coder to have full control over what he does. In general, I think that a type as a single way of being represented. If this is not the case, user should use manual coders. |
Yes, agreed. Thank you. I can have a crack at it myself also if that would be helpful? |
@MangelMaxime I've had a go at making the changes myself. I haven't been able to run the tests because I can't get things to build on VS, but I've pushed up my work to this branch thoth-org/Thoth.Json.Net@main...Arrow7000:Thoth.Json.Net:use-generic-names-in-extras-map Lmk if you want me to make more changes and/or submit a PR 🙂 |
Hello @Arrow7000 thank you for your work. I didn't forget about your issue. I am trying to wrapping up another work that I already have started and will have a look at your issue and code after. I see that you made the changes for Thoth.Json.Net, could you open a PR on that repo and also make the same changes for Thoth.Json? Both projects being still splited we need to do the job twice... 😅 |
@MangelMaxime apologies for the delay. I've now submitted PRs for both repos. Let me know if you have any questions! Thanks again for looking at this |
I have the following type that I want to encode:
but I only want to encode the
node
field's value directly, because thesource
is not necessary for serialisation, and it would just add clutter to the generated JSON.I then try to encode a sample record using the following code
Yet I still consistently get this in my console
So it looks like either
Encode.Auto.generateEncoder () cstNode.node
isn't actually doing anything, or that my extra encoder is never even being called. I'm leaning towards the latter because theprintfn
statement in the body of the encoder is never appearing in my console, so it looks like it's never being called.Is it possible that this is because my type includes a generic type parameter which doesn't play nicely with the logic for checking whether a custom encoder needs to be invoked?
UPDATE: it looks like my suspicion was correct, because as soon as I make my encoder accept only a concrete type the encoder does get called
The console now says
However my CstNode contains a wide variety of types across my codebase, so having to specify explicit encoders for each one would defeat the whole point of using an auto encoder; plus there'd be no way to verify that I've accounted for all the types of generic that
CstNode
contains across my codebase.The text was updated successfully, but these errors were encountered: