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 31package com.google.protobuf; 32 33import com.google.protobuf.Descriptors.Descriptor; 34import com.google.protobuf.Descriptors.FieldDescriptor; 35 36import java.io.InputStream; 37import java.io.IOException; 38import 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 */ 46public 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 */ 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 */ 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. */ 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. */ 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. */ 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. */ 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. */ 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. */ 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. */ 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. */ 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. */ 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 */ 135 public static Builder newBuilder(Message prototype) { 136 return new Builder(prototype.getDescriptorForType()).mergeFrom(prototype); 137 } 138 139 // ----------------------------------------------------------------- 140 // Implementation of Message interface. 141 142 public Descriptor getDescriptorForType() { 143 return type; 144 } 145 146 public DynamicMessage getDefaultInstanceForType() { 147 return getDefaultInstance(type); 148 } 149 150 public Map<FieldDescriptor, Object> getAllFields() { 151 return fields.getAllFields(); 152 } 153 154 public boolean hasField(FieldDescriptor field) { 155 verifyContainingType(field); 156 return fields.hasField(field); 157 } 158 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 172 public int getRepeatedFieldCount(FieldDescriptor field) { 173 verifyContainingType(field); 174 return fields.getRepeatedFieldCount(field); 175 } 176 177 public Object getRepeatedField(FieldDescriptor field, int index) { 178 verifyContainingType(field); 179 return fields.getRepeatedField(field, index); 180 } 181 182 public UnknownFieldSet getUnknownFields() { 183 return unknownFields; 184 } 185 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 201 public boolean isInitialized() { 202 return isInitialized(type, fields); 203 } 204 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 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 231 public Builder newBuilderForType() { 232 return new Builder(type); 233 } 234 235 public Builder toBuilder() { 236 return newBuilderForType().mergeFrom(this); 237 } 238 239 /** Verifies that the field is a field of this message. */ 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. */ 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 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 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 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 */ 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 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 327 public Builder clone() { 328 Builder result = new Builder(type); 329 result.fields.mergeFrom(fields); 330 return result; 331 } 332 333 public boolean isInitialized() { 334 return DynamicMessage.isInitialized(type, fields); 335 } 336 337 public Descriptor getDescriptorForType() { 338 return type; 339 } 340 341 public DynamicMessage getDefaultInstanceForType() { 342 return getDefaultInstance(type); 343 } 344 345 public Map<FieldDescriptor, Object> getAllFields() { 346 return fields.getAllFields(); 347 } 348 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 360 public boolean hasField(FieldDescriptor field) { 361 verifyContainingType(field); 362 return fields.hasField(field); 363 } 364 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 378 public Builder setField(FieldDescriptor field, Object value) { 379 verifyContainingType(field); 380 fields.setField(field, value); 381 return this; 382 } 383 384 public Builder clearField(FieldDescriptor field) { 385 verifyContainingType(field); 386 fields.clearField(field); 387 return this; 388 } 389 390 public int getRepeatedFieldCount(FieldDescriptor field) { 391 verifyContainingType(field); 392 return fields.getRepeatedFieldCount(field); 393 } 394 395 public Object getRepeatedField(FieldDescriptor field, int index) { 396 verifyContainingType(field); 397 return fields.getRepeatedField(field, index); 398 } 399 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 407 public Builder addRepeatedField(FieldDescriptor field, Object value) { 408 verifyContainingType(field); 409 fields.addRepeatedField(field, value); 410 return this; 411 } 412 413 public UnknownFieldSet getUnknownFields() { 414 return unknownFields; 415 } 416 417 public Builder setUnknownFields(UnknownFieldSet unknownFields) { 418 this.unknownFields = unknownFields; 419 return this; 420 } 421 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. */ 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