Feat/add support for custom kinds - #2072
Conversation
… and support custom variant serialization - Override three-arg deserialize in JsonData._DESERIALIZER to correctly use parser.getValue() when the event is already consumed. - Add default _customKind() method to TaggedUnion interface returning null for built-in kinds. - Fall back to _customKind() in ExternallyTaggedUnion typed-keys serialization when jsonValue() is null.
…nions Add Kind._Custom to every discriminated tagged union to gracefully handle plugin-provided types. Unknown discriminator values are captured as _Custom with the raw JSON preserved as JsonData. - Add _Custom(null) enum constant, _customKind field, _isCustom(), _customKind(), _custom() accessors, and Builder._custom(type, data). - Add CustomVariant inner class with equals/hashCode. - Use _customKind in serialize when Kind is _Custom. - Include _customKind in equals()/hashCode(). - Validate type and data with ApiTypeHelper.requireNonNull(). - Wire unknownFieldHandler in internally-tagged deserializers and unknownVariantCtor in externally-tagged deserializers. - Add user guide section with read/build examples.
…and serialization - Test externally-tagged (Aggregate) deserialization of unknown type. - Test typed-keys round-trip serialization preserves custom type name. - Test internally-tagged (Query) round-trip. - Test Builder._custom() API and equality semantics. - Update CHANGELOG with feature and fix entries.
| WeightedAvg("weighted_avg"); | ||
| WeightedAvg("weighted_avg"), | ||
| /** A custom variant type not natively supported by this client. */ | ||
| _Custom(null); |
There was a problem hiding this comment.
Thanks for the pull request @acote-coveo , mostly all code for the Java client is being generated (this is why every source file has @Generated("org.opensearch.client.codegen.CodeGenerator") annotation and the comment on top).
Please submit the change to the OpenSearch OpenAPI specification so it could be picked up automatically: https://github.com/opensearch-project/opensearch-api-specification/blob/main/spec/schemas/_common.aggregations.yaml#L9
There was a problem hiding this comment.
@reta Thanks for the quick feedback. I just wanted to mention that I didn't explicitly modify the generated, I instead customized the generator template because I assumed that this kind of customization should not be part of the API specification. To me, the API specification should describe what OpenSearch supports. The custom kind that I added is a client-side concern to allow customization over the typed DSL.
Let me know with my answer if you still think this should be document at the API level.
There was a problem hiding this comment.
If I were to add this to the API Specification, I would probably add a new custom annotation to mark the variants that are non-exhaustive and from the generator, I would look for this tag to know if I should generate the _custom variant code I just added. The main benefits would be that:
- We could control which variants are open or not.
- Other generators would have the same signals to generate exhaustive vs non-exhaustive variants.
Description
This PR adds a
_Customvariant kind to all discriminated tagged unions (e.g.Aggregate,Suggest,Query,Property,Processor,Analyzer,TokenFilterDefinition) so that plugin-provided types are captured as raw JSON instead of causing deserialization failures.When the server returns a discriminator value that isn't natively modeled, the client stores it as
Kind._Customwith the original type name accessible via_customKind()and the raw JSON body via_custom(). This enables users to work with plugin-defined aggregations, queries, processors, etc. without waiting for a client release that models the new type.How It Works
Reading a custom variant:
Building a custom variant:
The same
_isCustom(),_customKind(),_custom(), andBuilder._custom(type, data)methods are available on every discriminated tagged union type.Changes
Infrastructure (
java-client/src/main/java):JsonData._DESERIALIZER: Fix three-argdeserializeoverload to correctly handle a pre-consumed parser event.TaggedUnion: Add default_customKind()method returning null for built-in kinds.ExternallyTaggedUnion: Use_customKind()fallback in typed-keys serialization whenjsonValue()is null; acceptunknownVariantCtorfor graceful deserialization of unknown types.Code generation templates (
java-codegen/):TaggedUnionShape.mustache: AddKind._Custom(null),_customKindfield, accessors,CustomVariantinner class with equals/hashCode, null-validated builder method, and updated equals/hashCode on the union itself.Deserialize.mustache: WireunknownFieldHandler(internally-tagged) andunknownVariantCtor(externally-tagged).Serialize.mustache: Use_customKindwhenKind._Customfor the JSON key.Documentation: Added "Custom (Plugin-Provided) Variant Types" section to
guides/json.md.Tests: Added
CustomVariantTestcovering deserialization, typed-keys round-trip serialization, internally-tagged round-trip, builder API, and equality semantics.Related
This approach aligns with the Elasticsearch Java client's
OpenTaggedUnionpattern, adapted for OpenSearch's typed variant interfaces.On ElasticSearch, they specify whether an Tagged Union should be open or not. I took the approach to extend everything that is discriminated to offer as much flexibility as allowed by the plugins.
Issues Resolved
Closes: