| // 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) |
| */ |
| 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(). |
| * |
| * 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 {@code extensionRegistry} is required to also be non-null. |
| * {@code value} and {@code memoizedBytes} will be initialized lazily. |
| */ |
| private ByteString delayedBytes; |
| |
| /** |
| * 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 |
| * {@code delayedBytes} will be parsed lazily at that time. |
| */ |
| protected volatile MessageLite value; |
| |
| /** |
| * 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. |
| */ |
| 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. |
| */ |
| 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. |
| */ |
| 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. |
| */ |
| public boolean containsDefaultInstance() { |
| return memoizedBytes == ByteString.EMPTY |
| || value == null && (delayedBytes == null || delayedBytes == ByteString.EMPTY); |
| } |
| |
| /** |
| * 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. |
| * |
| * <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. |
| * |
| * @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. |
| * |
| * <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 {@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. We can't merge directly from one to the |
| // other because only generated builder code contains methods to mergeFrom another parsed |
| // message. We have to serialize one instance and then merge the bytes into the other. This may |
| // drop extensions from one of the messages if one of the values had an extension set on it |
| // directly. |
| // |
| // To mitigate this we prefer serializing a message that has an extension registry, and |
| // therefore a chance that all extensions set on it are in that registry. |
| // |
| // NOTE: The check for other.extensionRegistry not being null must come first because at this |
| // point in time if other.extensionRegistry is not null then this.extensionRegistry will not be |
| // null either. |
| if (other.extensionRegistry != null) { |
| setValue(mergeValueAndBytes(this.value, other.toByteString(), other.extensionRegistry)); |
| return; |
| } else if (this.extensionRegistry != null) { |
| setValue(mergeValueAndBytes(other.value, this.toByteString(), this.extensionRegistry)); |
| return; |
| } else { |
| // All extensions from the other message will be dropped because we have no registry. |
| setValue(mergeValueAndBytes(this.value, other.toByteString(), EMPTY_REGISTRY)); |
| return; |
| } |
| } |
| |
| /** |
| * 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. |
| */ |
| 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. |
| */ |
| 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. |
| */ |
| 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; |
| } |
| } |
| |
| /** |
| * 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"); |
| } |
| } |
| } |