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