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