Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(81)

Side by Side Diff: third_party/protobuf/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java

Issue 2590803003: Revert "third_party/protobuf: Update to HEAD (83d681ee2c)" (Closed)
Patch Set: Created 3 years, 12 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698