Subversion Repositories Code-Repo

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
87 Kevin 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
   */
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
}