@@ -104,6 +104,7 @@ tags, and then generate with `hack/update-toc.sh`.
104
104
- [ Unit tests] ( #unit-tests )
105
105
- [ Integration tests] ( #integration-tests )
106
106
- [ e2e tests] ( #e2e-tests )
107
+ - [ Custom JSON Marshalers] ( #custom-json-marshalers )
107
108
- [ Graduation Criteria] ( #graduation-criteria )
108
109
- [ Alpha] ( #alpha )
109
110
- [ Beta] ( #beta )
@@ -751,6 +752,48 @@ We expect no non-infra related flakes in the last month as a GA graduation crite
751
752
752
753
- request and response content-type negotiation with 1.17 sample API server
753
754
755
+ ### Custom JSON Marshalers
756
+
757
+ If a type implements json.Marshaler or json.Unmarshaler without corresponding CBOR behaviors,
758
+ serializing values of that type to and from CBOR using default behaviors risks mangling the data.
759
+
760
+ As an example, consider the structure of a marshalled
761
+ [ IntOrString] ( https://pkg.go.dev/k8s.io/apimachinery/pkg/util/intstr#IntOrString ) with the custom
762
+ behavior versus the default behavior:
763
+
764
+ | Go | Custom | Default |
765
+ | ------------------------------------------| ---------| ---------------------------------------|
766
+ | IntOrString{Type: Int, IntVal: 7} | 7 | {"IntVal":7,"StrVal":"","Type:":0} |
767
+ | IntOrString{Type: String, StrVal: "foo"} | "foo" | {"IntVal":0,"StrVal":"foo","Type:":1} |
768
+ | IntOrString{Type: -1} | <error > | {"IntVal":0,"StrVal":"","Type:":-1} |
769
+
770
+ Imagine a similar type is declared out-of-tree. It has a similar implementation of ` json.Marshaler ` ,
771
+ but not corresponding custom implementation for CBOR. From this type, a CRD and typed client are
772
+ generated. This typed client is used in a program to write to a custom resource, using JSON to
773
+ encode the request body as either a JSON number or a JSON string. On the server side, the request
774
+ body is decoded into an Unstructured object, and within that object, the IntOrString value is
775
+ represented by either a ` string ` or an ` int64 ` .
776
+
777
+ Now imagine that the same request is repeated, but with CBOR as the negotiated content type of the
778
+ request body, and that the CBOR serializer implementation _ does not_ recognize types that implement
779
+ ` json.Marshaler ` or ` json.Unmarshaler ` . By changing the request content type from JSON to CBOR, the
780
+ actual bytes of the request body represent a structurally different object. Referencing the table
781
+ above, instead of the "Custom" encoding, the encoded CBOR would look like the "Default" encoding.
782
+
783
+ On the server side, the value is represented within the decoded Unstructured as a
784
+ ` map[string]interface{} ` with three keys, ` "IntVal" ` , ` "StrVal ` ", and ` "Type" ` . A change in the
785
+ request encoding resulted in a structural change to the object the client intended to send.
786
+
787
+ The CBOR serializer must not use the default behaviors to marshal and unmarshal values that
788
+ implement only custom JSON behaviors. Rejecting them with an error is a minimum requirement for
789
+ alpha, since it prevents corruption. This would support in-tree types, server-side custom resource
790
+ serialization, and typical dynamic client usage. A second alpha release will support these types
791
+ automatically by invoking the JSON methods and transcoding to or from CBOR.
792
+
793
+ All of the above also applies to types implementing ` encoding.TextMarshaler ` (which is used if
794
+ implemented unless ` json.Marshaler ` is also implemented) and ` encoding.TextUnmarshaler ` (which is
795
+ used if implemented when the input is a JSON string unless ` json.Unmarshaler ` is also implemented).
796
+
754
797
### Graduation Criteria
755
798
756
799
<!--
@@ -823,11 +866,17 @@ in back-to-back releases.
823
866
- Client generation updated to support CBOR behind client-side gates.
824
867
- Runtime gating mechanism added to client-go.
825
868
- Maintenance of CBOR library is understood.
869
+ - Types that implement json.Marshaler or json.Unmarshaler without corresponding custom CBOR
870
+ behaviors are either rejected with an error on Encode and Decode or automatically transcoded from
871
+ JSON.
826
872
827
873
#### Beta
828
874
829
875
- Review of nondeterministic encoding mode and final decision on whether to keep
830
876
or remove it.
877
+ - To support rollback from beta to alpha, at least one alpha release has supported automatic
878
+ transcoding of types that implement json.Marshaler or json.Unmarshaler without corresponding
879
+ custom CBOR behaviors.
831
880
832
881
#### GA
833
882
0 commit comments