Comments (3)
Note that it's the shape of the JSON that I'm most interested in. I've tried other ways of representing that JSON in F#, such as:
type ListOperation = {
list : string
op : ListOperationUnion
}
where ListOperationUnion is | add of string list | remove of string list
. But this produces JSON that looks like:
{ list: "numbers", op: { add: ["one", "two"] } }
And I'd really like to not have the extra op
field in my API's shape.
from fsharp.systemtextjson.
It is a known limitation. What happens is that System.Text.Json deserialization doesn't work on an AST but in a single pass on the input stream. So to be able to determine which case it is, the JSON being parsed must have a non-overlapping field as its first field. To be able to round-trip, we would need to make the serializer write fields out of order to ensure that the first one is non-overlapping. I decided against this added complexity and instead went for the simpler rule of "all fields must be have different names".
That being said, it could be amended to "the first field of each case must have different names" while keeping serialization simple. It would enable your use case, provided that you swap the order of fields in your union cases so that "add" and "remove" come first.
from fsharp.systemtextjson.
That being said, it could be amended to "the first field of each case must have different names" while keeping serialization simple. It would enable your use case, provided that you swap the order of fields in your union cases so that "add" and "remove" come first.
It would be quite easy for me to swap the order of the union case fields, but if you're having to determine the union case based on the first field of the JSON, it's entirely possible that this would lead to a surprising failure case where { add: ["one", "two"], list: "numbers" }
parsed successfully but { list: "numbers", add: ["one", "two"] }
failed because the first field of the JSON was not enough to unambiguously resolve the case. The JSON spec says that "[a]n object is an unordered set of name/value pairs" (emphasis mine), so the fact that swapping the order of the fields causes it to fail would be a violation of the JSON spec. You can't count on the incoming JSON having been produced by the FSharp.SystemTextJson library, so although simply writing the fields in the correct order for deserialization would help round-tripping, it wouldn't be enough to guarantee that all valid JSON could be correctly deserialized.
So you'll have to stick with the "all fields must have different names" rule in order to guarantee that the first field you encounter will be sufficient to resolve the union case, and I might as well close this issue as there's no way to implement the feature I asked for given the single-pass nature of System.Text.Json. My fallback solution works rather well, anyway: I simply create a set of record types that each match a single possible API shape, and try deserializing each of those record types in turn, moving on to the next shape if deserializing throws a JSON encoding exception. It's slightly more work, but it works and gives me the API shape that I want. Thanks for your help, even if this feature turned out impossible to implement safely.
from fsharp.systemtextjson.
Related Issues (20)
- Congrats on 1.0, please avoid binary breaking changes 😊 HOT 8
- Regression: 1.0 can't deserialize to non-public records HOT 3
- Version 1.0 lost the ability to interpret missing field as None HOT 2
- Add Support for Untagged Unwrapped Single Cases
- `System.Reflection.TargetInvocationException` when serializing empty anonymous record HOT 1
- How to get the behaviour before breaking change #123 ? HOT 4
- [Bug] using `DefaultIgnoreCondition = WhenWritingNull` deserializes missing fields as null HOT 2
- String can be null on serialization but throws on deserialization HOT 3
- Never ending recursion when trying to handle recursive discriminated unions.
- JsonConverterAttribute applied to a record field is ignored HOT 4
- How handle full cases from first letter HOT 1
- Inconsistent behavior of nulls? HOT 4
- Map serialization with non-string keys (e.g. Guid keys) fails HOT 6
- using DefaultIgnoreCondition = WhenWritingNull deserializes missing fields as null HOT 5
- Types with mutual recursion are not supported HOT 2
- Translate JsonValue from/to F# data
- Unwrap the whole union into a record HOT 1
- Disallow null if not option-wrapped everywhere, not just for record fields HOT 6
- Allow using single-case unions as dictionary keys HOT 1
- Allow handling arbitrary Map keys as JSON object properties HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from fsharp.systemtextjson.