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