OLD | NEW |
1 // Protocol Buffers - Google's data interchange format | 1 // Protocol Buffers - Google's data interchange format |
2 // Copyright 2008 Google Inc. All rights reserved. | 2 // Copyright 2008 Google Inc. All rights reserved. |
3 // https://developers.google.com/protocol-buffers/ | 3 // https://developers.google.com/protocol-buffers/ |
4 // | 4 // |
5 // Redistribution and use in source and binary forms, with or without | 5 // Redistribution and use in source and binary forms, with or without |
6 // modification, are permitted provided that the following conditions are | 6 // modification, are permitted provided that the following conditions are |
7 // met: | 7 // met: |
8 // | 8 // |
9 // * Redistributions of source code must retain the above copyright | 9 // * Redistributions of source code must retain the above copyright |
10 // notice, this list of conditions and the following disclaimer. | 10 // notice, this list of conditions and the following disclaimer. |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
42 import com.google.gson.stream.JsonReader; | 42 import com.google.gson.stream.JsonReader; |
43 import com.google.protobuf.Any; | 43 import com.google.protobuf.Any; |
44 import com.google.protobuf.BoolValue; | 44 import com.google.protobuf.BoolValue; |
45 import com.google.protobuf.ByteString; | 45 import com.google.protobuf.ByteString; |
46 import com.google.protobuf.BytesValue; | 46 import com.google.protobuf.BytesValue; |
47 import com.google.protobuf.Descriptors.Descriptor; | 47 import com.google.protobuf.Descriptors.Descriptor; |
48 import com.google.protobuf.Descriptors.EnumDescriptor; | 48 import com.google.protobuf.Descriptors.EnumDescriptor; |
49 import com.google.protobuf.Descriptors.EnumValueDescriptor; | 49 import com.google.protobuf.Descriptors.EnumValueDescriptor; |
50 import com.google.protobuf.Descriptors.FieldDescriptor; | 50 import com.google.protobuf.Descriptors.FieldDescriptor; |
51 import com.google.protobuf.Descriptors.FileDescriptor; | 51 import com.google.protobuf.Descriptors.FileDescriptor; |
52 import com.google.protobuf.Descriptors.OneofDescriptor; | |
53 import com.google.protobuf.DoubleValue; | 52 import com.google.protobuf.DoubleValue; |
54 import com.google.protobuf.Duration; | 53 import com.google.protobuf.Duration; |
55 import com.google.protobuf.DynamicMessage; | 54 import com.google.protobuf.DynamicMessage; |
56 import com.google.protobuf.FieldMask; | 55 import com.google.protobuf.FieldMask; |
57 import com.google.protobuf.FloatValue; | 56 import com.google.protobuf.FloatValue; |
58 import com.google.protobuf.Int32Value; | 57 import com.google.protobuf.Int32Value; |
59 import com.google.protobuf.Int64Value; | 58 import com.google.protobuf.Int64Value; |
60 import com.google.protobuf.InvalidProtocolBufferException; | 59 import com.google.protobuf.InvalidProtocolBufferException; |
61 import com.google.protobuf.ListValue; | 60 import com.google.protobuf.ListValue; |
62 import com.google.protobuf.Message; | 61 import com.google.protobuf.Message; |
63 import com.google.protobuf.MessageOrBuilder; | 62 import com.google.protobuf.MessageOrBuilder; |
64 import com.google.protobuf.NullValue; | |
65 import com.google.protobuf.StringValue; | 63 import com.google.protobuf.StringValue; |
66 import com.google.protobuf.Struct; | 64 import com.google.protobuf.Struct; |
67 import com.google.protobuf.Timestamp; | 65 import com.google.protobuf.Timestamp; |
68 import com.google.protobuf.UInt32Value; | 66 import com.google.protobuf.UInt32Value; |
69 import com.google.protobuf.UInt64Value; | 67 import com.google.protobuf.UInt64Value; |
70 import com.google.protobuf.Value; | 68 import com.google.protobuf.Value; |
| 69 |
71 import java.io.IOException; | 70 import java.io.IOException; |
72 import java.io.Reader; | 71 import java.io.Reader; |
73 import java.io.StringReader; | 72 import java.io.StringReader; |
74 import java.math.BigDecimal; | 73 import java.math.BigDecimal; |
75 import java.math.BigInteger; | 74 import java.math.BigInteger; |
76 import java.text.ParseException; | 75 import java.text.ParseException; |
77 import java.util.Collections; | 76 import java.util.Collections; |
78 import java.util.HashMap; | 77 import java.util.HashMap; |
79 import java.util.HashSet; | 78 import java.util.HashSet; |
80 import java.util.List; | 79 import java.util.List; |
81 import java.util.Map; | 80 import java.util.Map; |
82 import java.util.Set; | 81 import java.util.Set; |
83 import java.util.TreeMap; | 82 import java.util.TreeMap; |
84 import java.util.logging.Logger; | 83 import java.util.logging.Logger; |
85 | 84 |
86 /** | 85 /** |
87 * Utility classes to convert protobuf messages to/from JSON format. The JSON | 86 * Utility classes to convert protobuf messages to/from JSON format. The JSON |
88 * format follows Proto3 JSON specification and only proto3 features are | 87 * format follows Proto3 JSON specification and only proto3 features are |
89 * supported. Proto2 only features (e.g., extensions and unknown fields) will | 88 * supported. Proto2 only features (e.g., extensions and unknown fields) will |
90 * be discarded in the conversion. That is, when converting proto2 messages | 89 * be discarded in the conversion. That is, when converting proto2 messages |
91 * to JSON format, extensions and unknown fields will be treated as if they | 90 * to JSON format, extensions and unknown fields will be treated as if they |
92 * do not exist. This applies to proto2 messages embedded in proto3 messages | 91 * do not exist. This applies to proto2 messages embedded in proto3 messages |
93 * as well. | 92 * as well. |
94 */ | 93 */ |
95 public class JsonFormat { | 94 public class JsonFormat { |
96 private static final Logger logger = Logger.getLogger(JsonFormat.class.getName
()); | 95 private static final Logger logger = |
| 96 Logger.getLogger(JsonFormat.class.getName()); |
97 | 97 |
98 private JsonFormat() {} | 98 private JsonFormat() {} |
99 | 99 |
100 /** | 100 /** |
101 * Creates a {@link Printer} with default configurations. | 101 * Creates a {@link Printer} with default configurations. |
102 */ | 102 */ |
103 public static Printer printer() { | 103 public static Printer printer() { |
104 return new Printer(TypeRegistry.getEmptyTypeRegistry(), false, false, false)
; | 104 return new Printer(TypeRegistry.getEmptyTypeRegistry(), false, false); |
105 } | 105 } |
106 | 106 |
107 /** | 107 /** |
108 * A Printer converts protobuf message to JSON format. | 108 * A Printer converts protobuf message to JSON format. |
109 */ | 109 */ |
110 public static class Printer { | 110 public static class Printer { |
111 private final TypeRegistry registry; | 111 private final TypeRegistry registry; |
112 private final boolean includingDefaultValueFields; | 112 private final boolean includingDefaultValueFields; |
113 private final boolean preservingProtoFieldNames; | 113 private final boolean preservingProtoFieldNames; |
114 private final boolean omittingInsignificantWhitespace; | |
115 | 114 |
116 private Printer( | 115 private Printer( |
117 TypeRegistry registry, | 116 TypeRegistry registry, |
118 boolean includingDefaultValueFields, | 117 boolean includingDefaultValueFields, |
119 boolean preservingProtoFieldNames, | 118 boolean preservingProtoFieldNames) { |
120 boolean omittingInsignificantWhitespace) { | |
121 this.registry = registry; | 119 this.registry = registry; |
122 this.includingDefaultValueFields = includingDefaultValueFields; | 120 this.includingDefaultValueFields = includingDefaultValueFields; |
123 this.preservingProtoFieldNames = preservingProtoFieldNames; | 121 this.preservingProtoFieldNames = preservingProtoFieldNames; |
124 this.omittingInsignificantWhitespace = omittingInsignificantWhitespace; | |
125 } | 122 } |
126 | 123 |
127 /** | 124 /** |
128 * Creates a new {@link Printer} using the given registry. The new Printer | 125 * Creates a new {@link Printer} using the given registry. The new Printer |
129 * clones all other configurations from the current {@link Printer}. | 126 * clones all other configurations from the current {@link Printer}. |
130 * | 127 * |
131 * @throws IllegalArgumentException if a registry is already set. | 128 * @throws IllegalArgumentException if a registry is already set. |
132 */ | 129 */ |
133 public Printer usingTypeRegistry(TypeRegistry registry) { | 130 public Printer usingTypeRegistry(TypeRegistry registry) { |
134 if (this.registry != TypeRegistry.getEmptyTypeRegistry()) { | 131 if (this.registry != TypeRegistry.getEmptyTypeRegistry()) { |
135 throw new IllegalArgumentException("Only one registry is allowed."); | 132 throw new IllegalArgumentException("Only one registry is allowed."); |
136 } | 133 } |
137 return new Printer( | 134 return new Printer(registry, includingDefaultValueFields, preservingProtoF
ieldNames); |
138 registry, | |
139 includingDefaultValueFields, | |
140 preservingProtoFieldNames, | |
141 omittingInsignificantWhitespace); | |
142 } | 135 } |
143 | 136 |
144 /** | 137 /** |
145 * Creates a new {@link Printer} that will also print fields set to their | 138 * Creates a new {@link Printer} that will also print fields set to their |
146 * defaults. Empty repeated fields and map fields will be printed as well. | 139 * defaults. Empty repeated fields and map fields will be printed as well. |
147 * The new Printer clones all other configurations from the current | 140 * The new Printer clones all other configurations from the current |
148 * {@link Printer}. | 141 * {@link Printer}. |
149 */ | 142 */ |
150 public Printer includingDefaultValueFields() { | 143 public Printer includingDefaultValueFields() { |
151 return new Printer( | 144 return new Printer(registry, true, preservingProtoFieldNames); |
152 registry, true, preservingProtoFieldNames, omittingInsignificantWhites
pace); | |
153 } | 145 } |
154 | 146 |
155 /** | 147 /** |
156 * Creates a new {@link Printer} that is configured to use the original prot
o | 148 * Creates a new {@link Printer} that is configured to use the original prot
o |
157 * field names as defined in the .proto file rather than converting them to | 149 * field names as defined in the .proto file rather than converting them to |
158 * lowerCamelCase. The new Printer clones all other configurations from the | 150 * lowerCamelCase. The new Printer clones all other configurations from the |
159 * current {@link Printer}. | 151 * current {@link Printer}. |
160 */ | 152 */ |
161 public Printer preservingProtoFieldNames() { | 153 public Printer preservingProtoFieldNames() { |
162 return new Printer( | 154 return new Printer(registry, includingDefaultValueFields, true); |
163 registry, includingDefaultValueFields, true, omittingInsignificantWhit
espace); | |
164 } | 155 } |
165 | 156 |
166 | |
167 /** | |
168 * Create a new {@link Printer} that will omit all insignificant whitespac
e | |
169 * in the JSON output. This new Printer clones all other configurations from
the | |
170 * current Printer. Insignificant whitespace is defined by the JSON spec as
whitespace | |
171 * that appear between JSON structural elements: | |
172 * <pre> | |
173 * ws = *( | |
174 * %x20 / ; Space | |
175 * %x09 / ; Horizontal tab | |
176 * %x0A / ; Line feed or New line | |
177 * %x0D ) ; Carriage return | |
178 * </pre> | |
179 * See <a href="https://tools.ietf.org/html/rfc7159">https://tools.ietf.org/
html/rfc7159</a> | |
180 * current {@link Printer}. | |
181 */ | |
182 public Printer omittingInsignificantWhitespace() { | |
183 return new Printer(registry, includingDefaultValueFields, preservingProtoF
ieldNames, true); | |
184 } | |
185 | |
186 /** | 157 /** |
187 * Converts a protobuf message to JSON format. | 158 * Converts a protobuf message to JSON format. |
188 * | 159 * |
189 * @throws InvalidProtocolBufferException if the message contains Any types | 160 * @throws InvalidProtocolBufferException if the message contains Any types |
190 * that can't be resolved. | 161 * that can't be resolved. |
191 * @throws IOException if writing to the output fails. | 162 * @throws IOException if writing to the output fails. |
192 */ | 163 */ |
193 public void appendTo(MessageOrBuilder message, Appendable output) throws IOE
xception { | 164 public void appendTo(MessageOrBuilder message, Appendable output) |
| 165 throws IOException { |
194 // TODO(xiaofeng): Investigate the allocation overhead and optimize for | 166 // TODO(xiaofeng): Investigate the allocation overhead and optimize for |
195 // mobile. | 167 // mobile. |
196 new PrinterImpl( | 168 new PrinterImpl(registry, includingDefaultValueFields, preservingProtoFiel
dNames, output) |
197 registry, | |
198 includingDefaultValueFields, | |
199 preservingProtoFieldNames, | |
200 output, | |
201 omittingInsignificantWhitespace) | |
202 .print(message); | 169 .print(message); |
203 } | 170 } |
204 | 171 |
205 /** | 172 /** |
206 * Converts a protobuf message to JSON format. Throws exceptions if there | 173 * Converts a protobuf message to JSON format. Throws exceptions if there |
207 * are unknown Any types in the message. | 174 * are unknown Any types in the message. |
208 */ | 175 */ |
209 public String print(MessageOrBuilder message) throws InvalidProtocolBufferEx
ception { | 176 public String print(MessageOrBuilder message) |
| 177 throws InvalidProtocolBufferException { |
210 try { | 178 try { |
211 StringBuilder builder = new StringBuilder(); | 179 StringBuilder builder = new StringBuilder(); |
212 appendTo(message, builder); | 180 appendTo(message, builder); |
213 return builder.toString(); | 181 return builder.toString(); |
214 } catch (InvalidProtocolBufferException e) { | 182 } catch (InvalidProtocolBufferException e) { |
215 throw e; | 183 throw e; |
216 } catch (IOException e) { | 184 } catch (IOException e) { |
217 // Unexpected IOException. | 185 // Unexpected IOException. |
218 throw new IllegalStateException(e); | 186 throw new IllegalStateException(e); |
219 } | 187 } |
220 } | 188 } |
221 } | 189 } |
222 | 190 |
223 /** | 191 /** |
224 * Creates a {@link Parser} with default configuration. | 192 * Creates a {@link Parser} with default configuration. |
225 */ | 193 */ |
226 public static Parser parser() { | 194 public static Parser parser() { |
227 return new Parser(TypeRegistry.getEmptyTypeRegistry(), false, Parser.DEFAULT
_RECURSION_LIMIT); | 195 return new Parser(TypeRegistry.getEmptyTypeRegistry()); |
228 } | 196 } |
229 | 197 |
230 /** | 198 /** |
231 * A Parser parses JSON to protobuf message. | 199 * A Parser parses JSON to protobuf message. |
232 */ | 200 */ |
233 public static class Parser { | 201 public static class Parser { |
234 private final TypeRegistry registry; | 202 private final TypeRegistry registry; |
235 private final boolean ignoringUnknownFields; | 203 |
236 private final int recursionLimit; | 204 private Parser(TypeRegistry registry) { |
237 | 205 this.registry = registry; |
238 // The default parsing recursion limit is aligned with the proto binary pars
er. | |
239 private static final int DEFAULT_RECURSION_LIMIT = 100; | |
240 | |
241 private Parser(TypeRegistry registry, boolean ignoreUnknownFields, int recur
sionLimit) { | |
242 this.registry = registry; | |
243 this.ignoringUnknownFields = ignoreUnknownFields; | |
244 this.recursionLimit = recursionLimit; | |
245 } | 206 } |
246 | 207 |
247 /** | 208 /** |
248 * Creates a new {@link Parser} using the given registry. The new Parser | 209 * Creates a new {@link Parser} using the given registry. The new Parser |
249 * clones all other configurations from this Parser. | 210 * clones all other configurations from this Parser. |
250 * | 211 * |
251 * @throws IllegalArgumentException if a registry is already set. | 212 * @throws IllegalArgumentException if a registry is already set. |
252 */ | 213 */ |
253 public Parser usingTypeRegistry(TypeRegistry registry) { | 214 public Parser usingTypeRegistry(TypeRegistry registry) { |
254 if (this.registry != TypeRegistry.getEmptyTypeRegistry()) { | 215 if (this.registry != TypeRegistry.getEmptyTypeRegistry()) { |
255 throw new IllegalArgumentException("Only one registry is allowed."); | 216 throw new IllegalArgumentException("Only one registry is allowed."); |
256 } | 217 } |
257 return new Parser(registry, ignoringUnknownFields, recursionLimit); | 218 return new Parser(registry); |
258 } | 219 } |
259 | 220 |
260 /** | |
261 * Creates a new {@link Parser} configured to not throw an exception when an
unknown field is | |
262 * encountered. The new Parser clones all other configurations from this Par
ser. | |
263 */ | |
264 public Parser ignoringUnknownFields() { | |
265 return new Parser(this.registry, true, recursionLimit); | |
266 } | |
267 | |
268 /** | 221 /** |
269 * Parses from JSON into a protobuf message. | 222 * Parses from JSON into a protobuf message. |
270 * | 223 * |
271 * @throws InvalidProtocolBufferException if the input is not valid JSON | 224 * @throws InvalidProtocolBufferException if the input is not valid JSON |
272 * format or there are unknown fields in the input. | 225 * format or there are unknown fields in the input. |
273 */ | 226 */ |
274 public void merge(String json, Message.Builder builder) throws InvalidProtoc
olBufferException { | 227 public void merge(String json, Message.Builder builder) |
| 228 throws InvalidProtocolBufferException { |
275 // TODO(xiaofeng): Investigate the allocation overhead and optimize for | 229 // TODO(xiaofeng): Investigate the allocation overhead and optimize for |
276 // mobile. | 230 // mobile. |
277 new ParserImpl(registry, ignoringUnknownFields, recursionLimit).merge(json
, builder); | 231 new ParserImpl(registry).merge(json, builder); |
278 } | 232 } |
279 | 233 |
280 /** | 234 /** |
281 * Parses from JSON into a protobuf message. | 235 * Parses from JSON into a protobuf message. |
282 * | 236 * |
283 * @throws InvalidProtocolBufferException if the input is not valid JSON | 237 * @throws InvalidProtocolBufferException if the input is not valid JSON |
284 * format or there are unknown fields in the input. | 238 * format or there are unknown fields in the input. |
285 * @throws IOException if reading from the input throws. | 239 * @throws IOException if reading from the input throws. |
286 */ | 240 */ |
287 public void merge(Reader json, Message.Builder builder) throws IOException { | 241 public void merge(Reader json, Message.Builder builder) |
| 242 throws IOException { |
288 // TODO(xiaofeng): Investigate the allocation overhead and optimize for | 243 // TODO(xiaofeng): Investigate the allocation overhead and optimize for |
289 // mobile. | 244 // mobile. |
290 new ParserImpl(registry, ignoringUnknownFields, recursionLimit).merge(json
, builder); | 245 new ParserImpl(registry).merge(json, builder); |
291 } | |
292 | |
293 // For testing only. | |
294 Parser usingRecursionLimit(int recursionLimit) { | |
295 return new Parser(registry, ignoringUnknownFields, recursionLimit); | |
296 } | 246 } |
297 } | 247 } |
298 | 248 |
299 /** | 249 /** |
300 * A TypeRegistry is used to resolve Any messages in the JSON conversion. | 250 * A TypeRegistry is used to resolve Any messages in the JSON conversion. |
301 * You must provide a TypeRegistry containing all message types used in | 251 * You must provide a TypeRegistry containing all message types used in |
302 * Any message fields, or the JSON conversion will fail because data | 252 * Any message fields, or the JSON conversion will fail because data |
303 * in Any message fields is unrecognizable. You don't need to supply a | 253 * in Any message fields is unrecognizable. You don't need to supply a |
304 * TypeRegistry if you don't use Any message fields. | 254 * TypeRegistry if you don't use Any message fields. |
305 */ | 255 */ |
306 public static class TypeRegistry { | 256 public static class TypeRegistry { |
307 private static class EmptyTypeRegistryHolder { | 257 private static class EmptyTypeRegistryHolder { |
308 private static final TypeRegistry EMPTY = | 258 private static final TypeRegistry EMPTY = new TypeRegistry( |
309 new TypeRegistry(Collections.<String, Descriptor>emptyMap()); | 259 Collections.<String, Descriptor>emptyMap()); |
310 } | 260 } |
311 | 261 |
312 public static TypeRegistry getEmptyTypeRegistry() { | 262 public static TypeRegistry getEmptyTypeRegistry() { |
313 return EmptyTypeRegistryHolder.EMPTY; | 263 return EmptyTypeRegistryHolder.EMPTY; |
314 } | 264 } |
315 | 265 |
316 public static Builder newBuilder() { | 266 public static Builder newBuilder() { |
317 return new Builder(); | 267 return new Builder(); |
318 } | 268 } |
319 | 269 |
(...skipping 16 matching lines...) Expand all Loading... |
336 */ | 286 */ |
337 public static class Builder { | 287 public static class Builder { |
338 private Builder() {} | 288 private Builder() {} |
339 | 289 |
340 /** | 290 /** |
341 * Adds a message type and all types defined in the same .proto file as | 291 * Adds a message type and all types defined in the same .proto file as |
342 * well as all transitively imported .proto files to this {@link Builder}. | 292 * well as all transitively imported .proto files to this {@link Builder}. |
343 */ | 293 */ |
344 public Builder add(Descriptor messageType) { | 294 public Builder add(Descriptor messageType) { |
345 if (types == null) { | 295 if (types == null) { |
346 throw new IllegalStateException("A TypeRegistry.Builer can only be use
d once."); | 296 throw new IllegalStateException( |
| 297 "A TypeRegistry.Builer can only be used once."); |
347 } | 298 } |
348 addFile(messageType.getFile()); | 299 addFile(messageType.getFile()); |
349 return this; | 300 return this; |
350 } | 301 } |
351 | 302 |
352 /** | 303 /** |
353 * Adds message types and all types defined in the same .proto file as | 304 * Adds message types and all types defined in the same .proto file as |
354 * well as all transitively imported .proto files to this {@link Builder}. | 305 * well as all transitively imported .proto files to this {@link Builder}. |
355 */ | 306 */ |
356 public Builder add(Iterable<Descriptor> messageTypes) { | 307 public Builder add(Iterable<Descriptor> messageTypes) { |
357 if (types == null) { | 308 if (types == null) { |
358 throw new IllegalStateException("A TypeRegistry.Builer can only be use
d once."); | 309 throw new IllegalStateException( |
| 310 "A TypeRegistry.Builer can only be used once."); |
359 } | 311 } |
360 for (Descriptor type : messageTypes) { | 312 for (Descriptor type : messageTypes) { |
361 addFile(type.getFile()); | 313 addFile(type.getFile()); |
362 } | 314 } |
363 return this; | 315 return this; |
364 } | 316 } |
365 | 317 |
366 /** | 318 /** |
367 * Builds a {@link TypeRegistry}. This method can only be called once for | 319 * Builds a {@link TypeRegistry}. This method can only be called once for |
368 * one Builder. | 320 * one Builder. |
(...skipping 17 matching lines...) Expand all Loading... |
386 addMessage(message); | 338 addMessage(message); |
387 } | 339 } |
388 } | 340 } |
389 | 341 |
390 private void addMessage(Descriptor message) { | 342 private void addMessage(Descriptor message) { |
391 for (Descriptor nestedType : message.getNestedTypes()) { | 343 for (Descriptor nestedType : message.getNestedTypes()) { |
392 addMessage(nestedType); | 344 addMessage(nestedType); |
393 } | 345 } |
394 | 346 |
395 if (types.containsKey(message.getFullName())) { | 347 if (types.containsKey(message.getFullName())) { |
396 logger.warning("Type " + message.getFullName() + " is added multiple t
imes."); | 348 logger.warning("Type " + message.getFullName() |
| 349 + " is added multiple times."); |
397 return; | 350 return; |
398 } | 351 } |
399 | 352 |
400 types.put(message.getFullName(), message); | 353 types.put(message.getFullName(), message); |
401 } | 354 } |
402 | 355 |
403 private final Set<String> files = new HashSet<String>(); | 356 private final Set<String> files = new HashSet<String>(); |
404 private Map<String, Descriptor> types = new HashMap<String, Descriptor>(); | 357 private Map<String, Descriptor> types = |
| 358 new HashMap<String, Descriptor>(); |
405 } | 359 } |
406 } | 360 } |
407 | 361 |
408 /** | 362 /** |
409 * An interface for json formatting that can be used in | |
410 * combination with the omittingInsignificantWhitespace() method | |
411 */ | |
412 interface TextGenerator { | |
413 void indent(); | |
414 | |
415 void outdent(); | |
416 | |
417 void print(final CharSequence text) throws IOException; | |
418 } | |
419 | |
420 /** | |
421 * Format the json without indentation | |
422 */ | |
423 private static final class CompactTextGenerator implements TextGenerator { | |
424 private final Appendable output; | |
425 | |
426 private CompactTextGenerator(final Appendable output) { | |
427 this.output = output; | |
428 } | |
429 | |
430 /** | |
431 * ignored by compact printer | |
432 */ | |
433 public void indent() {} | |
434 | |
435 /** | |
436 * ignored by compact printer | |
437 */ | |
438 public void outdent() {} | |
439 | |
440 /** | |
441 * Print text to the output stream. | |
442 */ | |
443 public void print(final CharSequence text) throws IOException { | |
444 output.append(text); | |
445 } | |
446 } | |
447 /** | |
448 * A TextGenerator adds indentation when writing formatted text. | 363 * A TextGenerator adds indentation when writing formatted text. |
449 */ | 364 */ |
450 private static final class PrettyTextGenerator implements TextGenerator { | 365 private static final class TextGenerator { |
451 private final Appendable output; | 366 private final Appendable output; |
452 private final StringBuilder indent = new StringBuilder(); | 367 private final StringBuilder indent = new StringBuilder(); |
453 private boolean atStartOfLine = true; | 368 private boolean atStartOfLine = true; |
454 | 369 |
455 private PrettyTextGenerator(final Appendable output) { | 370 private TextGenerator(final Appendable output) { |
456 this.output = output; | 371 this.output = output; |
457 } | 372 } |
458 | 373 |
459 /** | 374 /** |
460 * Indent text by two spaces. After calling Indent(), two spaces will be | 375 * Indent text by two spaces. After calling Indent(), two spaces will be |
461 * inserted at the beginning of each line of text. Indent() may be called | 376 * inserted at the beginning of each line of text. Indent() may be called |
462 * multiple times to produce deeper indents. | 377 * multiple times to produce deeper indents. |
463 */ | 378 */ |
464 public void indent() { | 379 public void indent() { |
465 indent.append(" "); | 380 indent.append(" "); |
466 } | 381 } |
467 | 382 |
468 /** | 383 /** |
469 * Reduces the current indent level by two spaces, or crashes if the indent | 384 * Reduces the current indent level by two spaces, or crashes if the indent |
470 * level is zero. | 385 * level is zero. |
471 */ | 386 */ |
472 public void outdent() { | 387 public void outdent() { |
473 final int length = indent.length(); | 388 final int length = indent.length(); |
474 if (length < 2) { | 389 if (length < 2) { |
475 throw new IllegalArgumentException(" Outdent() without matching Indent()
."); | 390 throw new IllegalArgumentException( |
| 391 " Outdent() without matching Indent()."); |
476 } | 392 } |
477 indent.delete(length - 2, length); | 393 indent.delete(length - 2, length); |
478 } | 394 } |
479 | 395 |
480 /** | 396 /** |
481 * Print text to the output stream. | 397 * Print text to the output stream. |
482 */ | 398 */ |
483 public void print(final CharSequence text) throws IOException { | 399 public void print(final CharSequence text) throws IOException { |
484 final int size = text.length(); | 400 final int size = text.length(); |
485 int pos = 0; | 401 int pos = 0; |
(...skipping 23 matching lines...) Expand all Loading... |
509 /** | 425 /** |
510 * A Printer converts protobuf messages to JSON format. | 426 * A Printer converts protobuf messages to JSON format. |
511 */ | 427 */ |
512 private static final class PrinterImpl { | 428 private static final class PrinterImpl { |
513 private final TypeRegistry registry; | 429 private final TypeRegistry registry; |
514 private final boolean includingDefaultValueFields; | 430 private final boolean includingDefaultValueFields; |
515 private final boolean preservingProtoFieldNames; | 431 private final boolean preservingProtoFieldNames; |
516 private final TextGenerator generator; | 432 private final TextGenerator generator; |
517 // We use Gson to help handle string escapes. | 433 // We use Gson to help handle string escapes. |
518 private final Gson gson; | 434 private final Gson gson; |
519 private final CharSequence blankOrSpace; | |
520 private final CharSequence blankOrNewLine; | |
521 | 435 |
522 private static class GsonHolder { | 436 private static class GsonHolder { |
523 private static final Gson DEFAULT_GSON = new GsonBuilder().disableHtmlEsca
ping().create(); | 437 private static final Gson DEFAULT_GSON = new GsonBuilder().disableHtmlEsca
ping().create(); |
524 } | 438 } |
525 | 439 |
526 PrinterImpl( | 440 PrinterImpl( |
527 TypeRegistry registry, | 441 TypeRegistry registry, |
528 boolean includingDefaultValueFields, | 442 boolean includingDefaultValueFields, |
529 boolean preservingProtoFieldNames, | 443 boolean preservingProtoFieldNames, |
530 Appendable jsonOutput, | 444 Appendable jsonOutput) { |
531 boolean omittingInsignificantWhitespace) { | |
532 this.registry = registry; | 445 this.registry = registry; |
533 this.includingDefaultValueFields = includingDefaultValueFields; | 446 this.includingDefaultValueFields = includingDefaultValueFields; |
534 this.preservingProtoFieldNames = preservingProtoFieldNames; | 447 this.preservingProtoFieldNames = preservingProtoFieldNames; |
| 448 this.generator = new TextGenerator(jsonOutput); |
535 this.gson = GsonHolder.DEFAULT_GSON; | 449 this.gson = GsonHolder.DEFAULT_GSON; |
536 // json format related properties, determined by printerType | |
537 if (omittingInsignificantWhitespace) { | |
538 this.generator = new CompactTextGenerator(jsonOutput); | |
539 this.blankOrSpace = ""; | |
540 this.blankOrNewLine = ""; | |
541 } else { | |
542 this.generator = new PrettyTextGenerator(jsonOutput); | |
543 this.blankOrSpace = " "; | |
544 this.blankOrNewLine = "\n"; | |
545 } | |
546 } | 450 } |
547 | 451 |
548 void print(MessageOrBuilder message) throws IOException { | 452 void print(MessageOrBuilder message) throws IOException { |
549 WellKnownTypePrinter specialPrinter = | 453 WellKnownTypePrinter specialPrinter = wellKnownTypePrinters.get( |
550 wellKnownTypePrinters.get(message.getDescriptorForType().getFullName()
); | 454 message.getDescriptorForType().getFullName()); |
551 if (specialPrinter != null) { | 455 if (specialPrinter != null) { |
552 specialPrinter.print(this, message); | 456 specialPrinter.print(this, message); |
553 return; | 457 return; |
554 } | 458 } |
555 print(message, null); | 459 print(message, null); |
556 } | 460 } |
557 | 461 |
558 private interface WellKnownTypePrinter { | 462 private interface WellKnownTypePrinter { |
559 void print(PrinterImpl printer, MessageOrBuilder message) throws IOExcepti
on; | 463 void print(PrinterImpl printer, MessageOrBuilder message) |
| 464 throws IOException; |
560 } | 465 } |
561 | 466 |
562 private static final Map<String, WellKnownTypePrinter> wellKnownTypePrinters
= | 467 private static final Map<String, WellKnownTypePrinter> |
563 buildWellKnownTypePrinters(); | 468 wellKnownTypePrinters = buildWellKnownTypePrinters(); |
564 | 469 |
565 private static Map<String, WellKnownTypePrinter> buildWellKnownTypePrinters(
) { | 470 private static Map<String, WellKnownTypePrinter> |
566 Map<String, WellKnownTypePrinter> printers = new HashMap<String, WellKnown
TypePrinter>(); | 471 buildWellKnownTypePrinters() { |
| 472 Map<String, WellKnownTypePrinter> printers = |
| 473 new HashMap<String, WellKnownTypePrinter>(); |
567 // Special-case Any. | 474 // Special-case Any. |
568 printers.put( | 475 printers.put(Any.getDescriptor().getFullName(), |
569 Any.getDescriptor().getFullName(), | |
570 new WellKnownTypePrinter() { | 476 new WellKnownTypePrinter() { |
571 @Override | 477 @Override |
572 public void print(PrinterImpl printer, MessageOrBuilder message) thr
ows IOException { | 478 public void print(PrinterImpl printer, MessageOrBuilder message) |
573 printer.printAny(message); | 479 throws IOException { |
574 } | 480 printer.printAny(message); |
575 }); | 481 } |
| 482 }); |
576 // Special-case wrapper types. | 483 // Special-case wrapper types. |
577 WellKnownTypePrinter wrappersPrinter = | 484 WellKnownTypePrinter wrappersPrinter = new WellKnownTypePrinter() { |
578 new WellKnownTypePrinter() { | 485 @Override |
579 @Override | 486 public void print(PrinterImpl printer, MessageOrBuilder message) |
580 public void print(PrinterImpl printer, MessageOrBuilder message) thr
ows IOException { | 487 throws IOException { |
581 printer.printWrapper(message); | 488 printer.printWrapper(message); |
582 } | 489 |
583 }; | 490 } |
| 491 }; |
584 printers.put(BoolValue.getDescriptor().getFullName(), wrappersPrinter); | 492 printers.put(BoolValue.getDescriptor().getFullName(), wrappersPrinter); |
585 printers.put(Int32Value.getDescriptor().getFullName(), wrappersPrinter); | 493 printers.put(Int32Value.getDescriptor().getFullName(), wrappersPrinter); |
586 printers.put(UInt32Value.getDescriptor().getFullName(), wrappersPrinter); | 494 printers.put(UInt32Value.getDescriptor().getFullName(), wrappersPrinter); |
587 printers.put(Int64Value.getDescriptor().getFullName(), wrappersPrinter); | 495 printers.put(Int64Value.getDescriptor().getFullName(), wrappersPrinter); |
588 printers.put(UInt64Value.getDescriptor().getFullName(), wrappersPrinter); | 496 printers.put(UInt64Value.getDescriptor().getFullName(), wrappersPrinter); |
589 printers.put(StringValue.getDescriptor().getFullName(), wrappersPrinter); | 497 printers.put(StringValue.getDescriptor().getFullName(), wrappersPrinter); |
590 printers.put(BytesValue.getDescriptor().getFullName(), wrappersPrinter); | 498 printers.put(BytesValue.getDescriptor().getFullName(), wrappersPrinter); |
591 printers.put(FloatValue.getDescriptor().getFullName(), wrappersPrinter); | 499 printers.put(FloatValue.getDescriptor().getFullName(), wrappersPrinter); |
592 printers.put(DoubleValue.getDescriptor().getFullName(), wrappersPrinter); | 500 printers.put(DoubleValue.getDescriptor().getFullName(), wrappersPrinter); |
593 // Special-case Timestamp. | 501 // Special-case Timestamp. |
594 printers.put( | 502 printers.put(Timestamp.getDescriptor().getFullName(), |
595 Timestamp.getDescriptor().getFullName(), | |
596 new WellKnownTypePrinter() { | 503 new WellKnownTypePrinter() { |
597 @Override | 504 @Override |
598 public void print(PrinterImpl printer, MessageOrBuilder message) thr
ows IOException { | 505 public void print(PrinterImpl printer, MessageOrBuilder message) |
599 printer.printTimestamp(message); | 506 throws IOException { |
600 } | 507 printer.printTimestamp(message); |
601 }); | 508 } |
| 509 }); |
602 // Special-case Duration. | 510 // Special-case Duration. |
603 printers.put( | 511 printers.put(Duration.getDescriptor().getFullName(), |
604 Duration.getDescriptor().getFullName(), | |
605 new WellKnownTypePrinter() { | 512 new WellKnownTypePrinter() { |
606 @Override | 513 @Override |
607 public void print(PrinterImpl printer, MessageOrBuilder message) thr
ows IOException { | 514 public void print(PrinterImpl printer, MessageOrBuilder message) |
608 printer.printDuration(message); | 515 throws IOException { |
609 } | 516 printer.printDuration(message); |
610 }); | 517 } |
| 518 }); |
611 // Special-case FieldMask. | 519 // Special-case FieldMask. |
612 printers.put( | 520 printers.put(FieldMask.getDescriptor().getFullName(), |
613 FieldMask.getDescriptor().getFullName(), | |
614 new WellKnownTypePrinter() { | 521 new WellKnownTypePrinter() { |
615 @Override | 522 @Override |
616 public void print(PrinterImpl printer, MessageOrBuilder message) thr
ows IOException { | 523 public void print(PrinterImpl printer, MessageOrBuilder message) |
617 printer.printFieldMask(message); | 524 throws IOException { |
618 } | 525 printer.printFieldMask(message); |
619 }); | 526 } |
| 527 }); |
620 // Special-case Struct. | 528 // Special-case Struct. |
621 printers.put( | 529 printers.put(Struct.getDescriptor().getFullName(), |
622 Struct.getDescriptor().getFullName(), | |
623 new WellKnownTypePrinter() { | 530 new WellKnownTypePrinter() { |
624 @Override | 531 @Override |
625 public void print(PrinterImpl printer, MessageOrBuilder message) thr
ows IOException { | 532 public void print(PrinterImpl printer, MessageOrBuilder message) |
626 printer.printStruct(message); | 533 throws IOException { |
627 } | 534 printer.printStruct(message); |
628 }); | 535 } |
| 536 }); |
629 // Special-case Value. | 537 // Special-case Value. |
630 printers.put( | 538 printers.put(Value.getDescriptor().getFullName(), |
631 Value.getDescriptor().getFullName(), | |
632 new WellKnownTypePrinter() { | 539 new WellKnownTypePrinter() { |
633 @Override | 540 @Override |
634 public void print(PrinterImpl printer, MessageOrBuilder message) thr
ows IOException { | 541 public void print(PrinterImpl printer, MessageOrBuilder message) |
635 printer.printValue(message); | 542 throws IOException { |
636 } | 543 printer.printValue(message); |
637 }); | 544 } |
| 545 }); |
638 // Special-case ListValue. | 546 // Special-case ListValue. |
639 printers.put( | 547 printers.put(ListValue.getDescriptor().getFullName(), |
640 ListValue.getDescriptor().getFullName(), | |
641 new WellKnownTypePrinter() { | 548 new WellKnownTypePrinter() { |
642 @Override | 549 @Override |
643 public void print(PrinterImpl printer, MessageOrBuilder message) thr
ows IOException { | 550 public void print(PrinterImpl printer, MessageOrBuilder message) |
644 printer.printListValue(message); | 551 throws IOException { |
645 } | 552 printer.printListValue(message); |
646 }); | 553 } |
| 554 }); |
647 return printers; | 555 return printers; |
648 } | 556 } |
649 | 557 |
650 /** Prints google.protobuf.Any */ | 558 /** Prints google.protobuf.Any */ |
651 private void printAny(MessageOrBuilder message) throws IOException { | 559 private void printAny(MessageOrBuilder message) throws IOException { |
652 if (Any.getDefaultInstance().equals(message)) { | |
653 generator.print("{}"); | |
654 return; | |
655 } | |
656 Descriptor descriptor = message.getDescriptorForType(); | 560 Descriptor descriptor = message.getDescriptorForType(); |
657 FieldDescriptor typeUrlField = descriptor.findFieldByName("type_url"); | 561 FieldDescriptor typeUrlField = descriptor.findFieldByName("type_url"); |
658 FieldDescriptor valueField = descriptor.findFieldByName("value"); | 562 FieldDescriptor valueField = descriptor.findFieldByName("value"); |
659 // Validates type of the message. Note that we can't just cast the message | 563 // Validates type of the message. Note that we can't just cast the message |
660 // to com.google.protobuf.Any because it might be a DynamicMessage. | 564 // to com.google.protobuf.Any because it might be a DynamicMessage. |
661 if (typeUrlField == null | 565 if (typeUrlField == null || valueField == null |
662 || valueField == null | |
663 || typeUrlField.getType() != FieldDescriptor.Type.STRING | 566 || typeUrlField.getType() != FieldDescriptor.Type.STRING |
664 || valueField.getType() != FieldDescriptor.Type.BYTES) { | 567 || valueField.getType() != FieldDescriptor.Type.BYTES) { |
665 throw new InvalidProtocolBufferException("Invalid Any type."); | 568 throw new InvalidProtocolBufferException("Invalid Any type."); |
666 } | 569 } |
667 String typeUrl = (String) message.getField(typeUrlField); | 570 String typeUrl = (String) message.getField(typeUrlField); |
668 String typeName = getTypeName(typeUrl); | 571 String typeName = getTypeName(typeUrl); |
669 Descriptor type = registry.find(typeName); | 572 Descriptor type = registry.find(typeName); |
670 if (type == null) { | 573 if (type == null) { |
671 throw new InvalidProtocolBufferException("Cannot find type for url: " +
typeUrl); | 574 throw new InvalidProtocolBufferException( |
| 575 "Cannot find type for url: " + typeUrl); |
672 } | 576 } |
673 ByteString content = (ByteString) message.getField(valueField); | 577 ByteString content = (ByteString) message.getField(valueField); |
674 Message contentMessage = | 578 Message contentMessage = DynamicMessage.getDefaultInstance(type) |
675 DynamicMessage.getDefaultInstance(type).getParserForType().parseFrom(c
ontent); | 579 .getParserForType().parseFrom(content); |
676 WellKnownTypePrinter printer = wellKnownTypePrinters.get(typeName); | 580 WellKnownTypePrinter printer = wellKnownTypePrinters.get(typeName); |
677 if (printer != null) { | 581 if (printer != null) { |
678 // If the type is one of the well-known types, we use a special | 582 // If the type is one of the well-known types, we use a special |
679 // formatting. | 583 // formatting. |
680 generator.print("{" + blankOrNewLine); | 584 generator.print("{\n"); |
681 generator.indent(); | 585 generator.indent(); |
682 generator.print("\"@type\":" + blankOrSpace + gson.toJson(typeUrl) + ","
+ blankOrNewLine); | 586 generator.print("\"@type\": " + gson.toJson(typeUrl) + ",\n"); |
683 generator.print("\"value\":" + blankOrSpace); | 587 generator.print("\"value\": "); |
684 printer.print(this, contentMessage); | 588 printer.print(this, contentMessage); |
685 generator.print(blankOrNewLine); | 589 generator.print("\n"); |
686 generator.outdent(); | 590 generator.outdent(); |
687 generator.print("}"); | 591 generator.print("}"); |
688 } else { | 592 } else { |
689 // Print the content message instead (with a "@type" field added). | 593 // Print the content message instead (with a "@type" field added). |
690 print(contentMessage, typeUrl); | 594 print(contentMessage, typeUrl); |
691 } | 595 } |
692 } | 596 } |
693 | 597 |
694 /** Prints wrapper types (e.g., google.protobuf.Int32Value) */ | 598 /** Prints wrapper types (e.g., google.protobuf.Int32Value) */ |
695 private void printWrapper(MessageOrBuilder message) throws IOException { | 599 private void printWrapper(MessageOrBuilder message) throws IOException { |
696 Descriptor descriptor = message.getDescriptorForType(); | 600 Descriptor descriptor = message.getDescriptorForType(); |
697 FieldDescriptor valueField = descriptor.findFieldByName("value"); | 601 FieldDescriptor valueField = descriptor.findFieldByName("value"); |
698 if (valueField == null) { | 602 if (valueField == null) { |
699 throw new InvalidProtocolBufferException("Invalid Wrapper type."); | 603 throw new InvalidProtocolBufferException("Invalid Wrapper type."); |
700 } | 604 } |
701 // When formatting wrapper types, we just print its value field instead of | 605 // When formatting wrapper types, we just print its value field instead of |
702 // the whole message. | 606 // the whole message. |
703 printSingleFieldValue(valueField, message.getField(valueField)); | 607 printSingleFieldValue(valueField, message.getField(valueField)); |
704 } | 608 } |
705 | 609 |
706 private ByteString toByteString(MessageOrBuilder message) { | 610 private ByteString toByteString(MessageOrBuilder message) { |
707 if (message instanceof Message) { | 611 if (message instanceof Message) { |
708 return ((Message) message).toByteString(); | 612 return ((Message) message).toByteString(); |
709 } else { | 613 } else { |
710 return ((Message.Builder) message).build().toByteString(); | 614 return ((Message.Builder) message).build().toByteString(); |
711 } | 615 } |
712 } | 616 } |
713 | 617 |
714 /** Prints google.protobuf.Timestamp */ | 618 /** Prints google.protobuf.Timestamp */ |
715 private void printTimestamp(MessageOrBuilder message) throws IOException { | 619 private void printTimestamp(MessageOrBuilder message) throws IOException { |
716 Timestamp value = Timestamp.parseFrom(toByteString(message)); | 620 Timestamp value = Timestamp.parseFrom(toByteString(message)); |
717 generator.print("\"" + Timestamps.toString(value) + "\""); | 621 generator.print("\"" + TimeUtil.toString(value) + "\""); |
718 } | 622 } |
719 | 623 |
720 /** Prints google.protobuf.Duration */ | 624 /** Prints google.protobuf.Duration */ |
721 private void printDuration(MessageOrBuilder message) throws IOException { | 625 private void printDuration(MessageOrBuilder message) throws IOException { |
722 Duration value = Duration.parseFrom(toByteString(message)); | 626 Duration value = Duration.parseFrom(toByteString(message)); |
723 generator.print("\"" + Durations.toString(value) + "\""); | 627 generator.print("\"" + TimeUtil.toString(value) + "\""); |
| 628 |
724 } | 629 } |
725 | 630 |
726 /** Prints google.protobuf.FieldMask */ | 631 /** Prints google.protobuf.FieldMask */ |
727 private void printFieldMask(MessageOrBuilder message) throws IOException { | 632 private void printFieldMask(MessageOrBuilder message) throws IOException { |
728 FieldMask value = FieldMask.parseFrom(toByteString(message)); | 633 FieldMask value = FieldMask.parseFrom(toByteString(message)); |
729 generator.print("\"" + FieldMaskUtil.toJsonString(value) + "\""); | 634 generator.print("\"" + FieldMaskUtil.toString(value) + "\""); |
730 } | 635 } |
731 | 636 |
732 /** Prints google.protobuf.Struct */ | 637 /** Prints google.protobuf.Struct */ |
733 private void printStruct(MessageOrBuilder message) throws IOException { | 638 private void printStruct(MessageOrBuilder message) throws IOException { |
734 Descriptor descriptor = message.getDescriptorForType(); | 639 Descriptor descriptor = message.getDescriptorForType(); |
735 FieldDescriptor field = descriptor.findFieldByName("fields"); | 640 FieldDescriptor field = descriptor.findFieldByName("fields"); |
736 if (field == null) { | 641 if (field == null) { |
737 throw new InvalidProtocolBufferException("Invalid Struct type."); | 642 throw new InvalidProtocolBufferException("Invalid Struct type."); |
738 } | 643 } |
739 // Struct is formatted as a map object. | 644 // Struct is formatted as a map object. |
740 printMapFieldValue(field, message.getField(field)); | 645 printMapFieldValue(field, message.getField(field)); |
741 } | 646 } |
742 | 647 |
743 /** Prints google.protobuf.Value */ | 648 /** Prints google.protobuf.Value */ |
744 private void printValue(MessageOrBuilder message) throws IOException { | 649 private void printValue(MessageOrBuilder message) throws IOException { |
745 // For a Value message, only the value of the field is formatted. | 650 // For a Value message, only the value of the field is formatted. |
746 Map<FieldDescriptor, Object> fields = message.getAllFields(); | 651 Map<FieldDescriptor, Object> fields = message.getAllFields(); |
747 if (fields.isEmpty()) { | 652 if (fields.isEmpty()) { |
748 // No value set. | 653 // No value set. |
749 generator.print("null"); | 654 generator.print("null"); |
750 return; | 655 return; |
751 } | 656 } |
752 // A Value message can only have at most one field set (it only contains | 657 // A Value message can only have at most one field set (it only contains |
753 // an oneof). | 658 // an oneof). |
754 if (fields.size() != 1) { | 659 if (fields.size() != 1) { |
755 throw new InvalidProtocolBufferException("Invalid Value type."); | 660 throw new InvalidProtocolBufferException("Invalid Value type."); |
756 } | 661 } |
757 for (Map.Entry<FieldDescriptor, Object> entry : fields.entrySet()) { | 662 for (Map.Entry<FieldDescriptor, Object> entry : fields.entrySet()) { |
758 printSingleFieldValue(entry.getKey(), entry.getValue()); | 663 printSingleFieldValue(entry.getKey(), entry.getValue()); |
759 } | 664 } |
760 } | 665 } |
761 | 666 |
762 /** Prints google.protobuf.ListValue */ | 667 /** Prints google.protobuf.ListValue */ |
763 private void printListValue(MessageOrBuilder message) throws IOException { | 668 private void printListValue(MessageOrBuilder message) throws IOException { |
764 Descriptor descriptor = message.getDescriptorForType(); | 669 Descriptor descriptor = message.getDescriptorForType(); |
765 FieldDescriptor field = descriptor.findFieldByName("values"); | 670 FieldDescriptor field = descriptor.findFieldByName("values"); |
766 if (field == null) { | 671 if (field == null) { |
767 throw new InvalidProtocolBufferException("Invalid ListValue type."); | 672 throw new InvalidProtocolBufferException("Invalid ListValue type."); |
768 } | 673 } |
769 printRepeatedFieldValue(field, message.getField(field)); | 674 printRepeatedFieldValue(field, message.getField(field)); |
770 } | 675 } |
771 | 676 |
772 /** Prints a regular message with an optional type URL. */ | 677 /** Prints a regular message with an optional type URL. */ |
773 private void print(MessageOrBuilder message, String typeUrl) throws IOExcept
ion { | 678 private void print(MessageOrBuilder message, String typeUrl) |
774 generator.print("{" + blankOrNewLine); | 679 throws IOException { |
| 680 generator.print("{\n"); |
775 generator.indent(); | 681 generator.indent(); |
776 | 682 |
777 boolean printedField = false; | 683 boolean printedField = false; |
778 if (typeUrl != null) { | 684 if (typeUrl != null) { |
779 generator.print("\"@type\":" + blankOrSpace + gson.toJson(typeUrl)); | 685 generator.print("\"@type\": " + gson.toJson(typeUrl)); |
780 printedField = true; | 686 printedField = true; |
781 } | 687 } |
782 Map<FieldDescriptor, Object> fieldsToPrint = null; | 688 Map<FieldDescriptor, Object> fieldsToPrint = null; |
783 if (includingDefaultValueFields) { | 689 if (includingDefaultValueFields) { |
784 fieldsToPrint = new TreeMap<FieldDescriptor, Object>(); | 690 fieldsToPrint = new TreeMap<FieldDescriptor, Object>(); |
785 for (FieldDescriptor field : message.getDescriptorForType().getFields())
{ | 691 for (FieldDescriptor field : message.getDescriptorForType().getFields())
{ |
786 if (field.isOptional()) { | 692 if (field.isOptional() |
787 if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE | 693 && field.getJavaType() == FieldDescriptor.JavaType.MESSAGE |
788 && !message.hasField(field)){ | 694 && !message.hasField(field)) { |
789 // Always skip empty optional message fields. If not we will recur
se indefinitely if | 695 // Always skip empty optional message fields. If not we will recurse
indefinitely if |
790 // a message has itself as a sub-field. | 696 // a message has itself as a sub-field. |
791 continue; | 697 continue; |
792 } | |
793 OneofDescriptor oneof = field.getContainingOneof(); | |
794 if (oneof != null && !message.hasField(field)) { | |
795 // Skip all oneof fields except the one that is actually set | |
796 continue; | |
797 } | |
798 } | 698 } |
799 fieldsToPrint.put(field, message.getField(field)); | 699 fieldsToPrint.put(field, message.getField(field)); |
800 } | 700 } |
801 } else { | 701 } else { |
802 fieldsToPrint = message.getAllFields(); | 702 fieldsToPrint = message.getAllFields(); |
803 } | 703 } |
804 for (Map.Entry<FieldDescriptor, Object> field : fieldsToPrint.entrySet())
{ | 704 for (Map.Entry<FieldDescriptor, Object> field : fieldsToPrint.entrySet())
{ |
805 if (printedField) { | 705 if (printedField) { |
806 // Add line-endings for the previous field. | 706 // Add line-endings for the previous field. |
807 generator.print("," + blankOrNewLine); | 707 generator.print(",\n"); |
808 } else { | 708 } else { |
809 printedField = true; | 709 printedField = true; |
810 } | 710 } |
811 printField(field.getKey(), field.getValue()); | 711 printField(field.getKey(), field.getValue()); |
812 } | 712 } |
813 | 713 |
814 // Add line-endings for the last field. | 714 // Add line-endings for the last field. |
815 if (printedField) { | 715 if (printedField) { |
816 generator.print(blankOrNewLine); | 716 generator.print("\n"); |
817 } | 717 } |
818 generator.outdent(); | 718 generator.outdent(); |
819 generator.print("}"); | 719 generator.print("}"); |
820 } | 720 } |
821 | 721 |
822 private void printField(FieldDescriptor field, Object value) throws IOExcept
ion { | 722 private void printField(FieldDescriptor field, Object value) |
| 723 throws IOException { |
823 if (preservingProtoFieldNames) { | 724 if (preservingProtoFieldNames) { |
824 generator.print("\"" + field.getName() + "\":" + blankOrSpace); | 725 generator.print("\"" + field.getName() + "\": "); |
825 } else { | 726 } else { |
826 generator.print("\"" + field.getJsonName() + "\":" + blankOrSpace); | 727 generator.print("\"" + field.getJsonName() + "\": "); |
827 } | 728 } |
828 if (field.isMapField()) { | 729 if (field.isMapField()) { |
829 printMapFieldValue(field, value); | 730 printMapFieldValue(field, value); |
830 } else if (field.isRepeated()) { | 731 } else if (field.isRepeated()) { |
831 printRepeatedFieldValue(field, value); | 732 printRepeatedFieldValue(field, value); |
832 } else { | 733 } else { |
833 printSingleFieldValue(field, value); | 734 printSingleFieldValue(field, value); |
834 } | 735 } |
835 } | 736 } |
836 | 737 |
837 @SuppressWarnings("rawtypes") | 738 @SuppressWarnings("rawtypes") |
838 private void printRepeatedFieldValue(FieldDescriptor field, Object value) th
rows IOException { | 739 private void printRepeatedFieldValue(FieldDescriptor field, Object value) |
| 740 throws IOException { |
839 generator.print("["); | 741 generator.print("["); |
840 boolean printedElement = false; | 742 boolean printedElement = false; |
841 for (Object element : (List) value) { | 743 for (Object element : (List) value) { |
842 if (printedElement) { | 744 if (printedElement) { |
843 generator.print("," + blankOrSpace); | 745 generator.print(", "); |
844 } else { | 746 } else { |
845 printedElement = true; | 747 printedElement = true; |
846 } | 748 } |
847 printSingleFieldValue(field, element); | 749 printSingleFieldValue(field, element); |
848 } | 750 } |
849 generator.print("]"); | 751 generator.print("]"); |
850 } | 752 } |
851 | 753 |
852 @SuppressWarnings("rawtypes") | 754 @SuppressWarnings("rawtypes") |
853 private void printMapFieldValue(FieldDescriptor field, Object value) throws
IOException { | 755 private void printMapFieldValue(FieldDescriptor field, Object value) |
| 756 throws IOException { |
854 Descriptor type = field.getMessageType(); | 757 Descriptor type = field.getMessageType(); |
855 FieldDescriptor keyField = type.findFieldByName("key"); | 758 FieldDescriptor keyField = type.findFieldByName("key"); |
856 FieldDescriptor valueField = type.findFieldByName("value"); | 759 FieldDescriptor valueField = type.findFieldByName("value"); |
857 if (keyField == null || valueField == null) { | 760 if (keyField == null || valueField == null) { |
858 throw new InvalidProtocolBufferException("Invalid map field."); | 761 throw new InvalidProtocolBufferException("Invalid map field."); |
859 } | 762 } |
860 generator.print("{" + blankOrNewLine); | 763 generator.print("{\n"); |
861 generator.indent(); | 764 generator.indent(); |
862 boolean printedElement = false; | 765 boolean printedElement = false; |
863 for (Object element : (List) value) { | 766 for (Object element : (List) value) { |
864 Message entry = (Message) element; | 767 Message entry = (Message) element; |
865 Object entryKey = entry.getField(keyField); | 768 Object entryKey = entry.getField(keyField); |
866 Object entryValue = entry.getField(valueField); | 769 Object entryValue = entry.getField(valueField); |
867 if (printedElement) { | 770 if (printedElement) { |
868 generator.print("," + blankOrNewLine); | 771 generator.print(",\n"); |
869 } else { | 772 } else { |
870 printedElement = true; | 773 printedElement = true; |
871 } | 774 } |
872 // Key fields are always double-quoted. | 775 // Key fields are always double-quoted. |
873 printSingleFieldValue(keyField, entryKey, true); | 776 printSingleFieldValue(keyField, entryKey, true); |
874 generator.print(":" + blankOrSpace); | 777 generator.print(": "); |
875 printSingleFieldValue(valueField, entryValue); | 778 printSingleFieldValue(valueField, entryValue); |
876 } | 779 } |
877 if (printedElement) { | 780 if (printedElement) { |
878 generator.print(blankOrNewLine); | 781 generator.print("\n"); |
879 } | 782 } |
880 generator.outdent(); | 783 generator.outdent(); |
881 generator.print("}"); | 784 generator.print("}"); |
882 } | 785 } |
883 | 786 |
884 private void printSingleFieldValue(FieldDescriptor field, Object value) thro
ws IOException { | 787 private void printSingleFieldValue(FieldDescriptor field, Object value) |
| 788 throws IOException { |
885 printSingleFieldValue(field, value, false); | 789 printSingleFieldValue(field, value, false); |
886 } | 790 } |
887 | 791 |
888 /** | 792 /** |
889 * Prints a field's value in JSON format. | 793 * Prints a field's value in JSON format. |
890 * | 794 * |
891 * @param alwaysWithQuotes whether to always add double-quotes to primitive | 795 * @param alwaysWithQuotes whether to always add double-quotes to primitive |
892 * types. | 796 * types. |
893 */ | 797 */ |
894 private void printSingleFieldValue( | 798 private void printSingleFieldValue( |
895 final FieldDescriptor field, final Object value, boolean alwaysWithQuote
s) | 799 final FieldDescriptor field, final Object value, |
896 throws IOException { | 800 boolean alwaysWithQuotes) throws IOException { |
897 switch (field.getType()) { | 801 switch (field.getType()) { |
898 case INT32: | 802 case INT32: |
899 case SINT32: | 803 case SINT32: |
900 case SFIXED32: | 804 case SFIXED32: |
901 if (alwaysWithQuotes) { | 805 if (alwaysWithQuotes) { |
902 generator.print("\""); | 806 generator.print("\""); |
903 } | 807 } |
904 generator.print(((Integer) value).toString()); | 808 generator.print(((Integer) value).toString()); |
905 if (alwaysWithQuotes) { | 809 if (alwaysWithQuotes) { |
906 generator.print("\""); | 810 generator.print("\""); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
940 } else { | 844 } else { |
941 if (alwaysWithQuotes) { | 845 if (alwaysWithQuotes) { |
942 generator.print("\""); | 846 generator.print("\""); |
943 } | 847 } |
944 generator.print(floatValue.toString()); | 848 generator.print(floatValue.toString()); |
945 if (alwaysWithQuotes) { | 849 if (alwaysWithQuotes) { |
946 generator.print("\""); | 850 generator.print("\""); |
947 } | 851 } |
948 } | 852 } |
949 break; | 853 break; |
950 | 854 |
951 case DOUBLE: | 855 case DOUBLE: |
952 Double doubleValue = (Double) value; | 856 Double doubleValue = (Double) value; |
953 if (doubleValue.isNaN()) { | 857 if (doubleValue.isNaN()) { |
954 generator.print("\"NaN\""); | 858 generator.print("\"NaN\""); |
955 } else if (doubleValue.isInfinite()) { | 859 } else if (doubleValue.isInfinite()) { |
956 if (doubleValue < 0) { | 860 if (doubleValue < 0) { |
957 generator.print("\"-Infinity\""); | 861 generator.print("\"-Infinity\""); |
958 } else { | 862 } else { |
959 generator.print("\"Infinity\""); | 863 generator.print("\"Infinity\""); |
960 } | 864 } |
(...skipping 23 matching lines...) Expand all Loading... |
984 case FIXED64: | 888 case FIXED64: |
985 generator.print("\"" + unsignedToString((Long) value) + "\""); | 889 generator.print("\"" + unsignedToString((Long) value) + "\""); |
986 break; | 890 break; |
987 | 891 |
988 case STRING: | 892 case STRING: |
989 generator.print(gson.toJson(value)); | 893 generator.print(gson.toJson(value)); |
990 break; | 894 break; |
991 | 895 |
992 case BYTES: | 896 case BYTES: |
993 generator.print("\""); | 897 generator.print("\""); |
994 generator.print(BaseEncoding.base64().encode(((ByteString) value).toBy
teArray())); | 898 generator.print( |
| 899 BaseEncoding.base64().encode(((ByteString) value).toByteArray())); |
995 generator.print("\""); | 900 generator.print("\""); |
996 break; | 901 break; |
997 | 902 |
998 case ENUM: | 903 case ENUM: |
999 // Special-case google.protobuf.NullValue (it's an Enum). | 904 // Special-case google.protobuf.NullValue (it's an Enum). |
1000 if (field.getEnumType().getFullName().equals("google.protobuf.NullValu
e")) { | 905 if (field.getEnumType().getFullName().equals( |
| 906 "google.protobuf.NullValue")) { |
1001 // No matter what value it contains, we always print it as "null". | 907 // No matter what value it contains, we always print it as "null". |
1002 if (alwaysWithQuotes) { | 908 if (alwaysWithQuotes) { |
1003 generator.print("\""); | 909 generator.print("\""); |
1004 } | 910 } |
1005 generator.print("null"); | 911 generator.print("null"); |
1006 if (alwaysWithQuotes) { | 912 if (alwaysWithQuotes) { |
1007 generator.print("\""); | 913 generator.print("\""); |
1008 } | 914 } |
1009 } else { | 915 } else { |
1010 if (((EnumValueDescriptor) value).getIndex() == -1) { | 916 if (((EnumValueDescriptor) value).getIndex() == -1) { |
1011 generator.print(String.valueOf(((EnumValueDescriptor) value).getNu
mber())); | 917 generator.print( |
| 918 String.valueOf(((EnumValueDescriptor) value).getNumber())); |
1012 } else { | 919 } else { |
1013 generator.print("\"" + ((EnumValueDescriptor) value).getName() + "
\""); | 920 generator.print( |
| 921 "\"" + ((EnumValueDescriptor) value).getName() + "\""); |
1014 } | 922 } |
1015 } | 923 } |
1016 break; | 924 break; |
1017 | 925 |
1018 case MESSAGE: | 926 case MESSAGE: |
1019 case GROUP: | 927 case GROUP: |
1020 print((Message) value); | 928 print((Message) value); |
1021 break; | 929 break; |
1022 } | 930 } |
1023 } | 931 } |
1024 } | 932 } |
1025 | 933 |
1026 /** Convert an unsigned 32-bit integer to a string. */ | 934 /** Convert an unsigned 32-bit integer to a string. */ |
1027 private static String unsignedToString(final int value) { | 935 private static String unsignedToString(final int value) { |
1028 if (value >= 0) { | 936 if (value >= 0) { |
1029 return Integer.toString(value); | 937 return Integer.toString(value); |
1030 } else { | 938 } else { |
1031 return Long.toString(value & 0x00000000FFFFFFFFL); | 939 return Long.toString(value & 0x00000000FFFFFFFFL); |
1032 } | 940 } |
1033 } | 941 } |
1034 | 942 |
1035 /** Convert an unsigned 64-bit integer to a string. */ | 943 /** Convert an unsigned 64-bit integer to a string. */ |
1036 private static String unsignedToString(final long value) { | 944 private static String unsignedToString(final long value) { |
1037 if (value >= 0) { | 945 if (value >= 0) { |
1038 return Long.toString(value); | 946 return Long.toString(value); |
1039 } else { | 947 } else { |
1040 // Pull off the most-significant bit so that BigInteger doesn't think | 948 // Pull off the most-significant bit so that BigInteger doesn't think |
1041 // the number is negative, then set it again using setBit(). | 949 // the number is negative, then set it again using setBit(). |
1042 return BigInteger.valueOf(value & Long.MAX_VALUE).setBit(Long.SIZE - 1).to
String(); | 950 return BigInteger.valueOf(value & Long.MAX_VALUE) |
| 951 .setBit(Long.SIZE - 1).toString(); |
1043 } | 952 } |
1044 } | 953 } |
| 954 |
1045 | 955 |
1046 private static String getTypeName(String typeUrl) throws InvalidProtocolBuffer
Exception { | 956 private static String getTypeName(String typeUrl) |
| 957 throws InvalidProtocolBufferException { |
1047 String[] parts = typeUrl.split("/"); | 958 String[] parts = typeUrl.split("/"); |
1048 if (parts.length == 1) { | 959 if (parts.length == 1) { |
1049 throw new InvalidProtocolBufferException("Invalid type url found: " + type
Url); | 960 throw new InvalidProtocolBufferException( |
| 961 "Invalid type url found: " + typeUrl); |
1050 } | 962 } |
1051 return parts[parts.length - 1]; | 963 return parts[parts.length - 1]; |
1052 } | 964 } |
1053 | 965 |
1054 private static class ParserImpl { | 966 private static class ParserImpl { |
1055 private final TypeRegistry registry; | 967 private final TypeRegistry registry; |
1056 private final JsonParser jsonParser; | 968 private final JsonParser jsonParser; |
1057 private final boolean ignoringUnknownFields; | 969 |
1058 private final int recursionLimit; | 970 ParserImpl(TypeRegistry registry) { |
1059 private int currentDepth; | |
1060 | |
1061 ParserImpl(TypeRegistry registry, boolean ignoreUnknownFields, int recursion
Limit) { | |
1062 this.registry = registry; | 971 this.registry = registry; |
1063 this.ignoringUnknownFields = ignoreUnknownFields; | |
1064 this.jsonParser = new JsonParser(); | 972 this.jsonParser = new JsonParser(); |
1065 this.recursionLimit = recursionLimit; | |
1066 this.currentDepth = 0; | |
1067 } | 973 } |
1068 | 974 |
1069 void merge(Reader json, Message.Builder builder) throws IOException { | 975 void merge(Reader json, Message.Builder builder) |
| 976 throws IOException { |
1070 JsonReader reader = new JsonReader(json); | 977 JsonReader reader = new JsonReader(json); |
1071 reader.setLenient(false); | 978 reader.setLenient(false); |
1072 merge(jsonParser.parse(reader), builder); | 979 merge(jsonParser.parse(reader), builder); |
1073 } | 980 } |
1074 | 981 |
1075 void merge(String json, Message.Builder builder) throws InvalidProtocolBuffe
rException { | 982 void merge(String json, Message.Builder builder) |
| 983 throws InvalidProtocolBufferException { |
1076 try { | 984 try { |
1077 JsonReader reader = new JsonReader(new StringReader(json)); | 985 JsonReader reader = new JsonReader(new StringReader(json)); |
1078 reader.setLenient(false); | 986 reader.setLenient(false); |
1079 merge(jsonParser.parse(reader), builder); | 987 merge(jsonParser.parse(reader), builder); |
1080 } catch (InvalidProtocolBufferException e) { | 988 } catch (InvalidProtocolBufferException e) { |
1081 throw e; | 989 throw e; |
1082 } catch (Exception e) { | 990 } catch (Exception e) { |
1083 // We convert all exceptions from JSON parsing to our own exceptions. | 991 // We convert all exceptions from JSON parsing to our own exceptions. |
1084 throw new InvalidProtocolBufferException(e.getMessage()); | 992 throw new InvalidProtocolBufferException(e.getMessage()); |
1085 } | 993 } |
1086 } | 994 } |
1087 | 995 |
1088 private interface WellKnownTypeParser { | 996 private interface WellKnownTypeParser { |
1089 void merge(ParserImpl parser, JsonElement json, Message.Builder builder) | 997 void merge(ParserImpl parser, JsonElement json, Message.Builder builder) |
1090 throws InvalidProtocolBufferException; | 998 throws InvalidProtocolBufferException; |
1091 } | 999 } |
1092 | 1000 |
1093 private static final Map<String, WellKnownTypeParser> wellKnownTypeParsers = | 1001 private static final Map<String, WellKnownTypeParser> wellKnownTypeParsers = |
1094 buildWellKnownTypeParsers(); | 1002 buildWellKnownTypeParsers(); |
1095 | 1003 |
1096 private static Map<String, WellKnownTypeParser> buildWellKnownTypeParsers()
{ | 1004 private static Map<String, WellKnownTypeParser> |
1097 Map<String, WellKnownTypeParser> parsers = new HashMap<String, WellKnownTy
peParser>(); | 1005 buildWellKnownTypeParsers() { |
| 1006 Map<String, WellKnownTypeParser> parsers = |
| 1007 new HashMap<String, WellKnownTypeParser>(); |
1098 // Special-case Any. | 1008 // Special-case Any. |
1099 parsers.put( | 1009 parsers.put(Any.getDescriptor().getFullName(), new WellKnownTypeParser() { |
1100 Any.getDescriptor().getFullName(), | 1010 @Override |
1101 new WellKnownTypeParser() { | 1011 public void merge(ParserImpl parser, JsonElement json, |
1102 @Override | 1012 Message.Builder builder) throws InvalidProtocolBufferException { |
1103 public void merge(ParserImpl parser, JsonElement json, Message.Build
er builder) | 1013 parser.mergeAny(json, builder); |
1104 throws InvalidProtocolBufferException { | 1014 } |
1105 parser.mergeAny(json, builder); | 1015 }); |
1106 } | |
1107 }); | |
1108 // Special-case wrapper types. | 1016 // Special-case wrapper types. |
1109 WellKnownTypeParser wrappersPrinter = | 1017 WellKnownTypeParser wrappersPrinter = new WellKnownTypeParser() { |
1110 new WellKnownTypeParser() { | 1018 @Override |
1111 @Override | 1019 public void merge(ParserImpl parser, JsonElement json, |
1112 public void merge(ParserImpl parser, JsonElement json, Message.Build
er builder) | 1020 Message.Builder builder) throws InvalidProtocolBufferException { |
1113 throws InvalidProtocolBufferException { | 1021 parser.mergeWrapper(json, builder); |
1114 parser.mergeWrapper(json, builder); | 1022 } |
1115 } | 1023 }; |
1116 }; | |
1117 parsers.put(BoolValue.getDescriptor().getFullName(), wrappersPrinter); | 1024 parsers.put(BoolValue.getDescriptor().getFullName(), wrappersPrinter); |
1118 parsers.put(Int32Value.getDescriptor().getFullName(), wrappersPrinter); | 1025 parsers.put(Int32Value.getDescriptor().getFullName(), wrappersPrinter); |
1119 parsers.put(UInt32Value.getDescriptor().getFullName(), wrappersPrinter); | 1026 parsers.put(UInt32Value.getDescriptor().getFullName(), wrappersPrinter); |
1120 parsers.put(Int64Value.getDescriptor().getFullName(), wrappersPrinter); | 1027 parsers.put(Int64Value.getDescriptor().getFullName(), wrappersPrinter); |
1121 parsers.put(UInt64Value.getDescriptor().getFullName(), wrappersPrinter); | 1028 parsers.put(UInt64Value.getDescriptor().getFullName(), wrappersPrinter); |
1122 parsers.put(StringValue.getDescriptor().getFullName(), wrappersPrinter); | 1029 parsers.put(StringValue.getDescriptor().getFullName(), wrappersPrinter); |
1123 parsers.put(BytesValue.getDescriptor().getFullName(), wrappersPrinter); | 1030 parsers.put(BytesValue.getDescriptor().getFullName(), wrappersPrinter); |
1124 parsers.put(FloatValue.getDescriptor().getFullName(), wrappersPrinter); | 1031 parsers.put(FloatValue.getDescriptor().getFullName(), wrappersPrinter); |
1125 parsers.put(DoubleValue.getDescriptor().getFullName(), wrappersPrinter); | 1032 parsers.put(DoubleValue.getDescriptor().getFullName(), wrappersPrinter); |
1126 // Special-case Timestamp. | 1033 // Special-case Timestamp. |
1127 parsers.put( | 1034 parsers.put(Timestamp.getDescriptor().getFullName(), |
1128 Timestamp.getDescriptor().getFullName(), | |
1129 new WellKnownTypeParser() { | 1035 new WellKnownTypeParser() { |
1130 @Override | 1036 @Override |
1131 public void merge(ParserImpl parser, JsonElement json, Message.Build
er builder) | 1037 public void merge(ParserImpl parser, JsonElement json, |
1132 throws InvalidProtocolBufferException { | 1038 Message.Builder builder) throws InvalidProtocolBufferException { |
1133 parser.mergeTimestamp(json, builder); | 1039 parser.mergeTimestamp(json, builder); |
1134 } | 1040 } |
1135 }); | 1041 }); |
1136 // Special-case Duration. | 1042 // Special-case Duration. |
1137 parsers.put( | 1043 parsers.put(Duration.getDescriptor().getFullName(), |
1138 Duration.getDescriptor().getFullName(), | |
1139 new WellKnownTypeParser() { | 1044 new WellKnownTypeParser() { |
1140 @Override | 1045 @Override |
1141 public void merge(ParserImpl parser, JsonElement json, Message.Build
er builder) | 1046 public void merge(ParserImpl parser, JsonElement json, |
1142 throws InvalidProtocolBufferException { | 1047 Message.Builder builder) throws InvalidProtocolBufferException { |
1143 parser.mergeDuration(json, builder); | 1048 parser.mergeDuration(json, builder); |
1144 } | 1049 } |
1145 }); | 1050 }); |
1146 // Special-case FieldMask. | 1051 // Special-case FieldMask. |
1147 parsers.put( | 1052 parsers.put(FieldMask.getDescriptor().getFullName(), |
1148 FieldMask.getDescriptor().getFullName(), | |
1149 new WellKnownTypeParser() { | 1053 new WellKnownTypeParser() { |
1150 @Override | 1054 @Override |
1151 public void merge(ParserImpl parser, JsonElement json, Message.Build
er builder) | 1055 public void merge(ParserImpl parser, JsonElement json, |
1152 throws InvalidProtocolBufferException { | 1056 Message.Builder builder) throws InvalidProtocolBufferException { |
1153 parser.mergeFieldMask(json, builder); | 1057 parser.mergeFieldMask(json, builder); |
1154 } | 1058 } |
1155 }); | 1059 }); |
1156 // Special-case Struct. | 1060 // Special-case Struct. |
1157 parsers.put( | 1061 parsers.put(Struct.getDescriptor().getFullName(), |
1158 Struct.getDescriptor().getFullName(), | |
1159 new WellKnownTypeParser() { | 1062 new WellKnownTypeParser() { |
1160 @Override | 1063 @Override |
1161 public void merge(ParserImpl parser, JsonElement json, Message.Build
er builder) | 1064 public void merge(ParserImpl parser, JsonElement json, |
1162 throws InvalidProtocolBufferException { | 1065 Message.Builder builder) throws InvalidProtocolBufferException { |
1163 parser.mergeStruct(json, builder); | 1066 parser.mergeStruct(json, builder); |
1164 } | 1067 } |
1165 }); | 1068 }); |
1166 // Special-case ListValue. | 1069 // Special-case ListValue. |
1167 parsers.put( | 1070 parsers.put(ListValue.getDescriptor().getFullName(), |
1168 ListValue.getDescriptor().getFullName(), | |
1169 new WellKnownTypeParser() { | 1071 new WellKnownTypeParser() { |
1170 @Override | 1072 @Override |
1171 public void merge(ParserImpl parser, JsonElement json, Message.Build
er builder) | 1073 public void merge(ParserImpl parser, JsonElement json, |
1172 throws InvalidProtocolBufferException { | 1074 Message.Builder builder) throws InvalidProtocolBufferException { |
1173 parser.mergeListValue(json, builder); | 1075 parser.mergeListValue(json, builder); |
1174 } | 1076 } |
1175 }); | 1077 }); |
1176 // Special-case Value. | 1078 // Special-case Value. |
1177 parsers.put( | 1079 parsers.put(Value.getDescriptor().getFullName(), |
1178 Value.getDescriptor().getFullName(), | |
1179 new WellKnownTypeParser() { | 1080 new WellKnownTypeParser() { |
1180 @Override | 1081 @Override |
1181 public void merge(ParserImpl parser, JsonElement json, Message.Build
er builder) | 1082 public void merge(ParserImpl parser, JsonElement json, |
1182 throws InvalidProtocolBufferException { | 1083 Message.Builder builder) throws InvalidProtocolBufferException { |
1183 parser.mergeValue(json, builder); | 1084 parser.mergeValue(json, builder); |
1184 } | 1085 } |
1185 }); | 1086 }); |
1186 return parsers; | 1087 return parsers; |
1187 } | 1088 } |
1188 | 1089 |
1189 private void merge(JsonElement json, Message.Builder builder) | 1090 private void merge(JsonElement json, Message.Builder builder) |
1190 throws InvalidProtocolBufferException { | 1091 throws InvalidProtocolBufferException { |
1191 WellKnownTypeParser specialParser = | 1092 WellKnownTypeParser specialParser = wellKnownTypeParsers.get( |
1192 wellKnownTypeParsers.get(builder.getDescriptorForType().getFullName())
; | 1093 builder.getDescriptorForType().getFullName()); |
1193 if (specialParser != null) { | 1094 if (specialParser != null) { |
1194 specialParser.merge(this, json, builder); | 1095 specialParser.merge(this, json, builder); |
1195 return; | 1096 return; |
1196 } | 1097 } |
1197 mergeMessage(json, builder, false); | 1098 mergeMessage(json, builder, false); |
1198 } | 1099 } |
1199 | 1100 |
1200 // Maps from camel-case field names to FieldDescriptor. | 1101 // Maps from camel-case field names to FieldDescriptor. |
1201 private final Map<Descriptor, Map<String, FieldDescriptor>> fieldNameMaps = | 1102 private final Map<Descriptor, Map<String, FieldDescriptor>> fieldNameMaps = |
1202 new HashMap<Descriptor, Map<String, FieldDescriptor>>(); | 1103 new HashMap<Descriptor, Map<String, FieldDescriptor>>(); |
1203 | 1104 |
1204 private Map<String, FieldDescriptor> getFieldNameMap(Descriptor descriptor)
{ | 1105 private Map<String, FieldDescriptor> getFieldNameMap( |
| 1106 Descriptor descriptor) { |
1205 if (!fieldNameMaps.containsKey(descriptor)) { | 1107 if (!fieldNameMaps.containsKey(descriptor)) { |
1206 Map<String, FieldDescriptor> fieldNameMap = new HashMap<String, FieldDes
criptor>(); | 1108 Map<String, FieldDescriptor> fieldNameMap = |
| 1109 new HashMap<String, FieldDescriptor>(); |
1207 for (FieldDescriptor field : descriptor.getFields()) { | 1110 for (FieldDescriptor field : descriptor.getFields()) { |
1208 fieldNameMap.put(field.getName(), field); | 1111 fieldNameMap.put(field.getName(), field); |
1209 fieldNameMap.put(field.getJsonName(), field); | 1112 fieldNameMap.put(field.getJsonName(), field); |
1210 } | 1113 } |
1211 fieldNameMaps.put(descriptor, fieldNameMap); | 1114 fieldNameMaps.put(descriptor, fieldNameMap); |
1212 return fieldNameMap; | 1115 return fieldNameMap; |
1213 } | 1116 } |
1214 return fieldNameMaps.get(descriptor); | 1117 return fieldNameMaps.get(descriptor); |
1215 } | 1118 } |
1216 | 1119 |
1217 private void mergeMessage(JsonElement json, Message.Builder builder, boolean
skipTypeUrl) | 1120 private void mergeMessage(JsonElement json, Message.Builder builder, |
1218 throws InvalidProtocolBufferException { | 1121 boolean skipTypeUrl) throws InvalidProtocolBufferException { |
1219 if (!(json instanceof JsonObject)) { | 1122 if (!(json instanceof JsonObject)) { |
1220 throw new InvalidProtocolBufferException("Expect message object but got:
" + json); | 1123 throw new InvalidProtocolBufferException( |
| 1124 "Expect message object but got: " + json); |
1221 } | 1125 } |
1222 JsonObject object = (JsonObject) json; | 1126 JsonObject object = (JsonObject) json; |
1223 Map<String, FieldDescriptor> fieldNameMap = getFieldNameMap(builder.getDes
criptorForType()); | 1127 Map<String, FieldDescriptor> fieldNameMap = |
| 1128 getFieldNameMap(builder.getDescriptorForType()); |
1224 for (Map.Entry<String, JsonElement> entry : object.entrySet()) { | 1129 for (Map.Entry<String, JsonElement> entry : object.entrySet()) { |
1225 if (skipTypeUrl && entry.getKey().equals("@type")) { | 1130 if (skipTypeUrl && entry.getKey().equals("@type")) { |
1226 continue; | 1131 continue; |
1227 } | 1132 } |
1228 FieldDescriptor field = fieldNameMap.get(entry.getKey()); | 1133 FieldDescriptor field = fieldNameMap.get(entry.getKey()); |
1229 if (field == null) { | 1134 if (field == null) { |
1230 if (ignoringUnknownFields) { | |
1231 continue; | |
1232 } | |
1233 throw new InvalidProtocolBufferException( | 1135 throw new InvalidProtocolBufferException( |
1234 "Cannot find field: " | 1136 "Cannot find field: " + entry.getKey() + " in message " |
1235 + entry.getKey() | 1137 + builder.getDescriptorForType().getFullName()); |
1236 + " in message " | |
1237 + builder.getDescriptorForType().getFullName()); | |
1238 } | 1138 } |
1239 mergeField(field, entry.getValue(), builder); | 1139 mergeField(field, entry.getValue(), builder); |
1240 } | 1140 } |
1241 } | 1141 } |
1242 | 1142 |
1243 private void mergeAny(JsonElement json, Message.Builder builder) | 1143 private void mergeAny(JsonElement json, Message.Builder builder) |
1244 throws InvalidProtocolBufferException { | 1144 throws InvalidProtocolBufferException { |
1245 Descriptor descriptor = builder.getDescriptorForType(); | 1145 Descriptor descriptor = builder.getDescriptorForType(); |
1246 FieldDescriptor typeUrlField = descriptor.findFieldByName("type_url"); | 1146 FieldDescriptor typeUrlField = descriptor.findFieldByName("type_url"); |
1247 FieldDescriptor valueField = descriptor.findFieldByName("value"); | 1147 FieldDescriptor valueField = descriptor.findFieldByName("value"); |
1248 // Validates type of the message. Note that we can't just cast the message | 1148 // Validates type of the message. Note that we can't just cast the message |
1249 // to com.google.protobuf.Any because it might be a DynamicMessage. | 1149 // to com.google.protobuf.Any because it might be a DynamicMessage. |
1250 if (typeUrlField == null | 1150 if (typeUrlField == null || valueField == null |
1251 || valueField == null | |
1252 || typeUrlField.getType() != FieldDescriptor.Type.STRING | 1151 || typeUrlField.getType() != FieldDescriptor.Type.STRING |
1253 || valueField.getType() != FieldDescriptor.Type.BYTES) { | 1152 || valueField.getType() != FieldDescriptor.Type.BYTES) { |
1254 throw new InvalidProtocolBufferException("Invalid Any type."); | 1153 throw new InvalidProtocolBufferException("Invalid Any type."); |
1255 } | 1154 } |
1256 | 1155 |
1257 if (!(json instanceof JsonObject)) { | 1156 if (!(json instanceof JsonObject)) { |
1258 throw new InvalidProtocolBufferException("Expect message object but got:
" + json); | 1157 throw new InvalidProtocolBufferException( |
| 1158 "Expect message object but got: " + json); |
1259 } | 1159 } |
1260 JsonObject object = (JsonObject) json; | 1160 JsonObject object = (JsonObject) json; |
1261 if (object.entrySet().isEmpty()) { | |
1262 return; // builder never modified, so it will end up building the defaul
t instance of Any | |
1263 } | |
1264 JsonElement typeUrlElement = object.get("@type"); | 1161 JsonElement typeUrlElement = object.get("@type"); |
1265 if (typeUrlElement == null) { | 1162 if (typeUrlElement == null) { |
1266 throw new InvalidProtocolBufferException("Missing type url when parsing:
" + json); | 1163 throw new InvalidProtocolBufferException( |
| 1164 "Missing type url when parsing: " + json); |
1267 } | 1165 } |
1268 String typeUrl = typeUrlElement.getAsString(); | 1166 String typeUrl = typeUrlElement.getAsString(); |
1269 Descriptor contentType = registry.find(getTypeName(typeUrl)); | 1167 Descriptor contentType = registry.find(getTypeName(typeUrl)); |
1270 if (contentType == null) { | 1168 if (contentType == null) { |
1271 throw new InvalidProtocolBufferException("Cannot resolve type: " + typeU
rl); | 1169 throw new InvalidProtocolBufferException( |
| 1170 "Cannot resolve type: " + typeUrl); |
1272 } | 1171 } |
1273 builder.setField(typeUrlField, typeUrl); | 1172 builder.setField(typeUrlField, typeUrl); |
1274 Message.Builder contentBuilder = | 1173 Message.Builder contentBuilder = |
1275 DynamicMessage.getDefaultInstance(contentType).newBuilderForType(); | 1174 DynamicMessage.getDefaultInstance(contentType).newBuilderForType(); |
1276 WellKnownTypeParser specialParser = wellKnownTypeParsers.get(contentType.g
etFullName()); | 1175 WellKnownTypeParser specialParser = |
| 1176 wellKnownTypeParsers.get(contentType.getFullName()); |
1277 if (specialParser != null) { | 1177 if (specialParser != null) { |
1278 JsonElement value = object.get("value"); | 1178 JsonElement value = object.get("value"); |
1279 if (value != null) { | 1179 if (value != null) { |
1280 specialParser.merge(this, value, contentBuilder); | 1180 specialParser.merge(this, value, contentBuilder); |
1281 } | 1181 } |
1282 } else { | 1182 } else { |
1283 mergeMessage(json, contentBuilder, true); | 1183 mergeMessage(json, contentBuilder, true); |
1284 } | 1184 } |
1285 builder.setField(valueField, contentBuilder.build().toByteString()); | 1185 builder.setField(valueField, contentBuilder.build().toByteString()); |
1286 } | 1186 } |
1287 | 1187 |
1288 private void mergeFieldMask(JsonElement json, Message.Builder builder) | 1188 private void mergeFieldMask(JsonElement json, Message.Builder builder) |
1289 throws InvalidProtocolBufferException { | 1189 throws InvalidProtocolBufferException { |
1290 FieldMask value = FieldMaskUtil.fromJsonString(json.getAsString()); | 1190 FieldMask value = FieldMaskUtil.fromString(json.getAsString()); |
1291 builder.mergeFrom(value.toByteString()); | 1191 builder.mergeFrom(value.toByteString()); |
1292 } | 1192 } |
1293 | 1193 |
1294 private void mergeTimestamp(JsonElement json, Message.Builder builder) | 1194 private void mergeTimestamp(JsonElement json, Message.Builder builder) |
1295 throws InvalidProtocolBufferException { | 1195 throws InvalidProtocolBufferException { |
1296 try { | 1196 try { |
1297 Timestamp value = Timestamps.parse(json.getAsString()); | 1197 Timestamp value = TimeUtil.parseTimestamp(json.getAsString()); |
1298 builder.mergeFrom(value.toByteString()); | 1198 builder.mergeFrom(value.toByteString()); |
1299 } catch (ParseException e) { | 1199 } catch (ParseException e) { |
1300 throw new InvalidProtocolBufferException("Failed to parse timestamp: " +
json); | 1200 throw new InvalidProtocolBufferException( |
| 1201 "Failed to parse timestamp: " + json); |
1301 } | 1202 } |
1302 } | 1203 } |
1303 | 1204 |
1304 private void mergeDuration(JsonElement json, Message.Builder builder) | 1205 private void mergeDuration(JsonElement json, Message.Builder builder) |
1305 throws InvalidProtocolBufferException { | 1206 throws InvalidProtocolBufferException { |
1306 try { | 1207 try { |
1307 Duration value = Durations.parse(json.getAsString()); | 1208 Duration value = TimeUtil.parseDuration(json.getAsString()); |
1308 builder.mergeFrom(value.toByteString()); | 1209 builder.mergeFrom(value.toByteString()); |
1309 } catch (ParseException e) { | 1210 } catch (ParseException e) { |
1310 throw new InvalidProtocolBufferException("Failed to parse duration: " +
json); | 1211 throw new InvalidProtocolBufferException( |
| 1212 "Failed to parse duration: " + json); |
1311 } | 1213 } |
1312 } | 1214 } |
1313 | 1215 |
1314 private void mergeStruct(JsonElement json, Message.Builder builder) | 1216 private void mergeStruct(JsonElement json, Message.Builder builder) |
1315 throws InvalidProtocolBufferException { | 1217 throws InvalidProtocolBufferException { |
1316 Descriptor descriptor = builder.getDescriptorForType(); | 1218 Descriptor descriptor = builder.getDescriptorForType(); |
1317 FieldDescriptor field = descriptor.findFieldByName("fields"); | 1219 FieldDescriptor field = descriptor.findFieldByName("fields"); |
1318 if (field == null) { | 1220 if (field == null) { |
1319 throw new InvalidProtocolBufferException("Invalid Struct type."); | 1221 throw new InvalidProtocolBufferException("Invalid Struct type."); |
1320 } | 1222 } |
1321 mergeMapField(field, json, builder); | 1223 mergeMapField(field, json, builder); |
1322 } | 1224 } |
1323 | 1225 |
1324 private void mergeListValue(JsonElement json, Message.Builder builder) | 1226 private void mergeListValue(JsonElement json, Message.Builder builder) |
1325 throws InvalidProtocolBufferException { | 1227 throws InvalidProtocolBufferException { |
1326 Descriptor descriptor = builder.getDescriptorForType(); | 1228 Descriptor descriptor = builder.getDescriptorForType(); |
1327 FieldDescriptor field = descriptor.findFieldByName("values"); | 1229 FieldDescriptor field = descriptor.findFieldByName("values"); |
1328 if (field == null) { | 1230 if (field == null) { |
1329 throw new InvalidProtocolBufferException("Invalid ListValue type."); | 1231 throw new InvalidProtocolBufferException("Invalid ListValue type."); |
1330 } | 1232 } |
1331 mergeRepeatedField(field, json, builder); | 1233 mergeRepeatedField(field, json, builder); |
1332 } | 1234 } |
1333 | 1235 |
1334 private void mergeValue(JsonElement json, Message.Builder builder) | 1236 private void mergeValue(JsonElement json, Message.Builder builder) |
1335 throws InvalidProtocolBufferException { | 1237 throws InvalidProtocolBufferException { |
1336 Descriptor type = builder.getDescriptorForType(); | 1238 Descriptor type = builder.getDescriptorForType(); |
1337 if (json instanceof JsonPrimitive) { | 1239 if (json instanceof JsonPrimitive) { |
1338 JsonPrimitive primitive = (JsonPrimitive) json; | 1240 JsonPrimitive primitive = (JsonPrimitive) json; |
1339 if (primitive.isBoolean()) { | 1241 if (primitive.isBoolean()) { |
1340 builder.setField(type.findFieldByName("bool_value"), primitive.getAsBo
olean()); | 1242 builder.setField(type.findFieldByName("bool_value"), |
| 1243 primitive.getAsBoolean()); |
1341 } else if (primitive.isNumber()) { | 1244 } else if (primitive.isNumber()) { |
1342 builder.setField(type.findFieldByName("number_value"), primitive.getAs
Double()); | 1245 builder.setField(type.findFieldByName("number_value"), |
| 1246 primitive.getAsDouble()); |
1343 } else { | 1247 } else { |
1344 builder.setField(type.findFieldByName("string_value"), primitive.getAs
String()); | 1248 builder.setField(type.findFieldByName("string_value"), |
| 1249 primitive.getAsString()); |
1345 } | 1250 } |
1346 } else if (json instanceof JsonObject) { | 1251 } else if (json instanceof JsonObject) { |
1347 FieldDescriptor field = type.findFieldByName("struct_value"); | 1252 FieldDescriptor field = type.findFieldByName("struct_value"); |
1348 Message.Builder structBuilder = builder.newBuilderForField(field); | 1253 Message.Builder structBuilder = builder.newBuilderForField(field); |
1349 merge(json, structBuilder); | 1254 merge(json, structBuilder); |
1350 builder.setField(field, structBuilder.build()); | 1255 builder.setField(field, structBuilder.build()); |
1351 } else if (json instanceof JsonArray) { | 1256 } else if (json instanceof JsonArray) { |
1352 FieldDescriptor field = type.findFieldByName("list_value"); | 1257 FieldDescriptor field = type.findFieldByName("list_value"); |
1353 Message.Builder listBuilder = builder.newBuilderForField(field); | 1258 Message.Builder listBuilder = builder.newBuilderForField(field); |
1354 merge(json, listBuilder); | 1259 merge(json, listBuilder); |
1355 builder.setField(field, listBuilder.build()); | 1260 builder.setField(field, listBuilder.build()); |
1356 } else if (json instanceof JsonNull) { | |
1357 builder.setField( | |
1358 type.findFieldByName("null_value"), NullValue.NULL_VALUE.getValueDes
criptor()); | |
1359 } else { | 1261 } else { |
1360 throw new IllegalStateException("Unexpected json data: " + json); | 1262 throw new IllegalStateException("Unexpected json data: " + json); |
1361 } | 1263 } |
1362 } | 1264 } |
1363 | 1265 |
1364 private void mergeWrapper(JsonElement json, Message.Builder builder) | 1266 private void mergeWrapper(JsonElement json, Message.Builder builder) |
1365 throws InvalidProtocolBufferException { | 1267 throws InvalidProtocolBufferException { |
1366 Descriptor type = builder.getDescriptorForType(); | 1268 Descriptor type = builder.getDescriptorForType(); |
1367 FieldDescriptor field = type.findFieldByName("value"); | 1269 FieldDescriptor field = type.findFieldByName("value"); |
1368 if (field == null) { | 1270 if (field == null) { |
1369 throw new InvalidProtocolBufferException("Invalid wrapper type: " + type
.getFullName()); | 1271 throw new InvalidProtocolBufferException( |
| 1272 "Invalid wrapper type: " + type.getFullName()); |
1370 } | 1273 } |
1371 builder.setField(field, parseFieldValue(field, json, builder)); | 1274 builder.setField(field, parseFieldValue(field, json, builder)); |
1372 } | 1275 } |
1373 | 1276 |
1374 private void mergeField(FieldDescriptor field, JsonElement json, Message.Bui
lder builder) | 1277 private void mergeField(FieldDescriptor field, JsonElement json, |
1375 throws InvalidProtocolBufferException { | 1278 Message.Builder builder) throws InvalidProtocolBufferException { |
1376 if (field.isRepeated()) { | 1279 if (field.isRepeated()) { |
1377 if (builder.getRepeatedFieldCount(field) > 0) { | 1280 if (builder.getRepeatedFieldCount(field) > 0) { |
1378 throw new InvalidProtocolBufferException( | 1281 throw new InvalidProtocolBufferException( |
1379 "Field " + field.getFullName() + " has already been set."); | 1282 "Field " + field.getFullName() + " has already been set."); |
1380 } | 1283 } |
1381 } else { | 1284 } else { |
1382 if (builder.hasField(field)) { | 1285 if (builder.hasField(field)) { |
1383 throw new InvalidProtocolBufferException( | 1286 throw new InvalidProtocolBufferException( |
1384 "Field " + field.getFullName() + " has already been set."); | 1287 "Field " + field.getFullName() + " has already been set."); |
1385 } | 1288 } |
1386 if (field.getContainingOneof() != null | 1289 if (field.getContainingOneof() != null |
1387 && builder.getOneofFieldDescriptor(field.getContainingOneof()) != nu
ll) { | 1290 && builder.getOneofFieldDescriptor(field.getContainingOneof()) != nu
ll) { |
1388 FieldDescriptor other = builder.getOneofFieldDescriptor(field.getConta
iningOneof()); | 1291 FieldDescriptor other = builder.getOneofFieldDescriptor(field.getConta
iningOneof()); |
1389 throw new InvalidProtocolBufferException( | 1292 throw new InvalidProtocolBufferException( |
1390 "Cannot set field " | 1293 "Cannot set field " + field.getFullName() + " because another fiel
d " |
1391 + field.getFullName() | 1294 + other.getFullName() + " belonging to the same oneof has already
been set "); |
1392 + " because another field " | |
1393 + other.getFullName() | |
1394 + " belonging to the same oneof has already been set "); | |
1395 } | 1295 } |
1396 } | 1296 } |
1397 if (field.isRepeated() && json instanceof JsonNull) { | 1297 if (field.isRepeated() && json instanceof JsonNull) { |
1398 // We allow "null" as value for all field types and treat it as if the | 1298 // We allow "null" as value for all field types and treat it as if the |
1399 // field is not present. | 1299 // field is not present. |
1400 return; | 1300 return; |
1401 } | 1301 } |
1402 if (field.isMapField()) { | 1302 if (field.isMapField()) { |
1403 mergeMapField(field, json, builder); | 1303 mergeMapField(field, json, builder); |
1404 } else if (field.isRepeated()) { | 1304 } else if (field.isRepeated()) { |
1405 mergeRepeatedField(field, json, builder); | 1305 mergeRepeatedField(field, json, builder); |
1406 } else { | 1306 } else { |
1407 Object value = parseFieldValue(field, json, builder); | 1307 Object value = parseFieldValue(field, json, builder); |
1408 if (value != null) { | 1308 if (value != null) { |
1409 builder.setField(field, value); | 1309 builder.setField(field, value); |
1410 } | 1310 } |
1411 } | 1311 } |
1412 } | 1312 } |
1413 | 1313 |
1414 private void mergeMapField(FieldDescriptor field, JsonElement json, Message.
Builder builder) | 1314 private void mergeMapField(FieldDescriptor field, JsonElement json, |
1415 throws InvalidProtocolBufferException { | 1315 Message.Builder builder) throws InvalidProtocolBufferException { |
1416 if (!(json instanceof JsonObject)) { | 1316 if (!(json instanceof JsonObject)) { |
1417 throw new InvalidProtocolBufferException("Expect a map object but found:
" + json); | 1317 throw new InvalidProtocolBufferException( |
| 1318 "Expect a map object but found: " + json); |
1418 } | 1319 } |
1419 Descriptor type = field.getMessageType(); | 1320 Descriptor type = field.getMessageType(); |
1420 FieldDescriptor keyField = type.findFieldByName("key"); | 1321 FieldDescriptor keyField = type.findFieldByName("key"); |
1421 FieldDescriptor valueField = type.findFieldByName("value"); | 1322 FieldDescriptor valueField = type.findFieldByName("value"); |
1422 if (keyField == null || valueField == null) { | 1323 if (keyField == null || valueField == null) { |
1423 throw new InvalidProtocolBufferException("Invalid map field: " + field.g
etFullName()); | 1324 throw new InvalidProtocolBufferException( |
| 1325 "Invalid map field: " + field.getFullName()); |
1424 } | 1326 } |
1425 JsonObject object = (JsonObject) json; | 1327 JsonObject object = (JsonObject) json; |
1426 for (Map.Entry<String, JsonElement> entry : object.entrySet()) { | 1328 for (Map.Entry<String, JsonElement> entry : object.entrySet()) { |
1427 Message.Builder entryBuilder = builder.newBuilderForField(field); | 1329 Message.Builder entryBuilder = builder.newBuilderForField(field); |
1428 Object key = parseFieldValue(keyField, new JsonPrimitive(entry.getKey())
, entryBuilder); | 1330 Object key = parseFieldValue( |
1429 Object value = parseFieldValue(valueField, entry.getValue(), entryBuilde
r); | 1331 keyField, new JsonPrimitive(entry.getKey()), entryBuilder); |
| 1332 Object value = parseFieldValue( |
| 1333 valueField, entry.getValue(), entryBuilder); |
1430 if (value == null) { | 1334 if (value == null) { |
1431 throw new InvalidProtocolBufferException("Map value cannot be null."); | 1335 throw new InvalidProtocolBufferException( |
| 1336 "Map value cannot be null."); |
1432 } | 1337 } |
1433 entryBuilder.setField(keyField, key); | 1338 entryBuilder.setField(keyField, key); |
1434 entryBuilder.setField(valueField, value); | 1339 entryBuilder.setField(valueField, value); |
1435 builder.addRepeatedField(field, entryBuilder.build()); | 1340 builder.addRepeatedField(field, entryBuilder.build()); |
1436 } | 1341 } |
1437 } | 1342 } |
1438 | 1343 |
1439 /** | 1344 /** |
1440 * Gets the default value for a field type. Note that we use proto3 | 1345 * Gets the default value for a field type. Note that we use proto3 |
1441 * language defaults and ignore any default values set through the | 1346 * language defaults and ignore any default values set through the |
1442 * proto "default" option. | 1347 * proto "default" option. |
1443 */ | 1348 */ |
1444 private Object getDefaultValue(FieldDescriptor field, Message.Builder builde
r) { | 1349 private Object getDefaultValue(FieldDescriptor field, |
| 1350 Message.Builder builder) { |
1445 switch (field.getType()) { | 1351 switch (field.getType()) { |
1446 case INT32: | 1352 case INT32: |
1447 case SINT32: | 1353 case SINT32: |
1448 case SFIXED32: | 1354 case SFIXED32: |
1449 case UINT32: | 1355 case UINT32: |
1450 case FIXED32: | 1356 case FIXED32: |
1451 return 0; | 1357 return 0; |
1452 case INT64: | 1358 case INT64: |
1453 case SINT64: | 1359 case SINT64: |
1454 case SFIXED64: | 1360 case SFIXED64: |
1455 case UINT64: | 1361 case UINT64: |
1456 case FIXED64: | 1362 case FIXED64: |
1457 return 0L; | 1363 return 0L; |
1458 case FLOAT: | 1364 case FLOAT: |
1459 return 0.0f; | 1365 return 0.0f; |
1460 case DOUBLE: | 1366 case DOUBLE: |
1461 return 0.0; | 1367 return 0.0; |
1462 case BOOL: | 1368 case BOOL: |
1463 return false; | 1369 return false; |
1464 case STRING: | 1370 case STRING: |
1465 return ""; | 1371 return ""; |
1466 case BYTES: | 1372 case BYTES: |
1467 return ByteString.EMPTY; | 1373 return ByteString.EMPTY; |
1468 case ENUM: | 1374 case ENUM: |
1469 return field.getEnumType().getValues().get(0); | 1375 return field.getEnumType().getValues().get(0); |
1470 case MESSAGE: | 1376 case MESSAGE: |
1471 case GROUP: | 1377 case GROUP: |
1472 return builder.newBuilderForField(field).getDefaultInstanceForType(); | 1378 return builder.newBuilderForField(field).getDefaultInstanceForType(); |
1473 default: | 1379 default: |
1474 throw new IllegalStateException("Invalid field type: " + field.getType
()); | 1380 throw new IllegalStateException( |
| 1381 "Invalid field type: " + field.getType()); |
1475 } | 1382 } |
1476 } | 1383 } |
1477 | 1384 |
1478 private void mergeRepeatedField( | 1385 private void mergeRepeatedField(FieldDescriptor field, JsonElement json, |
1479 FieldDescriptor field, JsonElement json, Message.Builder builder) | 1386 Message.Builder builder) throws InvalidProtocolBufferException { |
1480 throws InvalidProtocolBufferException { | |
1481 if (!(json instanceof JsonArray)) { | 1387 if (!(json instanceof JsonArray)) { |
1482 throw new InvalidProtocolBufferException("Expect an array but found: " +
json); | 1388 throw new InvalidProtocolBufferException( |
| 1389 "Expect an array but found: " + json); |
1483 } | 1390 } |
1484 JsonArray array = (JsonArray) json; | 1391 JsonArray array = (JsonArray) json; |
1485 for (int i = 0; i < array.size(); ++i) { | 1392 for (int i = 0; i < array.size(); ++i) { |
1486 Object value = parseFieldValue(field, array.get(i), builder); | 1393 Object value = parseFieldValue(field, array.get(i), builder); |
1487 if (value == null) { | 1394 if (value == null) { |
1488 throw new InvalidProtocolBufferException("Repeated field elements cann
ot be null"); | 1395 throw new InvalidProtocolBufferException( |
| 1396 "Repeated field elements cannot be null"); |
1489 } | 1397 } |
1490 builder.addRepeatedField(field, value); | 1398 builder.addRepeatedField(field, value); |
1491 } | 1399 } |
1492 } | 1400 } |
1493 | 1401 |
1494 private int parseInt32(JsonElement json) throws InvalidProtocolBufferExcepti
on { | 1402 private int parseInt32(JsonElement json) |
| 1403 throws InvalidProtocolBufferException { |
1495 try { | 1404 try { |
1496 return Integer.parseInt(json.getAsString()); | 1405 return Integer.parseInt(json.getAsString()); |
1497 } catch (Exception e) { | 1406 } catch (Exception e) { |
1498 // Fall through. | 1407 // Fall through. |
1499 } | 1408 } |
1500 // JSON doesn't distinguish between integer values and floating point valu
es so "1" and | 1409 // JSON doesn't distinguish between integer values and floating point valu
es so "1" and |
1501 // "1.000" are treated as equal in JSON. For this reason we accept floatin
g point values for | 1410 // "1.000" are treated as equal in JSON. For this reason we accept floatin
g point values for |
1502 // integer fields as well as long as it actually is an integer (i.e., roun
d(value) == value). | 1411 // integer fields as well as long as it actually is an integer (i.e., roun
d(value) == value). |
1503 try { | 1412 try { |
1504 BigDecimal value = new BigDecimal(json.getAsString()); | 1413 BigDecimal value = new BigDecimal(json.getAsString()); |
1505 return value.intValueExact(); | 1414 return value.intValueExact(); |
1506 } catch (Exception e) { | 1415 } catch (Exception e) { |
1507 throw new InvalidProtocolBufferException("Not an int32 value: " + json); | 1416 throw new InvalidProtocolBufferException("Not an int32 value: " + json); |
1508 } | 1417 } |
1509 } | 1418 } |
1510 | 1419 |
1511 private long parseInt64(JsonElement json) throws InvalidProtocolBufferExcept
ion { | 1420 private long parseInt64(JsonElement json) |
| 1421 throws InvalidProtocolBufferException { |
1512 try { | 1422 try { |
1513 return Long.parseLong(json.getAsString()); | 1423 return Long.parseLong(json.getAsString()); |
1514 } catch (Exception e) { | 1424 } catch (Exception e) { |
1515 // Fall through. | 1425 // Fall through. |
1516 } | 1426 } |
1517 // JSON doesn't distinguish between integer values and floating point valu
es so "1" and | 1427 // JSON doesn't distinguish between integer values and floating point valu
es so "1" and |
1518 // "1.000" are treated as equal in JSON. For this reason we accept floatin
g point values for | 1428 // "1.000" are treated as equal in JSON. For this reason we accept floatin
g point values for |
1519 // integer fields as well as long as it actually is an integer (i.e., roun
d(value) == value). | 1429 // integer fields as well as long as it actually is an integer (i.e., roun
d(value) == value). |
1520 try { | 1430 try { |
1521 BigDecimal value = new BigDecimal(json.getAsString()); | 1431 BigDecimal value = new BigDecimal(json.getAsString()); |
1522 return value.longValueExact(); | 1432 return value.longValueExact(); |
1523 } catch (Exception e) { | 1433 } catch (Exception e) { |
1524 throw new InvalidProtocolBufferException("Not an int32 value: " + json); | 1434 throw new InvalidProtocolBufferException("Not an int32 value: " + json); |
1525 } | 1435 } |
1526 } | 1436 } |
1527 | 1437 |
1528 private int parseUint32(JsonElement json) throws InvalidProtocolBufferExcept
ion { | 1438 private int parseUint32(JsonElement json) |
| 1439 throws InvalidProtocolBufferException { |
1529 try { | 1440 try { |
1530 long result = Long.parseLong(json.getAsString()); | 1441 long result = Long.parseLong(json.getAsString()); |
1531 if (result < 0 || result > 0xFFFFFFFFL) { | 1442 if (result < 0 || result > 0xFFFFFFFFL) { |
1532 throw new InvalidProtocolBufferException("Out of range uint32 value: "
+ json); | 1443 throw new InvalidProtocolBufferException( |
| 1444 "Out of range uint32 value: " + json); |
1533 } | 1445 } |
1534 return (int) result; | 1446 return (int) result; |
1535 } catch (InvalidProtocolBufferException e) { | 1447 } catch (InvalidProtocolBufferException e) { |
1536 throw e; | 1448 throw e; |
1537 } catch (Exception e) { | 1449 } catch (Exception e) { |
1538 // Fall through. | 1450 // Fall through. |
1539 } | 1451 } |
1540 // JSON doesn't distinguish between integer values and floating point valu
es so "1" and | 1452 // JSON doesn't distinguish between integer values and floating point valu
es so "1" and |
1541 // "1.000" are treated as equal in JSON. For this reason we accept floatin
g point values for | 1453 // "1.000" are treated as equal in JSON. For this reason we accept floatin
g point values for |
1542 // integer fields as well as long as it actually is an integer (i.e., roun
d(value) == value). | 1454 // integer fields as well as long as it actually is an integer (i.e., roun
d(value) == value). |
1543 try { | 1455 try { |
1544 BigDecimal decimalValue = new BigDecimal(json.getAsString()); | 1456 BigDecimal decimalValue = new BigDecimal(json.getAsString()); |
1545 BigInteger value = decimalValue.toBigIntegerExact(); | 1457 BigInteger value = decimalValue.toBigIntegerExact(); |
1546 if (value.signum() < 0 || value.compareTo(new BigInteger("FFFFFFFF", 16)
) > 0) { | 1458 if (value.signum() < 0 || value.compareTo(new BigInteger("FFFFFFFF", 16)
) > 0) { |
1547 throw new InvalidProtocolBufferException("Out of range uint32 value: "
+ json); | 1459 throw new InvalidProtocolBufferException("Out of range uint32 value: "
+ json); |
1548 } | 1460 } |
1549 return value.intValue(); | 1461 return value.intValue(); |
1550 } catch (InvalidProtocolBufferException e) { | 1462 } catch (InvalidProtocolBufferException e) { |
1551 throw e; | 1463 throw e; |
1552 } catch (Exception e) { | 1464 } catch (Exception e) { |
1553 throw new InvalidProtocolBufferException("Not an uint32 value: " + json)
; | 1465 throw new InvalidProtocolBufferException( |
| 1466 "Not an uint32 value: " + json); |
1554 } | 1467 } |
1555 } | 1468 } |
1556 | 1469 |
1557 private static final BigInteger MAX_UINT64 = new BigInteger("FFFFFFFFFFFFFFF
F", 16); | 1470 private static final BigInteger MAX_UINT64 = |
1558 | 1471 new BigInteger("FFFFFFFFFFFFFFFF", 16); |
1559 private long parseUint64(JsonElement json) throws InvalidProtocolBufferExcep
tion { | 1472 |
| 1473 private long parseUint64(JsonElement json) |
| 1474 throws InvalidProtocolBufferException { |
1560 try { | 1475 try { |
1561 BigDecimal decimalValue = new BigDecimal(json.getAsString()); | 1476 BigDecimal decimalValue = new BigDecimal(json.getAsString()); |
1562 BigInteger value = decimalValue.toBigIntegerExact(); | 1477 BigInteger value = decimalValue.toBigIntegerExact(); |
1563 if (value.compareTo(BigInteger.ZERO) < 0 || value.compareTo(MAX_UINT64)
> 0) { | 1478 if (value.compareTo(BigInteger.ZERO) < 0 |
1564 throw new InvalidProtocolBufferException("Out of range uint64 value: "
+ json); | 1479 || value.compareTo(MAX_UINT64) > 0) { |
| 1480 throw new InvalidProtocolBufferException( |
| 1481 "Out of range uint64 value: " + json); |
1565 } | 1482 } |
1566 return value.longValue(); | 1483 return value.longValue(); |
1567 } catch (InvalidProtocolBufferException e) { | 1484 } catch (InvalidProtocolBufferException e) { |
1568 throw e; | 1485 throw e; |
1569 } catch (Exception e) { | 1486 } catch (Exception e) { |
1570 throw new InvalidProtocolBufferException("Not an uint64 value: " + json)
; | 1487 throw new InvalidProtocolBufferException( |
| 1488 "Not an uint64 value: " + json); |
1571 } | 1489 } |
1572 } | 1490 } |
1573 | 1491 |
1574 private boolean parseBool(JsonElement json) throws InvalidProtocolBufferExce
ption { | 1492 private boolean parseBool(JsonElement json) |
| 1493 throws InvalidProtocolBufferException { |
1575 if (json.getAsString().equals("true")) { | 1494 if (json.getAsString().equals("true")) { |
1576 return true; | 1495 return true; |
1577 } | 1496 } |
1578 if (json.getAsString().equals("false")) { | 1497 if (json.getAsString().equals("false")) { |
1579 return false; | 1498 return false; |
1580 } | 1499 } |
1581 throw new InvalidProtocolBufferException("Invalid bool value: " + json); | 1500 throw new InvalidProtocolBufferException("Invalid bool value: " + json); |
1582 } | 1501 } |
1583 | 1502 |
1584 private static final double EPSILON = 1e-6; | 1503 private static final double EPSILON = 1e-6; |
1585 | 1504 |
1586 private float parseFloat(JsonElement json) throws InvalidProtocolBufferExcep
tion { | 1505 private float parseFloat(JsonElement json) |
| 1506 throws InvalidProtocolBufferException { |
1587 if (json.getAsString().equals("NaN")) { | 1507 if (json.getAsString().equals("NaN")) { |
1588 return Float.NaN; | 1508 return Float.NaN; |
1589 } else if (json.getAsString().equals("Infinity")) { | 1509 } else if (json.getAsString().equals("Infinity")) { |
1590 return Float.POSITIVE_INFINITY; | 1510 return Float.POSITIVE_INFINITY; |
1591 } else if (json.getAsString().equals("-Infinity")) { | 1511 } else if (json.getAsString().equals("-Infinity")) { |
1592 return Float.NEGATIVE_INFINITY; | 1512 return Float.NEGATIVE_INFINITY; |
1593 } | 1513 } |
1594 try { | 1514 try { |
1595 // We don't use Float.parseFloat() here because that function simply | 1515 // We don't use Float.parseFloat() here because that function simply |
1596 // accepts all double values. Here we parse the value into a Double | 1516 // accepts all double values. Here we parse the value into a Double |
1597 // and do explicit range check on it. | 1517 // and do explicit range check on it. |
1598 double value = Double.parseDouble(json.getAsString()); | 1518 double value = Double.parseDouble(json.getAsString()); |
1599 // When a float value is printed, the printed value might be a little | 1519 // When a float value is printed, the printed value might be a little |
1600 // larger or smaller due to precision loss. Here we need to add a bit | 1520 // larger or smaller due to precision loss. Here we need to add a bit |
1601 // of tolerance when checking whether the float value is in range. | 1521 // of tolerance when checking whether the float value is in range. |
1602 if (value > Float.MAX_VALUE * (1.0 + EPSILON) | 1522 if (value > Float.MAX_VALUE * (1.0 + EPSILON) |
1603 || value < -Float.MAX_VALUE * (1.0 + EPSILON)) { | 1523 || value < -Float.MAX_VALUE * (1.0 + EPSILON)) { |
1604 throw new InvalidProtocolBufferException("Out of range float value: "
+ json); | 1524 throw new InvalidProtocolBufferException( |
| 1525 "Out of range float value: " + json); |
1605 } | 1526 } |
1606 return (float) value; | 1527 return (float) value; |
1607 } catch (InvalidProtocolBufferException e) { | 1528 } catch (InvalidProtocolBufferException e) { |
1608 throw e; | 1529 throw e; |
1609 } catch (Exception e) { | 1530 } catch (Exception e) { |
1610 throw new InvalidProtocolBufferException("Not a float value: " + json); | 1531 throw new InvalidProtocolBufferException("Not a float value: " + json); |
1611 } | 1532 } |
1612 } | 1533 } |
1613 | 1534 |
1614 private static final BigDecimal MORE_THAN_ONE = new BigDecimal(String.valueO
f(1.0 + EPSILON)); | 1535 private static final BigDecimal MORE_THAN_ONE = new BigDecimal( |
| 1536 String.valueOf(1.0 + EPSILON)); |
1615 // When a float value is printed, the printed value might be a little | 1537 // When a float value is printed, the printed value might be a little |
1616 // larger or smaller due to precision loss. Here we need to add a bit | 1538 // larger or smaller due to precision loss. Here we need to add a bit |
1617 // of tolerance when checking whether the float value is in range. | 1539 // of tolerance when checking whether the float value is in range. |
1618 private static final BigDecimal MAX_DOUBLE = | 1540 private static final BigDecimal MAX_DOUBLE = new BigDecimal( |
1619 new BigDecimal(String.valueOf(Double.MAX_VALUE)).multiply(MORE_THAN_ONE)
; | 1541 String.valueOf(Double.MAX_VALUE)).multiply(MORE_THAN_ONE); |
1620 private static final BigDecimal MIN_DOUBLE = | 1542 private static final BigDecimal MIN_DOUBLE = new BigDecimal( |
1621 new BigDecimal(String.valueOf(-Double.MAX_VALUE)).multiply(MORE_THAN_ONE
); | 1543 String.valueOf(-Double.MAX_VALUE)).multiply(MORE_THAN_ONE); |
1622 | 1544 |
1623 private double parseDouble(JsonElement json) throws InvalidProtocolBufferExc
eption { | 1545 private double parseDouble(JsonElement json) |
| 1546 throws InvalidProtocolBufferException { |
1624 if (json.getAsString().equals("NaN")) { | 1547 if (json.getAsString().equals("NaN")) { |
1625 return Double.NaN; | 1548 return Double.NaN; |
1626 } else if (json.getAsString().equals("Infinity")) { | 1549 } else if (json.getAsString().equals("Infinity")) { |
1627 return Double.POSITIVE_INFINITY; | 1550 return Double.POSITIVE_INFINITY; |
1628 } else if (json.getAsString().equals("-Infinity")) { | 1551 } else if (json.getAsString().equals("-Infinity")) { |
1629 return Double.NEGATIVE_INFINITY; | 1552 return Double.NEGATIVE_INFINITY; |
1630 } | 1553 } |
1631 try { | 1554 try { |
1632 // We don't use Double.parseDouble() here because that function simply | 1555 // We don't use Double.parseDouble() here because that function simply |
1633 // accepts all values. Here we parse the value into a BigDecimal and do | 1556 // accepts all values. Here we parse the value into a BigDecimal and do |
1634 // explicit range check on it. | 1557 // explicit range check on it. |
1635 BigDecimal value = new BigDecimal(json.getAsString()); | 1558 BigDecimal value = new BigDecimal(json.getAsString()); |
1636 if (value.compareTo(MAX_DOUBLE) > 0 || value.compareTo(MIN_DOUBLE) < 0)
{ | 1559 if (value.compareTo(MAX_DOUBLE) > 0 |
1637 throw new InvalidProtocolBufferException("Out of range double value: "
+ json); | 1560 || value.compareTo(MIN_DOUBLE) < 0) { |
| 1561 throw new InvalidProtocolBufferException( |
| 1562 "Out of range double value: " + json); |
1638 } | 1563 } |
1639 return value.doubleValue(); | 1564 return value.doubleValue(); |
1640 } catch (InvalidProtocolBufferException e) { | 1565 } catch (InvalidProtocolBufferException e) { |
1641 throw e; | 1566 throw e; |
1642 } catch (Exception e) { | 1567 } catch (Exception e) { |
1643 throw new InvalidProtocolBufferException("Not an double value: " + json)
; | 1568 throw new InvalidProtocolBufferException( |
| 1569 "Not an double value: " + json); |
1644 } | 1570 } |
1645 } | 1571 } |
1646 | 1572 |
1647 private String parseString(JsonElement json) { | 1573 private String parseString(JsonElement json) { |
1648 return json.getAsString(); | 1574 return json.getAsString(); |
1649 } | 1575 } |
1650 | 1576 |
1651 private ByteString parseBytes(JsonElement json) throws InvalidProtocolBuffer
Exception { | 1577 private ByteString parseBytes(JsonElement json) throws InvalidProtocolBuffer
Exception { |
1652 return ByteString.copyFrom(BaseEncoding.base64().decode(json.getAsString()
)); | 1578 String encoded = json.getAsString(); |
| 1579 if (encoded.length() % 4 != 0) { |
| 1580 throw new InvalidProtocolBufferException( |
| 1581 "Bytes field is not encoded in standard BASE64 with paddings: " + en
coded); |
| 1582 } |
| 1583 return ByteString.copyFrom( |
| 1584 BaseEncoding.base64().decode(json.getAsString())); |
1653 } | 1585 } |
1654 | 1586 |
1655 private EnumValueDescriptor parseEnum(EnumDescriptor enumDescriptor, JsonEle
ment json) | 1587 private EnumValueDescriptor parseEnum(EnumDescriptor enumDescriptor, |
1656 throws InvalidProtocolBufferException { | 1588 JsonElement json) throws InvalidProtocolBufferException { |
1657 String value = json.getAsString(); | 1589 String value = json.getAsString(); |
1658 EnumValueDescriptor result = enumDescriptor.findValueByName(value); | 1590 EnumValueDescriptor result = enumDescriptor.findValueByName(value); |
1659 if (result == null) { | 1591 if (result == null) { |
1660 // Try to interpret the value as a number. | 1592 // Try to interpret the value as a number. |
1661 try { | 1593 try { |
1662 int numericValue = parseInt32(json); | 1594 int numericValue = parseInt32(json); |
1663 if (enumDescriptor.getFile().getSyntax() == FileDescriptor.Syntax.PROT
O3) { | 1595 if (enumDescriptor.getFile().getSyntax() == FileDescriptor.Syntax.PROT
O3) { |
1664 result = enumDescriptor.findValueByNumberCreatingIfUnknown(numericVa
lue); | 1596 result = enumDescriptor.findValueByNumberCreatingIfUnknown(numericVa
lue); |
1665 } else { | 1597 } else { |
1666 result = enumDescriptor.findValueByNumber(numericValue); | 1598 result = enumDescriptor.findValueByNumber(numericValue); |
1667 } | 1599 } |
1668 } catch (InvalidProtocolBufferException e) { | 1600 } catch (InvalidProtocolBufferException e) { |
1669 // Fall through. This exception is about invalid int32 value we get fr
om parseInt32() but | 1601 // Fall through. This exception is about invalid int32 value we get fr
om parseInt32() but |
1670 // that's not the exception we want the user to see. Since result == n
ull, we will throw | 1602 // that's not the exception we want the user to see. Since result == n
ull, we will throw |
1671 // an exception later. | 1603 // an exception later. |
1672 } | 1604 } |
1673 | 1605 |
1674 if (result == null) { | 1606 if (result == null) { |
1675 throw new InvalidProtocolBufferException( | 1607 throw new InvalidProtocolBufferException( |
1676 "Invalid enum value: " + value + " for enum type: " + enumDescript
or.getFullName()); | 1608 "Invalid enum value: " + value + " for enum type: " |
| 1609 + enumDescriptor.getFullName()); |
1677 } | 1610 } |
1678 } | 1611 } |
1679 return result; | 1612 return result; |
1680 } | 1613 } |
1681 | 1614 |
1682 private Object parseFieldValue(FieldDescriptor field, JsonElement json, Mess
age.Builder builder) | 1615 private Object parseFieldValue(FieldDescriptor field, JsonElement json, |
1683 throws InvalidProtocolBufferException { | 1616 Message.Builder builder) throws InvalidProtocolBufferException { |
1684 if (json instanceof JsonNull) { | 1617 if (json instanceof JsonNull) { |
1685 if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE | 1618 if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE |
1686 && field.getMessageType().getFullName().equals(Value.getDescriptor()
.getFullName())) { | 1619 && field.getMessageType().getFullName().equals( |
| 1620 Value.getDescriptor().getFullName())) { |
1687 // For every other type, "null" means absence, but for the special | 1621 // For every other type, "null" means absence, but for the special |
1688 // Value message, it means the "null_value" field has been set. | 1622 // Value message, it means the "null_value" field has been set. |
1689 Value value = Value.newBuilder().setNullValueValue(0).build(); | 1623 Value value = Value.newBuilder().setNullValueValue(0).build(); |
1690 return builder.newBuilderForField(field).mergeFrom(value.toByteString(
)).build(); | 1624 return builder.newBuilderForField(field).mergeFrom( |
1691 } else if (field.getJavaType() == FieldDescriptor.JavaType.ENUM | 1625 value.toByteString()).build(); |
1692 && field.getEnumType().getFullName().equals(NullValue.getDescriptor(
).getFullName())) { | |
1693 // If the type of the field is a NullValue, then the value should be e
xplicitly set. | |
1694 return field.getEnumType().findValueByNumber(0); | |
1695 } | 1626 } |
1696 return null; | 1627 return null; |
1697 } | 1628 } |
1698 switch (field.getType()) { | 1629 switch (field.getType()) { |
1699 case INT32: | 1630 case INT32: |
1700 case SINT32: | 1631 case SINT32: |
1701 case SFIXED32: | 1632 case SFIXED32: |
1702 return parseInt32(json); | 1633 return parseInt32(json); |
1703 | 1634 |
1704 case INT64: | 1635 case INT64: |
1705 case SINT64: | 1636 case SINT64: |
1706 case SFIXED64: | 1637 case SFIXED64: |
1707 return parseInt64(json); | 1638 return parseInt64(json); |
1708 | 1639 |
1709 case BOOL: | 1640 case BOOL: |
1710 return parseBool(json); | 1641 return parseBool(json); |
1711 | 1642 |
1712 case FLOAT: | 1643 case FLOAT: |
1713 return parseFloat(json); | 1644 return parseFloat(json); |
1714 | 1645 |
1715 case DOUBLE: | 1646 case DOUBLE: |
1716 return parseDouble(json); | 1647 return parseDouble(json); |
1717 | 1648 |
1718 case UINT32: | 1649 case UINT32: |
1719 case FIXED32: | 1650 case FIXED32: |
1720 return parseUint32(json); | 1651 return parseUint32(json); |
1721 | 1652 |
1722 case UINT64: | 1653 case UINT64: |
1723 case FIXED64: | 1654 case FIXED64: |
1724 return parseUint64(json); | 1655 return parseUint64(json); |
1725 | 1656 |
1726 case STRING: | 1657 case STRING: |
1727 return parseString(json); | 1658 return parseString(json); |
1728 | 1659 |
1729 case BYTES: | 1660 case BYTES: |
1730 return parseBytes(json); | 1661 return parseBytes(json); |
1731 | 1662 |
1732 case ENUM: | 1663 case ENUM: |
1733 return parseEnum(field.getEnumType(), json); | 1664 return parseEnum(field.getEnumType(), json); |
1734 | 1665 |
1735 case MESSAGE: | 1666 case MESSAGE: |
1736 case GROUP: | 1667 case GROUP: |
1737 if (currentDepth >= recursionLimit) { | |
1738 throw new InvalidProtocolBufferException("Hit recursion limit."); | |
1739 } | |
1740 ++currentDepth; | |
1741 Message.Builder subBuilder = builder.newBuilderForField(field); | 1668 Message.Builder subBuilder = builder.newBuilderForField(field); |
1742 merge(json, subBuilder); | 1669 merge(json, subBuilder); |
1743 --currentDepth; | |
1744 return subBuilder.build(); | 1670 return subBuilder.build(); |
1745 | 1671 |
1746 default: | 1672 default: |
1747 throw new InvalidProtocolBufferException("Invalid field type: " + fiel
d.getType()); | 1673 throw new InvalidProtocolBufferException( |
1748 } | 1674 "Invalid field type: " + field.getType()); |
| 1675 } |
1749 } | 1676 } |
1750 } | 1677 } |
1751 } | 1678 } |
OLD | NEW |