44import io .vertx .core .json .JsonObject ;
55
66/**
7- * JSON {@link WireFormat}. Carries the protobuf-aware writer/reader flags that
8- * {@link ProtobufJsonWriter} and {@link ProtobufJsonReader} consult.
7+ * JSON {@link WireFormat}. Carries the protobuf-aware writer/reader flags that the JSON
8+ * encoder and decoder consult.
99 * <p>
1010 * Instances are immutable. Each flag setter returns a new instance with that flag updated:
1111 * <pre>
@@ -19,160 +19,150 @@ public class JsonWireFormat implements WireFormat {
1919
2020 public static final String NAME = "json" ;
2121
22- /**
23- * Default {@code alwaysPrintFieldsWithNoPresence} flag = {@code false}.
24- */
25- public static final boolean DEFAULT_ALWAYS_PRINT_FIELDS_WITH_NO_PRESENCE = false ;
22+ private static final String MEDIA_TYPE = "application/grpc+json" ;
23+ private static final JsonWireFormat [] CACHE = new JsonWireFormat [1 << Flag .values ().length ];
2624
27- /**
28- * Default {@code omittingInsignificantWhitespace} flag = {@code false}.
29- */
30- public static final boolean DEFAULT_OMITTING_INSIGNIFICANT_WHITESPACE = false ;
25+ private final byte flags ;
3126
32- /**
33- * Default {@code preservingProtoFieldNames} flag = {@code false}.
34- */
35- public static final boolean DEFAULT_PRESERVING_PROTO_FIELD_NAMES = false ;
27+ public JsonWireFormat () {
28+ this ((byte ) 0 );
29+ }
3630
37- /**
38- * Default {@code printingEnumsAsInts} flag = {@code false}.
39- */
40- public static final boolean DEFAULT_PRINTING_ENUMS_AS_INTS = false ;
31+ private JsonWireFormat (byte flags ) {
32+ this .flags = flags ;
33+ }
4134
42- /**
43- * Default {@code sortingMapKeys} flag = {@code false}.
44- */
45- public static final boolean DEFAULT_SORTING_MAP_KEYS = false ;
35+ public JsonWireFormat (JsonObject json ) {
36+ this (read (json ));
37+ }
4638
47- /**
48- * Default {@code ignoringUnknownFields} flag = {@code false}.
49- */
50- public static final boolean DEFAULT_IGNORING_UNKNOWN_FIELDS = false ;
39+ static JsonWireFormat of (int flags ) {
40+ JsonWireFormat fmt = CACHE [flags ];
41+ if (fmt == null ) {
42+ fmt = new JsonWireFormat ((byte ) flags );
43+ CACHE [flags ] = fmt ;
44+ }
45+ return fmt ;
46+ }
5147
52- private final boolean alwaysPrintFieldsWithNoPresence ;
53- private final boolean omittingInsignificantWhitespace ;
54- private final boolean preservingProtoFieldNames ;
55- private final boolean printingEnumsAsInts ;
56- private final boolean sortingMapKeys ;
57- private final boolean ignoringUnknownFields ;
48+ private static byte read (JsonObject json ) {
49+ int flags = 0 ;
50+ for (Flag flag : Flag .values ()) {
51+ if (json .getBoolean (flag .key , false )) {
52+ flags |= flag .mask ;
53+ }
54+ }
55+ return (byte ) flags ;
56+ }
5857
59- public JsonWireFormat () {
60- this (
61- DEFAULT_ALWAYS_PRINT_FIELDS_WITH_NO_PRESENCE ,
62- DEFAULT_OMITTING_INSIGNIFICANT_WHITESPACE ,
63- DEFAULT_PRESERVING_PROTO_FIELD_NAMES ,
64- DEFAULT_PRINTING_ENUMS_AS_INTS ,
65- DEFAULT_SORTING_MAP_KEYS ,
66- DEFAULT_IGNORING_UNKNOWN_FIELDS
67- );
68- }
69-
70- private JsonWireFormat (
71- boolean alwaysPrintFieldsWithNoPresence ,
72- boolean omittingInsignificantWhitespace ,
73- boolean preservingProtoFieldNames ,
74- boolean printingEnumsAsInts ,
75- boolean sortingMapKeys ,
76- boolean ignoringUnknownFields
77- ) {
78- this .alwaysPrintFieldsWithNoPresence = alwaysPrintFieldsWithNoPresence ;
79- this .omittingInsignificantWhitespace = omittingInsignificantWhitespace ;
80- this .preservingProtoFieldNames = preservingProtoFieldNames ;
81- this .printingEnumsAsInts = printingEnumsAsInts ;
82- this .sortingMapKeys = sortingMapKeys ;
83- this .ignoringUnknownFields = ignoringUnknownFields ;
58+ private boolean isSet (Flag flag ) {
59+ return (flags & flag .mask ) != 0 ;
8460 }
8561
86- public JsonWireFormat (JsonObject json ) {
87- this (
88- json .getBoolean ("alwaysPrintFieldsWithNoPresence" , DEFAULT_ALWAYS_PRINT_FIELDS_WITH_NO_PRESENCE ),
89- json .getBoolean ("omittingInsignificantWhitespace" , DEFAULT_OMITTING_INSIGNIFICANT_WHITESPACE ),
90- json .getBoolean ("preservingProtoFieldNames" , DEFAULT_PRESERVING_PROTO_FIELD_NAMES ),
91- json .getBoolean ("printingEnumsAsInts" , DEFAULT_PRINTING_ENUMS_AS_INTS ),
92- json .getBoolean ("sortingMapKeys" , DEFAULT_SORTING_MAP_KEYS ),
93- json .getBoolean ("ignoringUnknownFields" , DEFAULT_IGNORING_UNKNOWN_FIELDS )
94- );
62+ private JsonWireFormat with (Flag flag , boolean value ) {
63+ return of (value ? flags | flag .mask : flags & ~flag .mask );
9564 }
9665
9766 @ Override
9867 public final String name () {
9968 return NAME ;
10069 }
10170
71+ @ Override
72+ public String mediaType () {
73+ return MEDIA_TYPE ;
74+ }
75+
76+ /**
77+ * @return whether fields without presence are always printed, including those left at their default value
78+ */
10279 public boolean alwaysPrintFieldsWithNoPresence () {
103- return alwaysPrintFieldsWithNoPresence ;
80+ return isSet ( Flag . ALWAYS_PRINT_FIELDS_WITH_NO_PRESENCE ) ;
10481 }
10582
10683 /**
10784 * @return a copy of this format with {@code alwaysPrintFieldsWithNoPresence} set to {@code value}
10885 */
10986 public JsonWireFormat alwaysPrintFieldsWithNoPresence (boolean value ) {
110- return new JsonWireFormat ( value , omittingInsignificantWhitespace , preservingProtoFieldNames , printingEnumsAsInts , sortingMapKeys , ignoringUnknownFields );
87+ return with ( Flag . ALWAYS_PRINT_FIELDS_WITH_NO_PRESENCE , value );
11188 }
11289
90+ /**
91+ * @return whether insignificant whitespace is omitted, producing a compact single-line output
92+ */
11393 public boolean omittingInsignificantWhitespace () {
114- return omittingInsignificantWhitespace ;
94+ return isSet ( Flag . OMITTING_INSIGNIFICANT_WHITESPACE ) ;
11595 }
11696
11797 /**
11898 * @return a copy of this format with {@code omittingInsignificantWhitespace} set to {@code value}
11999 */
120100 public JsonWireFormat omittingInsignificantWhitespace (boolean value ) {
121- return new JsonWireFormat ( alwaysPrintFieldsWithNoPresence , value , preservingProtoFieldNames , printingEnumsAsInts , sortingMapKeys , ignoringUnknownFields );
101+ return with ( Flag . OMITTING_INSIGNIFICANT_WHITESPACE , value );
122102 }
123103
104+ /**
105+ * @return whether the original proto field names are used instead of the lowerCamelCase JSON names
106+ */
124107 public boolean preservingProtoFieldNames () {
125- return preservingProtoFieldNames ;
108+ return isSet ( Flag . PRESERVING_PROTO_FIELD_NAMES ) ;
126109 }
127110
128111 /**
129112 * @return a copy of this format with {@code preservingProtoFieldNames} set to {@code value}
130113 */
131114 public JsonWireFormat preservingProtoFieldNames (boolean value ) {
132- return new JsonWireFormat ( alwaysPrintFieldsWithNoPresence , omittingInsignificantWhitespace , value , printingEnumsAsInts , sortingMapKeys , ignoringUnknownFields );
115+ return with ( Flag . PRESERVING_PROTO_FIELD_NAMES , value );
133116 }
134117
118+ /**
119+ * @return whether enum values are printed as their integer number instead of their name
120+ */
135121 public boolean printingEnumsAsInts () {
136- return printingEnumsAsInts ;
122+ return isSet ( Flag . PRINTING_ENUMS_AS_INTS ) ;
137123 }
138124
139125 /**
140126 * @return a copy of this format with {@code printingEnumsAsInts} set to {@code value}
141127 */
142128 public JsonWireFormat printingEnumsAsInts (boolean value ) {
143- return new JsonWireFormat ( alwaysPrintFieldsWithNoPresence , omittingInsignificantWhitespace , preservingProtoFieldNames , value , sortingMapKeys , ignoringUnknownFields );
129+ return with ( Flag . PRINTING_ENUMS_AS_INTS , value );
144130 }
145131
132+ /**
133+ * @return whether map entries are emitted with their keys sorted, for deterministic output
134+ */
146135 public boolean sortingMapKeys () {
147- return sortingMapKeys ;
136+ return isSet ( Flag . SORTING_MAP_KEYS ) ;
148137 }
149138
150139 /**
151140 * @return a copy of this format with {@code sortingMapKeys} set to {@code value}
152141 */
153142 public JsonWireFormat sortingMapKeys (boolean value ) {
154- return new JsonWireFormat ( alwaysPrintFieldsWithNoPresence , omittingInsignificantWhitespace , preservingProtoFieldNames , printingEnumsAsInts , value , ignoringUnknownFields );
143+ return with ( Flag . SORTING_MAP_KEYS , value );
155144 }
156145
146+ /**
147+ * @return whether unknown fields encountered while parsing are ignored rather than rejected
148+ */
157149 public boolean ignoringUnknownFields () {
158- return ignoringUnknownFields ;
150+ return isSet ( Flag . IGNORING_UNKNOWN_FIELDS ) ;
159151 }
160152
161153 /**
162154 * @return a copy of this format with {@code ignoringUnknownFields} set to {@code value}
163155 */
164156 public JsonWireFormat ignoringUnknownFields (boolean value ) {
165- return new JsonWireFormat ( alwaysPrintFieldsWithNoPresence , omittingInsignificantWhitespace , preservingProtoFieldNames , printingEnumsAsInts , sortingMapKeys , value );
157+ return with ( Flag . IGNORING_UNKNOWN_FIELDS , value );
166158 }
167159
168160 public JsonObject toJson () {
169- return new JsonObject ()
170- .put ("alwaysPrintFieldsWithNoPresence" , alwaysPrintFieldsWithNoPresence )
171- .put ("omittingInsignificantWhitespace" , omittingInsignificantWhitespace )
172- .put ("preservingProtoFieldNames" , preservingProtoFieldNames )
173- .put ("printingEnumsAsInts" , printingEnumsAsInts )
174- .put ("sortingMapKeys" , sortingMapKeys )
175- .put ("ignoringUnknownFields" , ignoringUnknownFields );
161+ JsonObject json = new JsonObject ();
162+ for (Flag flag : Flag .values ()) {
163+ json .put (flag .key , isSet (flag ));
164+ }
165+ return json ;
176166 }
177167
178168 @ Override
@@ -195,4 +185,21 @@ public int hashCode() {
195185 public String toString () {
196186 return NAME ;
197187 }
188+
189+ private enum Flag {
190+ ALWAYS_PRINT_FIELDS_WITH_NO_PRESENCE ("alwaysPrintFieldsWithNoPresence" ),
191+ OMITTING_INSIGNIFICANT_WHITESPACE ("omittingInsignificantWhitespace" ),
192+ PRESERVING_PROTO_FIELD_NAMES ("preservingProtoFieldNames" ),
193+ PRINTING_ENUMS_AS_INTS ("printingEnumsAsInts" ),
194+ SORTING_MAP_KEYS ("sortingMapKeys" ),
195+ IGNORING_UNKNOWN_FIELDS ("ignoringUnknownFields" );
196+
197+ final String key ;
198+ final int mask ;
199+
200+ Flag (String key ) {
201+ this .key = key ;
202+ this .mask = 1 << ordinal ();
203+ }
204+ }
198205}
0 commit comments