1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // http://code.google.com/p/protobuf/ 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions are 7 // met: 8 // 9 // * Redistributions of source code must retain the above copyright 10 // notice, this list of conditions and the following disclaimer. 11 // * Redistributions in binary form must reproduce the above 12 // copyright notice, this list of conditions and the following disclaimer 13 // in the documentation and/or other materials provided with the 14 // distribution. 15 // * Neither the name of Google Inc. nor the names of its 16 // contributors may be used to endorse or promote products derived from 17 // this software without specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 package com.google.protobuf; 32 33 import com.google.protobuf.Descriptors.Descriptor; 34 import com.google.protobuf.Descriptors.FieldDescriptor; 35 36 import java.io.InputStream; 37 import java.io.IOException; 38 import java.util.Map; 39 40 /** 41 * An implementation of {@link Message} that can represent arbitrary types, 42 * given a {@link Descriptors.Descriptor}. 43 * 44 * @author kenton@google.com Kenton Varda 45 */ 46 public final class DynamicMessage extends AbstractMessage { 47 private final Descriptor type; 48 private final FieldSet<FieldDescriptor> fields; 49 private final UnknownFieldSet unknownFields; 50 private int memoizedSize = -1; 51 52 /** 53 * Construct a {@code DynamicMessage} using the given {@code FieldSet}. 54 */ DynamicMessage(Descriptor type, FieldSet<FieldDescriptor> fields, UnknownFieldSet unknownFields)55 private DynamicMessage(Descriptor type, FieldSet<FieldDescriptor> fields, 56 UnknownFieldSet unknownFields) { 57 this.type = type; 58 this.fields = fields; 59 this.unknownFields = unknownFields; 60 } 61 62 /** 63 * Get a {@code DynamicMessage} representing the default instance of the 64 * given type. 65 */ getDefaultInstance(Descriptor type)66 public static DynamicMessage getDefaultInstance(Descriptor type) { 67 return new DynamicMessage(type, FieldSet.<FieldDescriptor>emptySet(), 68 UnknownFieldSet.getDefaultInstance()); 69 } 70 71 /** Parse a message of the given type from the given input stream. */ parseFrom(Descriptor type, CodedInputStream input)72 public static DynamicMessage parseFrom(Descriptor type, 73 CodedInputStream input) 74 throws IOException { 75 return newBuilder(type).mergeFrom(input).buildParsed(); 76 } 77 78 /** Parse a message of the given type from the given input stream. */ parseFrom( Descriptor type, CodedInputStream input, ExtensionRegistry extensionRegistry)79 public static DynamicMessage parseFrom( 80 Descriptor type, 81 CodedInputStream input, 82 ExtensionRegistry extensionRegistry) 83 throws IOException { 84 return newBuilder(type).mergeFrom(input, extensionRegistry).buildParsed(); 85 } 86 87 /** Parse {@code data} as a message of the given type and return it. */ parseFrom(Descriptor type, ByteString data)88 public static DynamicMessage parseFrom(Descriptor type, ByteString data) 89 throws InvalidProtocolBufferException { 90 return newBuilder(type).mergeFrom(data).buildParsed(); 91 } 92 93 /** Parse {@code data} as a message of the given type and return it. */ parseFrom(Descriptor type, ByteString data, ExtensionRegistry extensionRegistry)94 public static DynamicMessage parseFrom(Descriptor type, ByteString data, 95 ExtensionRegistry extensionRegistry) 96 throws InvalidProtocolBufferException { 97 return newBuilder(type).mergeFrom(data, extensionRegistry).buildParsed(); 98 } 99 100 /** Parse {@code data} as a message of the given type and return it. */ parseFrom(Descriptor type, byte[] data)101 public static DynamicMessage parseFrom(Descriptor type, byte[] data) 102 throws InvalidProtocolBufferException { 103 return newBuilder(type).mergeFrom(data).buildParsed(); 104 } 105 106 /** Parse {@code data} as a message of the given type and return it. */ parseFrom(Descriptor type, byte[] data, ExtensionRegistry extensionRegistry)107 public static DynamicMessage parseFrom(Descriptor type, byte[] data, 108 ExtensionRegistry extensionRegistry) 109 throws InvalidProtocolBufferException { 110 return newBuilder(type).mergeFrom(data, extensionRegistry).buildParsed(); 111 } 112 113 /** Parse a message of the given type from {@code input} and return it. */ parseFrom(Descriptor type, InputStream input)114 public static DynamicMessage parseFrom(Descriptor type, InputStream input) 115 throws IOException { 116 return newBuilder(type).mergeFrom(input).buildParsed(); 117 } 118 119 /** Parse a message of the given type from {@code input} and return it. */ parseFrom(Descriptor type, InputStream input, ExtensionRegistry extensionRegistry)120 public static DynamicMessage parseFrom(Descriptor type, InputStream input, 121 ExtensionRegistry extensionRegistry) 122 throws IOException { 123 return newBuilder(type).mergeFrom(input, extensionRegistry).buildParsed(); 124 } 125 126 /** Construct a {@link Message.Builder} for the given type. */ newBuilder(Descriptor type)127 public static Builder newBuilder(Descriptor type) { 128 return new Builder(type); 129 } 130 131 /** 132 * Construct a {@link Message.Builder} for a message of the same type as 133 * {@code prototype}, and initialize it with {@code prototype}'s contents. 134 */ newBuilder(Message prototype)135 public static Builder newBuilder(Message prototype) { 136 return new Builder(prototype.getDescriptorForType()).mergeFrom(prototype); 137 } 138 139 // ----------------------------------------------------------------- 140 // Implementation of Message interface. 141 getDescriptorForType()142 public Descriptor getDescriptorForType() { 143 return type; 144 } 145 getDefaultInstanceForType()146 public DynamicMessage getDefaultInstanceForType() { 147 return getDefaultInstance(type); 148 } 149 getAllFields()150 public Map<FieldDescriptor, Object> getAllFields() { 151 return fields.getAllFields(); 152 } 153 hasField(FieldDescriptor field)154 public boolean hasField(FieldDescriptor field) { 155 verifyContainingType(field); 156 return fields.hasField(field); 157 } 158 getField(FieldDescriptor field)159 public Object getField(FieldDescriptor field) { 160 verifyContainingType(field); 161 Object result = fields.getField(field); 162 if (result == null) { 163 if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { 164 result = getDefaultInstance(field.getMessageType()); 165 } else { 166 result = field.getDefaultValue(); 167 } 168 } 169 return result; 170 } 171 getRepeatedFieldCount(FieldDescriptor field)172 public int getRepeatedFieldCount(FieldDescriptor field) { 173 verifyContainingType(field); 174 return fields.getRepeatedFieldCount(field); 175 } 176 getRepeatedField(FieldDescriptor field, int index)177 public Object getRepeatedField(FieldDescriptor field, int index) { 178 verifyContainingType(field); 179 return fields.getRepeatedField(field, index); 180 } 181 getUnknownFields()182 public UnknownFieldSet getUnknownFields() { 183 return unknownFields; 184 } 185 isInitialized(Descriptor type, FieldSet<FieldDescriptor> fields)186 private static boolean isInitialized(Descriptor type, 187 FieldSet<FieldDescriptor> fields) { 188 // Check that all required fields are present. 189 for (final FieldDescriptor field : type.getFields()) { 190 if (field.isRequired()) { 191 if (!fields.hasField(field)) { 192 return false; 193 } 194 } 195 } 196 197 // Check that embedded messages are initialized. 198 return fields.isInitialized(); 199 } 200 isInitialized()201 public boolean isInitialized() { 202 return isInitialized(type, fields); 203 } 204 writeTo(CodedOutputStream output)205 public void writeTo(CodedOutputStream output) throws IOException { 206 if (type.getOptions().getMessageSetWireFormat()) { 207 fields.writeMessageSetTo(output); 208 unknownFields.writeAsMessageSetTo(output); 209 } else { 210 fields.writeTo(output); 211 unknownFields.writeTo(output); 212 } 213 } 214 getSerializedSize()215 public int getSerializedSize() { 216 int size = memoizedSize; 217 if (size != -1) return size; 218 219 if (type.getOptions().getMessageSetWireFormat()) { 220 size = fields.getMessageSetSerializedSize(); 221 size += unknownFields.getSerializedSizeAsMessageSet(); 222 } else { 223 size = fields.getSerializedSize(); 224 size += unknownFields.getSerializedSize(); 225 } 226 227 memoizedSize = size; 228 return size; 229 } 230 newBuilderForType()231 public Builder newBuilderForType() { 232 return new Builder(type); 233 } 234 toBuilder()235 public Builder toBuilder() { 236 return newBuilderForType().mergeFrom(this); 237 } 238 239 /** Verifies that the field is a field of this message. */ verifyContainingType(FieldDescriptor field)240 private void verifyContainingType(FieldDescriptor field) { 241 if (field.getContainingType() != type) { 242 throw new IllegalArgumentException( 243 "FieldDescriptor does not match message type."); 244 } 245 } 246 247 // ================================================================= 248 249 /** 250 * Builder for {@link DynamicMessage}s. 251 */ 252 public static final class Builder extends AbstractMessage.Builder<Builder> { 253 private final Descriptor type; 254 private FieldSet<FieldDescriptor> fields; 255 private UnknownFieldSet unknownFields; 256 257 /** Construct a {@code Builder} for the given type. */ Builder(Descriptor type)258 private Builder(Descriptor type) { 259 this.type = type; 260 this.fields = FieldSet.newFieldSet(); 261 this.unknownFields = UnknownFieldSet.getDefaultInstance(); 262 } 263 264 // --------------------------------------------------------------- 265 // Implementation of Message.Builder interface. 266 clear()267 public Builder clear() { 268 if (fields == null) { 269 throw new IllegalStateException("Cannot call clear() after build()."); 270 } 271 fields.clear(); 272 return this; 273 } 274 mergeFrom(Message other)275 public Builder mergeFrom(Message other) { 276 if (other instanceof DynamicMessage) { 277 // This should be somewhat faster than calling super.mergeFrom(). 278 DynamicMessage otherDynamicMessage = (DynamicMessage) other; 279 if (otherDynamicMessage.type != type) { 280 throw new IllegalArgumentException( 281 "mergeFrom(Message) can only merge messages of the same type."); 282 } 283 fields.mergeFrom(otherDynamicMessage.fields); 284 mergeUnknownFields(otherDynamicMessage.unknownFields); 285 return this; 286 } else { 287 return super.mergeFrom(other); 288 } 289 } 290 build()291 public DynamicMessage build() { 292 // If fields == null, we'll throw an appropriate exception later. 293 if (fields != null && !isInitialized()) { 294 throw newUninitializedMessageException( 295 new DynamicMessage(type, fields, unknownFields)); 296 } 297 return buildPartial(); 298 } 299 300 /** 301 * Helper for DynamicMessage.parseFrom() methods to call. Throws 302 * {@link InvalidProtocolBufferException} instead of 303 * {@link UninitializedMessageException}. 304 */ buildParsed()305 private DynamicMessage buildParsed() throws InvalidProtocolBufferException { 306 if (!isInitialized()) { 307 throw newUninitializedMessageException( 308 new DynamicMessage(type, fields, unknownFields)) 309 .asInvalidProtocolBufferException(); 310 } 311 return buildPartial(); 312 } 313 buildPartial()314 public DynamicMessage buildPartial() { 315 if (fields == null) { 316 throw new IllegalStateException( 317 "build() has already been called on this Builder."); 318 } 319 fields.makeImmutable(); 320 DynamicMessage result = 321 new DynamicMessage(type, fields, unknownFields); 322 fields = null; 323 unknownFields = null; 324 return result; 325 } 326 clone()327 public Builder clone() { 328 Builder result = new Builder(type); 329 result.fields.mergeFrom(fields); 330 return result; 331 } 332 isInitialized()333 public boolean isInitialized() { 334 return DynamicMessage.isInitialized(type, fields); 335 } 336 getDescriptorForType()337 public Descriptor getDescriptorForType() { 338 return type; 339 } 340 getDefaultInstanceForType()341 public DynamicMessage getDefaultInstanceForType() { 342 return getDefaultInstance(type); 343 } 344 getAllFields()345 public Map<FieldDescriptor, Object> getAllFields() { 346 return fields.getAllFields(); 347 } 348 newBuilderForField(FieldDescriptor field)349 public Builder newBuilderForField(FieldDescriptor field) { 350 verifyContainingType(field); 351 352 if (field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) { 353 throw new IllegalArgumentException( 354 "newBuilderForField is only valid for fields with message type."); 355 } 356 357 return new Builder(field.getMessageType()); 358 } 359 hasField(FieldDescriptor field)360 public boolean hasField(FieldDescriptor field) { 361 verifyContainingType(field); 362 return fields.hasField(field); 363 } 364 getField(FieldDescriptor field)365 public Object getField(FieldDescriptor field) { 366 verifyContainingType(field); 367 Object result = fields.getField(field); 368 if (result == null) { 369 if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { 370 result = getDefaultInstance(field.getMessageType()); 371 } else { 372 result = field.getDefaultValue(); 373 } 374 } 375 return result; 376 } 377 setField(FieldDescriptor field, Object value)378 public Builder setField(FieldDescriptor field, Object value) { 379 verifyContainingType(field); 380 fields.setField(field, value); 381 return this; 382 } 383 clearField(FieldDescriptor field)384 public Builder clearField(FieldDescriptor field) { 385 verifyContainingType(field); 386 fields.clearField(field); 387 return this; 388 } 389 getRepeatedFieldCount(FieldDescriptor field)390 public int getRepeatedFieldCount(FieldDescriptor field) { 391 verifyContainingType(field); 392 return fields.getRepeatedFieldCount(field); 393 } 394 getRepeatedField(FieldDescriptor field, int index)395 public Object getRepeatedField(FieldDescriptor field, int index) { 396 verifyContainingType(field); 397 return fields.getRepeatedField(field, index); 398 } 399 setRepeatedField(FieldDescriptor field, int index, Object value)400 public Builder setRepeatedField(FieldDescriptor field, 401 int index, Object value) { 402 verifyContainingType(field); 403 fields.setRepeatedField(field, index, value); 404 return this; 405 } 406 addRepeatedField(FieldDescriptor field, Object value)407 public Builder addRepeatedField(FieldDescriptor field, Object value) { 408 verifyContainingType(field); 409 fields.addRepeatedField(field, value); 410 return this; 411 } 412 getUnknownFields()413 public UnknownFieldSet getUnknownFields() { 414 return unknownFields; 415 } 416 setUnknownFields(UnknownFieldSet unknownFields)417 public Builder setUnknownFields(UnknownFieldSet unknownFields) { 418 this.unknownFields = unknownFields; 419 return this; 420 } 421 mergeUnknownFields(UnknownFieldSet unknownFields)422 public Builder mergeUnknownFields(UnknownFieldSet unknownFields) { 423 this.unknownFields = 424 UnknownFieldSet.newBuilder(this.unknownFields) 425 .mergeFrom(unknownFields) 426 .build(); 427 return this; 428 } 429 430 /** Verifies that the field is a field of this message. */ verifyContainingType(FieldDescriptor field)431 private void verifyContainingType(FieldDescriptor field) { 432 if (field.getContainingType() != type) { 433 throw new IllegalArgumentException( 434 "FieldDescriptor does not match message type."); 435 } 436 } 437 } 438 } 439