I don't believe I would have had this particular problem in Rust, because Rust fields, unlike Java ones, have a well-defined order.
They're not necessarily alphabetically sorted (that's up to the programmer), but I don't actually need them to be; I just need the order to be consistent.
The exception is Rust's HashMap, which intentionally uses a random order. IIRC it's to mitigate a potential denial-of-service attack. No problem if you use TreeMap or Vec<(_, _)> or something like that, though.
GPT-4o via Duck.ai suggested that I could fix this using SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS. Surprisingly, this seems to work.
However, this has the disturbing implication that JsonUnwrapped is causing Jackson to collect properties into a Map before serializing them. Seems bad for performance.
Fortunately, this code doesn't execute very often, so this slowdown isn't show-stopping.
I solved the problem by moving JsonAnySetter to a method that checks if the “unknown” property is actually one of the subobjects' properties, and if so, discards it.
That seems to work, but it's kind of brittle. 😬 I'm not sure what I would do if this was Rust. Some equally brittle thing involving traits, I guess.
In Rust, I suppose I would've seen this coming, because the way to flatten a subobject is to annotate it with serde(flatten), and that is also the way to record a list of unknown properties.
But this is a Java project, and the Jackson library has different annotations for these purposes: JsonUnwrapped for flattening, and JsonAnyGetter/JsonAnySetter for collecting unknown properties.
It was not obvious that JsonUnwrapped and JsonAnyGetter/JsonAnySetter would interact like this!
I have a data structure that deserializes from a #JSON object. It has a field for storing all unknown JSON properties. It also contains a couple of subobjects that are to be flattened into the containing object, as in #Rust serde(flatten) or #Java JsonAnyGetter/JsonAnySetter.
This has created a curious problem: upon serializing, any property in one of the flattened subobjects is *duplicated* in the list of unknown properties!