• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
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 java.io.IOException;
34 
35 /**
36  * LazyFieldLite encapsulates the logic of lazily parsing message fields. It stores
37  * the message in a ByteString initially and then parses it on-demand.
38  *
39  * LazyFieldLite is thread-compatible: concurrent reads are safe once the proto that this
40  * LazyFieldLite is a part of is no longer being mutated by its Builder. However, explicit
41  * synchronization is needed under read/write situations.
42  *
43  * When a LazyFieldLite is used in the context of a MessageLite object, its behavior is considered
44  * to be immutable and none of the setter methods in its API are expected to be invoked. All of the
45  * getters are expected to be thread-safe. When used in the context of a MessageLite.Builder,
46  * setters can be invoked, but there is no guarantee of thread safety.
47  *
48  * TODO(yatin,dweis): Consider splitting this class's functionality and put the mutable methods
49  * into a separate builder class to allow us to give stronger compile-time guarantees.
50  *
51  * This class is internal implementation detail of the protobuf library, so you don't need to use it
52  * directly.
53  *
54  * @author xiangl@google.com (Xiang Li)
55  */
56 public class LazyFieldLite {
57   private static final ExtensionRegistryLite EMPTY_REGISTRY =
58       ExtensionRegistryLite.getEmptyRegistry();
59 
60   /**
61    * The value associated with the LazyFieldLite object is stored in one or more of the following
62    * three fields (delayedBytes, value, memoizedBytes). They should together be interpreted as
63    * follows.
64    * 1) delayedBytes can be non-null, while value and memoizedBytes is null. The object will be in
65    *    this state while the value for the object has not yet been parsed.
66    * 2) Both delayedBytes and value are non-null. The object transitions to this state as soon as
67    *    some caller needs to access the value (by invoking getValue()).
68    * 3) memoizedBytes is merely an optimization for calls to LazyFieldLite.toByteString() to avoid
69    *    recomputing the ByteString representation on each call. Instead, when the value is parsed
70    *    from delayedBytes, we will also assign the contents of delayedBytes to memoizedBytes (since
71    *    that is the ByteString representation of value).
72    * 4) Finally, if the LazyFieldLite was created directly with a parsed MessageLite value, then
73    *    delayedBytes will be null, and memoizedBytes will be initialized only upon the first call to
74    *    LazyFieldLite.toByteString().
75    *
76    * Given the above conditions, any caller that needs a serialized representation of this object
77    * must first check if the memoizedBytes or delayedBytes ByteString is non-null and use it
78    * directly; if both of those are null, it can look at the parsed value field. Similarly, any
79    * caller that needs a parsed value must first check if the value field is already non-null, if
80    * not it must parse the value from delayedBytes.
81    */
82 
83   /**
84    * A delayed-parsed version of the contents of this field. When this field is non-null, then the
85    * "value" field is allowed to be null until the time that the value needs to be read.
86    *
87    * When delayedBytes is non-null then {@code extensionRegistry} is required to also be non-null.
88    * {@code value} and {@code memoizedBytes} will be initialized lazily.
89    */
90   private ByteString delayedBytes;
91 
92   /**
93    * An {@code ExtensionRegistryLite} for parsing bytes. It is non-null on a best-effort basis. It
94    * is only guaranteed to be non-null if this message was initialized using bytes and an
95    * {@code ExtensionRegistry}. If it directly had a value set then it will be null, unless it has
96    * been merged with another {@code LazyFieldLite} that had an {@code ExtensionRegistry}.
97    */
98   private ExtensionRegistryLite extensionRegistry;
99 
100   /**
101    * The parsed value. When this is null and a caller needs access to the MessageLite value, then
102    * {@code delayedBytes} will be parsed lazily at that time.
103    */
104   protected volatile MessageLite value;
105 
106   /**
107    * The memoized bytes for {@code value}. This is an optimization for the toByteString() method to
108    * not have to recompute its return-value on each invocation.
109    * TODO(yatin): Figure out whether this optimization is actually necessary.
110    */
111   private volatile ByteString memoizedBytes;
112 
113   /**
114    * Constructs a LazyFieldLite with bytes that will be parsed lazily.
115    */
LazyFieldLite(ExtensionRegistryLite extensionRegistry, ByteString bytes)116   public LazyFieldLite(ExtensionRegistryLite extensionRegistry, ByteString bytes) {
117     checkArguments(extensionRegistry, bytes);
118     this.extensionRegistry = extensionRegistry;
119     this.delayedBytes = bytes;
120   }
121 
122   /**
123    * Constructs a LazyFieldLite with no contents, and no ability to parse extensions.
124    */
LazyFieldLite()125   public LazyFieldLite() {
126   }
127 
128   /**
129    * Constructs a LazyFieldLite instance with a value. The LazyFieldLite may not be able to parse
130    * the extensions in the value as it has no ExtensionRegistry.
131    */
fromValue(MessageLite value)132   public static LazyFieldLite fromValue(MessageLite value) {
133     LazyFieldLite lf = new LazyFieldLite();
134     lf.setValue(value);
135     return lf;
136   }
137 
138   @Override
equals(Object o)139   public boolean equals(Object o) {
140     if (this == o) {
141       return true;
142     }
143 
144     if (!(o instanceof LazyFieldLite)) {
145       return false;
146     }
147 
148     LazyFieldLite other = (LazyFieldLite) o;
149 
150     // Lazy fields do not work well with equals... If both are delayedBytes, we do not have a
151     // mechanism to deserialize them so we rely on bytes equality. Otherwise we coerce into an
152     // actual message (if necessary) and call equals on the message itself. This implies that two
153     // messages can by unequal but then be turned equal simply be invoking a getter on a lazy field.
154     MessageLite value1 = value;
155     MessageLite value2 = other.value;
156     if (value1 == null && value2 == null) {
157       return toByteString().equals(other.toByteString());
158     } else if (value1 != null && value2 != null) {
159       return value1.equals(value2);
160     } else if (value1 != null) {
161       return value1.equals(other.getValue(value1.getDefaultInstanceForType()));
162     } else {
163       return getValue(value2.getDefaultInstanceForType()).equals(value2);
164     }
165   }
166 
167   @Override
hashCode()168   public int hashCode() {
169     // We can't provide a memoizable hash code for lazy fields. The byte strings may have different
170     // hash codes but evaluate to equivalent messages. And we have no facility for constructing
171     // a message here if we were not already holding a value.
172     return 1;
173   }
174 
175   /**
176    * Determines whether this LazyFieldLite instance represents the default instance of this type.
177    */
containsDefaultInstance()178   public boolean containsDefaultInstance() {
179     return memoizedBytes == ByteString.EMPTY
180         || value == null && (delayedBytes == null || delayedBytes == ByteString.EMPTY);
181   }
182 
183   /**
184    * Clears the value state of this instance.
185    *
186    * <p>LazyField is not thread-safe for write access. Synchronizations are needed
187    * under read/write situations.
188    */
clear()189   public void clear() {
190     // Don't clear the ExtensionRegistry. It might prove useful later on when merging in another
191     // value, but there is no guarantee that it will contain all extensions that were directly set
192     // on the values that need to be merged.
193     delayedBytes = null;
194     value = null;
195     memoizedBytes = null;
196   }
197 
198   /**
199    * Overrides the contents of this LazyField.
200    *
201    * <p>LazyField is not thread-safe for write access. Synchronizations are needed
202    * under read/write situations.
203    */
set(LazyFieldLite other)204   public void set(LazyFieldLite other) {
205     this.delayedBytes = other.delayedBytes;
206     this.value = other.value;
207     this.memoizedBytes = other.memoizedBytes;
208     // If the other LazyFieldLite was created by directly setting the value rather than first by
209     // parsing, then it will not have an extensionRegistry. In this case we hold on to the existing
210     // extensionRegistry, which has no guarantees that it has all the extensions that will be
211     // directly set on the value.
212     if (other.extensionRegistry != null) {
213       this.extensionRegistry = other.extensionRegistry;
214     }
215   }
216 
217   /**
218    * Returns message instance. It may do some thread-safe delayed parsing of bytes.
219    *
220    * @param defaultInstance its message's default instance. It's also used to get parser for the
221    * message type.
222    */
getValue(MessageLite defaultInstance)223   public MessageLite getValue(MessageLite defaultInstance) {
224     ensureInitialized(defaultInstance);
225     return value;
226   }
227 
228   /**
229    * Sets the value of the instance and returns the old value without delay parsing anything.
230    *
231    * <p>LazyField is not thread-safe for write access. Synchronizations are needed
232    * under read/write situations.
233    */
setValue(MessageLite value)234   public MessageLite setValue(MessageLite value) {
235     MessageLite originalValue = this.value;
236     this.delayedBytes = null;
237     this.memoizedBytes = null;
238     this.value = value;
239     return originalValue;
240   }
241 
242   /**
243    * Merges another instance's contents. In some cases may drop some extensions if both fields
244    * contain data. If the other field has an {@code ExtensionRegistry} but this does not, then this
245    * field will copy over that {@code ExtensionRegistry}.
246    *
247    * <p>LazyField is not thread-safe for write access. Synchronizations are needed
248    * under read/write situations.
249    */
merge(LazyFieldLite other)250   public void merge(LazyFieldLite other) {
251     if (other.containsDefaultInstance()) {
252       return;
253     }
254 
255     if (this.containsDefaultInstance()) {
256       set(other);
257       return;
258     }
259 
260     // If the other field has an extension registry but this does not, copy over the other extension
261     // registry.
262     if (this.extensionRegistry == null) {
263       this.extensionRegistry = other.extensionRegistry;
264     }
265 
266     // In the case that both of them are not parsed we simply concatenate the bytes to save time. In
267     // the (probably rare) case that they have different extension registries there is a chance that
268     // some of the extensions may be dropped, but the tradeoff of making this operation fast seems
269     // to outway the benefits of combining the extension registries, which is not normally done for
270     // lite protos anyways.
271     if (this.delayedBytes != null && other.delayedBytes != null) {
272       this.delayedBytes = this.delayedBytes.concat(other.delayedBytes);
273       return;
274     }
275 
276     // At least one is parsed and both contain data. We won't drop any extensions here directly, but
277     // in the case that the extension registries are not the same then we might in the future if we
278     // need to serialze and parse a message again.
279     if (this.value == null && other.value != null) {
280       setValue(mergeValueAndBytes(other.value, this.delayedBytes, this.extensionRegistry));
281       return;
282     } else if (this.value != null && other.value == null) {
283       setValue(mergeValueAndBytes(this.value, other.delayedBytes, other.extensionRegistry));
284       return;
285     }
286 
287     // At this point we have two fully parsed messages. We can't merge directly from one to the
288     // other because only generated builder code contains methods to mergeFrom another parsed
289     // message. We have to serialize one instance and then merge the bytes into the other. This may
290     // drop extensions from one of the messages if one of the values had an extension set on it
291     // directly.
292     //
293     // To mitigate this we prefer serializing a message that has an extension registry, and
294     // therefore a chance that all extensions set on it are in that registry.
295     //
296     // NOTE: The check for other.extensionRegistry not being null must come first because at this
297     // point in time if other.extensionRegistry is not null then this.extensionRegistry will not be
298     // null either.
299     if (other.extensionRegistry != null) {
300       setValue(mergeValueAndBytes(this.value, other.toByteString(), other.extensionRegistry));
301       return;
302     } else if (this.extensionRegistry != null) {
303       setValue(mergeValueAndBytes(other.value, this.toByteString(), this.extensionRegistry));
304       return;
305     } else {
306       // All extensions from the other message will be dropped because we have no registry.
307       setValue(mergeValueAndBytes(this.value, other.toByteString(), EMPTY_REGISTRY));
308       return;
309     }
310   }
311 
312   /**
313    * Merges another instance's contents from a stream.
314    *
315    * <p>LazyField is not thread-safe for write access. Synchronizations are needed
316    * under read/write situations.
317    */
mergeFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry)318   public void mergeFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry)
319       throws IOException {
320     if (this.containsDefaultInstance()) {
321       setByteString(input.readBytes(), extensionRegistry);
322       return;
323     }
324 
325     // If the other field has an extension registry but this does not, copy over the other extension
326     // registry.
327     if (this.extensionRegistry == null) {
328       this.extensionRegistry = extensionRegistry;
329     }
330 
331     // In the case that both of them are not parsed we simply concatenate the bytes to save time. In
332     // the (probably rare) case that they have different extension registries there is a chance that
333     // some of the extensions may be dropped, but the tradeoff of making this operation fast seems
334     // to outway the benefits of combining the extension registries, which is not normally done for
335     // lite protos anyways.
336     if (this.delayedBytes != null) {
337       setByteString(this.delayedBytes.concat(input.readBytes()), this.extensionRegistry);
338       return;
339     }
340 
341     // We are parsed and both contain data. We won't drop any extensions here directly, but in the
342     // case that the extension registries are not the same then we might in the future if we
343     // need to serialize and parse a message again.
344     try {
345       setValue(value.toBuilder().mergeFrom(input, extensionRegistry).build());
346     } catch (InvalidProtocolBufferException e) {
347       // Nothing is logged and no exceptions are thrown. Clients will be unaware that a proto
348       // was invalid.
349     }
350   }
351 
mergeValueAndBytes( MessageLite value, ByteString otherBytes, ExtensionRegistryLite extensionRegistry)352   private static MessageLite mergeValueAndBytes(
353       MessageLite value, ByteString otherBytes, ExtensionRegistryLite extensionRegistry) {
354     try {
355       return value.toBuilder().mergeFrom(otherBytes, extensionRegistry).build();
356     } catch (InvalidProtocolBufferException e) {
357       // Nothing is logged and no exceptions are thrown. Clients will be unaware that a proto
358       // was invalid.
359       return value;
360     }
361   }
362 
363   /**
364    * Sets this field with bytes to delay-parse.
365    */
setByteString(ByteString bytes, ExtensionRegistryLite extensionRegistry)366   public void setByteString(ByteString bytes, ExtensionRegistryLite extensionRegistry) {
367     checkArguments(extensionRegistry, bytes);
368     this.delayedBytes = bytes;
369     this.extensionRegistry = extensionRegistry;
370     this.value = null;
371     this.memoizedBytes = null;
372   }
373 
374   /**
375    * Due to the optional field can be duplicated at the end of serialized
376    * bytes, which will make the serialized size changed after LazyField
377    * parsed. Be careful when using this method.
378    */
getSerializedSize()379   public int getSerializedSize() {
380     // We *must* return delayed bytes size if it was ever set because the dependent messages may
381     // have memoized serialized size based off of it.
382     if (memoizedBytes != null) {
383       return memoizedBytes.size();
384     } else if (delayedBytes != null) {
385       return delayedBytes.size();
386     } else if (value != null) {
387       return value.getSerializedSize();
388     } else {
389       return 0;
390     }
391   }
392 
393   /**
394    * Returns a BytesString for this field in a thread-safe way.
395    */
toByteString()396   public ByteString toByteString() {
397     if (memoizedBytes != null) {
398       return memoizedBytes;
399     }
400     // We *must* return delayed bytes if it was set because the dependent messages may have
401     // memoized serialized size based off of it.
402     if (delayedBytes != null) {
403       return delayedBytes;
404     }
405     synchronized (this) {
406       if (memoizedBytes != null) {
407         return memoizedBytes;
408       }
409       if (value == null) {
410         memoizedBytes = ByteString.EMPTY;
411       } else {
412         memoizedBytes = value.toByteString();
413       }
414       return memoizedBytes;
415     }
416   }
417 
418   /**
419    * Might lazily parse the bytes that were previously passed in. Is thread-safe.
420    */
ensureInitialized(MessageLite defaultInstance)421   protected void ensureInitialized(MessageLite defaultInstance) {
422     if (value != null) {
423       return;
424     }
425     synchronized (this) {
426       if (value != null) {
427         return;
428       }
429       try {
430         if (delayedBytes != null) {
431           // The extensionRegistry shouldn't be null here since we have delayedBytes.
432           MessageLite parsedValue = defaultInstance.getParserForType()
433               .parseFrom(delayedBytes, extensionRegistry);
434           this.value = parsedValue;
435           this.memoizedBytes = delayedBytes;
436         } else {
437           this.value = defaultInstance;
438           this.memoizedBytes = ByteString.EMPTY;
439         }
440       } catch (InvalidProtocolBufferException e) {
441         // Nothing is logged and no exceptions are thrown. Clients will be unaware that this proto
442         // was invalid.
443         this.value = defaultInstance;
444         this.memoizedBytes = ByteString.EMPTY;
445       }
446     }
447   }
448 
449 
checkArguments(ExtensionRegistryLite extensionRegistry, ByteString bytes)450   private static void checkArguments(ExtensionRegistryLite extensionRegistry, ByteString bytes) {
451     if (extensionRegistry == null) {
452       throw new NullPointerException("found null ExtensionRegistry");
453     }
454     if (bytes == null) {
455       throw new NullPointerException("found null ByteString");
456     }
457   }
458 }
459