// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package com.google.protobuf;

import java.io.IOException;

LazyFieldLite encapsulates the logic of lazily parsing message fields. It stores the message in a ByteString initially and then parses it on-demand.

LazyFieldLite is thread-compatible: concurrent reads are safe once the proto that this LazyFieldLite is a part of is no longer being mutated by its Builder. However, explicit synchronization is needed under read/write situations.

When a LazyFieldLite is used in the context of a MessageLite object, its behavior is considered to be immutable and none of the setter methods in its API are expected to be invoked. All of the getters are expected to be thread-safe. When used in the context of a MessageLite.Builder, setters can be invoked, but there is no guarantee of thread safety.

TODO(yatin,dweis): Consider splitting this class's functionality and put the mutable methods into a separate builder class to allow us to give stronger compile-time guarantees.

This class is internal implementation detail of the protobuf library, so you don't need to use it directly.

Author:xiangl@google.com (Xiang Li)
/** * LazyFieldLite encapsulates the logic of lazily parsing message fields. It stores the message in a * ByteString initially and then parses it on-demand. * * <p>LazyFieldLite is thread-compatible: concurrent reads are safe once the proto that this * LazyFieldLite is a part of is no longer being mutated by its Builder. However, explicit * synchronization is needed under read/write situations. * * <p>When a LazyFieldLite is used in the context of a MessageLite object, its behavior is * considered to be immutable and none of the setter methods in its API are expected to be invoked. * All of the getters are expected to be thread-safe. When used in the context of a * MessageLite.Builder, setters can be invoked, but there is no guarantee of thread safety. * * <p>TODO(yatin,dweis): Consider splitting this class's functionality and put the mutable methods * into a separate builder class to allow us to give stronger compile-time guarantees. * * <p>This class is internal implementation detail of the protobuf library, so you don't need to use * it directly. * * @author xiangl@google.com (Xiang Li) */
public class LazyFieldLite { private static final ExtensionRegistryLite EMPTY_REGISTRY = ExtensionRegistryLite.getEmptyRegistry(); /* * The value associated with the LazyFieldLite object is stored in one or more of the following * three fields (delayedBytes, value, memoizedBytes). They should together be interpreted as * follows. * * 1) delayedBytes can be non-null, while value and memoizedBytes is null. The object will be in * this state while the value for the object has not yet been parsed. * * 2) Both delayedBytes and value are non-null. The object transitions to this state as soon as * some caller needs to access the value (by invoking getValue()). * * 3) memoizedBytes is merely an optimization for calls to LazyFieldLite.toByteString() to avoid * recomputing the ByteString representation on each call. Instead, when the value is parsed from * delayedBytes, we will also assign the contents of delayedBytes to memoizedBytes (since that is * the ByteString representation of value). * * 4) Finally, if the LazyFieldLite was created directly with a parsed MessageLite value, then * delayedBytes will be null, and memoizedBytes will be initialized only upon the first call to * LazyFieldLite.toByteString(). * * <p>Given the above conditions, any caller that needs a serialized representation of this object * must first check if the memoizedBytes or delayedBytes ByteString is non-null and use it * directly; if both of those are null, it can look at the parsed value field. Similarly, any * caller that needs a parsed value must first check if the value field is already non-null, if * not it must parse the value from delayedBytes. */
A delayed-parsed version of the contents of this field. When this field is non-null, then the "value" field is allowed to be null until the time that the value needs to be read.

When delayedBytes is non-null then extensionRegistry is required to also be non-null. value and memoizedBytes will be initialized lazily.

/** * A delayed-parsed version of the contents of this field. When this field is non-null, then the * "value" field is allowed to be null until the time that the value needs to be read. * * <p>When delayedBytes is non-null then {@code extensionRegistry} is required to also be * non-null. {@code value} and {@code memoizedBytes} will be initialized lazily. */
private ByteString delayedBytes;
An ExtensionRegistryLite for parsing bytes. It is non-null on a best-effort basis. It is only guaranteed to be non-null if this message was initialized using bytes and an ExtensionRegistry. If it directly had a value set then it will be null, unless it has been merged with another LazyFieldLite that had an ExtensionRegistry.
/** * An {@code ExtensionRegistryLite} for parsing bytes. It is non-null on a best-effort basis. It * is only guaranteed to be non-null if this message was initialized using bytes and an {@code * ExtensionRegistry}. If it directly had a value set then it will be null, unless it has been * merged with another {@code LazyFieldLite} that had an {@code ExtensionRegistry}. */
private ExtensionRegistryLite extensionRegistry;
The parsed value. When this is null and a caller needs access to the MessageLite value, then delayedBytes will be parsed lazily at that time.
/** * The parsed value. When this is null and a caller needs access to the MessageLite value, then * {@code delayedBytes} will be parsed lazily at that time. */
protected volatile MessageLite value;
The memoized bytes for value. This is an optimization for the toByteString() method to not have to recompute its return-value on each invocation. TODO(yatin): Figure out whether this optimization is actually necessary.
/** * The memoized bytes for {@code value}. This is an optimization for the toByteString() method to * not have to recompute its return-value on each invocation. TODO(yatin): Figure out whether this * optimization is actually necessary. */
private volatile ByteString memoizedBytes;
Constructs a LazyFieldLite with bytes that will be parsed lazily.
/** Constructs a LazyFieldLite with bytes that will be parsed lazily. */
public LazyFieldLite(ExtensionRegistryLite extensionRegistry, ByteString bytes) { checkArguments(extensionRegistry, bytes); this.extensionRegistry = extensionRegistry; this.delayedBytes = bytes; }
Constructs a LazyFieldLite with no contents, and no ability to parse extensions.
/** Constructs a LazyFieldLite with no contents, and no ability to parse extensions. */
public LazyFieldLite() {}
Constructs a LazyFieldLite instance with a value. The LazyFieldLite may not be able to parse the extensions in the value as it has no ExtensionRegistry.
/** * Constructs a LazyFieldLite instance with a value. The LazyFieldLite may not be able to parse * the extensions in the value as it has no ExtensionRegistry. */
public static LazyFieldLite fromValue(MessageLite value) { LazyFieldLite lf = new LazyFieldLite(); lf.setValue(value); return lf; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof LazyFieldLite)) { return false; } LazyFieldLite other = (LazyFieldLite) o; // Lazy fields do not work well with equals... If both are delayedBytes, we do not have a // mechanism to deserialize them so we rely on bytes equality. Otherwise we coerce into an // actual message (if necessary) and call equals on the message itself. This implies that two // messages can by unequal but then be turned equal simply be invoking a getter on a lazy field. MessageLite value1 = value; MessageLite value2 = other.value; if (value1 == null && value2 == null) { return toByteString().equals(other.toByteString()); } else if (value1 != null && value2 != null) { return value1.equals(value2); } else if (value1 != null) { return value1.equals(other.getValue(value1.getDefaultInstanceForType())); } else { return getValue(value2.getDefaultInstanceForType()).equals(value2); } } @Override public int hashCode() { // We can't provide a memoizable hash code for lazy fields. The byte strings may have different // hash codes but evaluate to equivalent messages. And we have no facility for constructing // a message here if we were not already holding a value. return 1; }
Determines whether this LazyFieldLite instance represents the default instance of this type.
/** * Determines whether this LazyFieldLite instance represents the default instance of this type. */
public boolean containsDefaultInstance() { return memoizedBytes == ByteString.EMPTY || value == null && (delayedBytes == null || delayedBytes == ByteString.EMPTY); }
Clears the value state of this instance.

LazyField is not thread-safe for write access. Synchronizations are needed under read/write situations.

/** * Clears the value state of this instance. * * <p>LazyField is not thread-safe for write access. Synchronizations are needed under read/write * situations. */
public void clear() { // Don't clear the ExtensionRegistry. It might prove useful later on when merging in another // value, but there is no guarantee that it will contain all extensions that were directly set // on the values that need to be merged. delayedBytes = null; value = null; memoizedBytes = null; }
Overrides the contents of this LazyField.

LazyField is not thread-safe for write access. Synchronizations are needed under read/write situations.

/** * Overrides the contents of this LazyField. * * <p>LazyField is not thread-safe for write access. Synchronizations are needed under read/write * situations. */
public void set(LazyFieldLite other) { this.delayedBytes = other.delayedBytes; this.value = other.value; this.memoizedBytes = other.memoizedBytes; // If the other LazyFieldLite was created by directly setting the value rather than first by // parsing, then it will not have an extensionRegistry. In this case we hold on to the existing // extensionRegistry, which has no guarantees that it has all the extensions that will be // directly set on the value. if (other.extensionRegistry != null) { this.extensionRegistry = other.extensionRegistry; } }
Returns message instance. It may do some thread-safe delayed parsing of bytes.
Params:
  • defaultInstance – its message's default instance. It's also used to get parser for the message type.
/** * Returns message instance. It may do some thread-safe delayed parsing of bytes. * * @param defaultInstance its message's default instance. It's also used to get parser for the * message type. */
public MessageLite getValue(MessageLite defaultInstance) { ensureInitialized(defaultInstance); return value; }
Sets the value of the instance and returns the old value without delay parsing anything.

LazyField is not thread-safe for write access. Synchronizations are needed under read/write situations.

/** * Sets the value of the instance and returns the old value without delay parsing anything. * * <p>LazyField is not thread-safe for write access. Synchronizations are needed under read/write * situations. */
public MessageLite setValue(MessageLite value) { MessageLite originalValue = this.value; this.delayedBytes = null; this.memoizedBytes = null; this.value = value; return originalValue; }
Merges another instance's contents. In some cases may drop some extensions if both fields contain data. If the other field has an ExtensionRegistry but this does not, then this field will copy over that ExtensionRegistry.

LazyField is not thread-safe for write access. Synchronizations are needed under read/write situations.

/** * Merges another instance's contents. In some cases may drop some extensions if both fields * contain data. If the other field has an {@code ExtensionRegistry} but this does not, then this * field will copy over that {@code ExtensionRegistry}. * * <p>LazyField is not thread-safe for write access. Synchronizations are needed under read/write * situations. */
public void merge(LazyFieldLite other) { if (other.containsDefaultInstance()) { return; } if (this.containsDefaultInstance()) { set(other); return; } // If the other field has an extension registry but this does not, copy over the other extension // registry. if (this.extensionRegistry == null) { this.extensionRegistry = other.extensionRegistry; } // In the case that both of them are not parsed we simply concatenate the bytes to save time. In // the (probably rare) case that they have different extension registries there is a chance that // some of the extensions may be dropped, but the tradeoff of making this operation fast seems // to outway the benefits of combining the extension registries, which is not normally done for // lite protos anyways. if (this.delayedBytes != null && other.delayedBytes != null) { this.delayedBytes = this.delayedBytes.concat(other.delayedBytes); return; } // At least one is parsed and both contain data. We won't drop any extensions here directly, but // in the case that the extension registries are not the same then we might in the future if we // need to serialze and parse a message again. if (this.value == null && other.value != null) { setValue(mergeValueAndBytes(other.value, this.delayedBytes, this.extensionRegistry)); return; } else if (this.value != null && other.value == null) { setValue(mergeValueAndBytes(this.value, other.delayedBytes, other.extensionRegistry)); return; } // At this point we have two fully parsed messages. setValue(this.value.toBuilder().mergeFrom(other.value).build()); }
Merges another instance's contents from a stream.

LazyField is not thread-safe for write access. Synchronizations are needed under read/write situations.

/** * Merges another instance's contents from a stream. * * <p>LazyField is not thread-safe for write access. Synchronizations are needed under read/write * situations. */
public void mergeFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry) throws IOException { if (this.containsDefaultInstance()) { setByteString(input.readBytes(), extensionRegistry); return; } // If the other field has an extension registry but this does not, copy over the other extension // registry. if (this.extensionRegistry == null) { this.extensionRegistry = extensionRegistry; } // In the case that both of them are not parsed we simply concatenate the bytes to save time. In // the (probably rare) case that they have different extension registries there is a chance that // some of the extensions may be dropped, but the tradeoff of making this operation fast seems // to outway the benefits of combining the extension registries, which is not normally done for // lite protos anyways. if (this.delayedBytes != null) { setByteString(this.delayedBytes.concat(input.readBytes()), this.extensionRegistry); return; } // We are parsed and both contain data. We won't drop any extensions here directly, but in the // case that the extension registries are not the same then we might in the future if we // need to serialize and parse a message again. try { setValue(value.toBuilder().mergeFrom(input, extensionRegistry).build()); } catch (InvalidProtocolBufferException e) { // Nothing is logged and no exceptions are thrown. Clients will be unaware that a proto // was invalid. } } private static MessageLite mergeValueAndBytes( MessageLite value, ByteString otherBytes, ExtensionRegistryLite extensionRegistry) { try { return value.toBuilder().mergeFrom(otherBytes, extensionRegistry).build(); } catch (InvalidProtocolBufferException e) { // Nothing is logged and no exceptions are thrown. Clients will be unaware that a proto // was invalid. return value; } }
Sets this field with bytes to delay-parse.
/** Sets this field with bytes to delay-parse. */
public void setByteString(ByteString bytes, ExtensionRegistryLite extensionRegistry) { checkArguments(extensionRegistry, bytes); this.delayedBytes = bytes; this.extensionRegistry = extensionRegistry; this.value = null; this.memoizedBytes = null; }
Due to the optional field can be duplicated at the end of serialized bytes, which will make the serialized size changed after LazyField parsed. Be careful when using this method.
/** * Due to the optional field can be duplicated at the end of serialized bytes, which will make the * serialized size changed after LazyField parsed. Be careful when using this method. */
public int getSerializedSize() { // We *must* return delayed bytes size if it was ever set because the dependent messages may // have memoized serialized size based off of it. if (memoizedBytes != null) { return memoizedBytes.size(); } else if (delayedBytes != null) { return delayedBytes.size(); } else if (value != null) { return value.getSerializedSize(); } else { return 0; } }
Returns a BytesString for this field in a thread-safe way.
/** Returns a BytesString for this field in a thread-safe way. */
public ByteString toByteString() { if (memoizedBytes != null) { return memoizedBytes; } // We *must* return delayed bytes if it was set because the dependent messages may have // memoized serialized size based off of it. if (delayedBytes != null) { return delayedBytes; } synchronized (this) { if (memoizedBytes != null) { return memoizedBytes; } if (value == null) { memoizedBytes = ByteString.EMPTY; } else { memoizedBytes = value.toByteString(); } return memoizedBytes; } }
Writes this lazy field into a Writer.
/** Writes this lazy field into a {@link Writer}. */
void writeTo(Writer writer, int fieldNumber) throws IOException { if (memoizedBytes != null) { writer.writeBytes(fieldNumber, memoizedBytes); } else if (delayedBytes != null) { writer.writeBytes(fieldNumber, delayedBytes); } else if (value != null) { writer.writeMessage(fieldNumber, value); } else { writer.writeBytes(fieldNumber, ByteString.EMPTY); } }
Might lazily parse the bytes that were previously passed in. Is thread-safe.
/** Might lazily parse the bytes that were previously passed in. Is thread-safe. */
protected void ensureInitialized(MessageLite defaultInstance) { if (value != null) { return; } synchronized (this) { if (value != null) { return; } try { if (delayedBytes != null) { // The extensionRegistry shouldn't be null here since we have delayedBytes. MessageLite parsedValue = defaultInstance.getParserForType().parseFrom(delayedBytes, extensionRegistry); this.value = parsedValue; this.memoizedBytes = delayedBytes; } else { this.value = defaultInstance; this.memoizedBytes = ByteString.EMPTY; } } catch (InvalidProtocolBufferException e) { // Nothing is logged and no exceptions are thrown. Clients will be unaware that this proto // was invalid. this.value = defaultInstance; this.memoizedBytes = ByteString.EMPTY; } } } private static void checkArguments(ExtensionRegistryLite extensionRegistry, ByteString bytes) { if (extensionRegistry == null) { throw new NullPointerException("found null ExtensionRegistry"); } if (bytes == null) { throw new NullPointerException("found null ByteString"); } } }