All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.protobuf.DynamicMessage Maven / Gradle / Ivy

There is a newer version: 5.3.3
Show newest version
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// http://code.google.com/p/protobuf/
//
// 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 com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;

import java.io.IOException;
import java.io.InputStream;
import java.util.Map;

/**
 * An implementation of {@link Message} that can represent arbitrary types,
 * given a {@link Descriptors.Descriptor}.
 *
 * @author [email protected] Kenton Varda
 */
public final class DynamicMessage extends AbstractMessage {
    private final Descriptor type;
    private final FieldSet fields;
    private final UnknownFieldSet unknownFields;
    private int memoizedSize = -1;

    /**
     * Construct a {@code DynamicMessage} using the given {@code FieldSet}.
     */
    private DynamicMessage(Descriptor type, FieldSet fields,
                           UnknownFieldSet unknownFields) {
        this.type = type;
        this.fields = fields;
        this.unknownFields = unknownFields;
    }

    /**
     * Get a {@code DynamicMessage} representing the default instance of the
     * given type.
     */
    public static DynamicMessage getDefaultInstance(Descriptor type) {
        return new DynamicMessage(type, FieldSet.emptySet(),
                UnknownFieldSet.getDefaultInstance());
    }

    /**
     * Parse a message of the given type from the given input stream.
     */
    public static DynamicMessage parseFrom(Descriptor type,
                                           CodedInputStream input)
            throws IOException {
        return newBuilder(type).mergeFrom(input).buildParsed();
    }

    /**
     * Parse a message of the given type from the given input stream.
     */
    public static DynamicMessage parseFrom(
            Descriptor type,
            CodedInputStream input,
            ExtensionRegistry extensionRegistry)
            throws IOException {
        return newBuilder(type).mergeFrom(input, extensionRegistry).buildParsed();
    }

    /**
     * Parse {@code data} as a message of the given type and return it.
     */
    public static DynamicMessage parseFrom(Descriptor type, ByteString data)
            throws InvalidProtocolBufferException {
        return newBuilder(type).mergeFrom(data).buildParsed();
    }

    /**
     * Parse {@code data} as a message of the given type and return it.
     */
    public static DynamicMessage parseFrom(Descriptor type, ByteString data,
                                           ExtensionRegistry extensionRegistry)
            throws InvalidProtocolBufferException {
        return newBuilder(type).mergeFrom(data, extensionRegistry).buildParsed();
    }

    /**
     * Parse {@code data} as a message of the given type and return it.
     */
    public static DynamicMessage parseFrom(Descriptor type, byte[] data)
            throws InvalidProtocolBufferException {
        return newBuilder(type).mergeFrom(data).buildParsed();
    }

    /**
     * Parse {@code data} as a message of the given type and return it.
     */
    public static DynamicMessage parseFrom(Descriptor type, byte[] data,
                                           ExtensionRegistry extensionRegistry)
            throws InvalidProtocolBufferException {
        return newBuilder(type).mergeFrom(data, extensionRegistry).buildParsed();
    }

    /**
     * Parse a message of the given type from {@code input} and return it.
     */
    public static DynamicMessage parseFrom(Descriptor type, InputStream input)
            throws IOException {
        return newBuilder(type).mergeFrom(input).buildParsed();
    }

    /**
     * Parse a message of the given type from {@code input} and return it.
     */
    public static DynamicMessage parseFrom(Descriptor type, InputStream input,
                                           ExtensionRegistry extensionRegistry)
            throws IOException {
        return newBuilder(type).mergeFrom(input, extensionRegistry).buildParsed();
    }

    /**
     * Construct a {@link Message.Builder} for the given type.
     */
    public static Builder newBuilder(Descriptor type) {
        return new Builder(type);
    }

    /**
     * Construct a {@link Message.Builder} for a message of the same type as
     * {@code prototype}, and initialize it with {@code prototype}'s contents.
     */
    public static Builder newBuilder(Message prototype) {
        return new Builder(prototype.getDescriptorForType()).mergeFrom(prototype);
    }

    // -----------------------------------------------------------------
    // Implementation of Message interface.

    private static boolean isInitialized(Descriptor type,
                                         FieldSet fields) {
        // Check that all required fields are present.
        for (final FieldDescriptor field : type.getFields()) {
            if (field.isRequired()) {
                if (!fields.hasField(field)) {
                    return false;
                }
            }
        }

        // Check that embedded messages are initialized.
        return fields.isInitialized();
    }

    public Descriptor getDescriptorForType() {
        return type;
    }

    public DynamicMessage getDefaultInstanceForType() {
        return getDefaultInstance(type);
    }

    public Map getAllFields() {
        return fields.getAllFields();
    }

    public boolean hasField(FieldDescriptor field) {
        verifyContainingType(field);
        return fields.hasField(field);
    }

    public Object getField(FieldDescriptor field) {
        verifyContainingType(field);
        Object result = fields.getField(field);
        if (result == null) {
            if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
                result = getDefaultInstance(field.getMessageType());
            } else {
                result = field.getDefaultValue();
            }
        }
        return result;
    }

    public int getRepeatedFieldCount(FieldDescriptor field) {
        verifyContainingType(field);
        return fields.getRepeatedFieldCount(field);
    }

    public Object getRepeatedField(FieldDescriptor field, int index) {
        verifyContainingType(field);
        return fields.getRepeatedField(field, index);
    }

    public UnknownFieldSet getUnknownFields() {
        return unknownFields;
    }

    public boolean isInitialized() {
        return isInitialized(type, fields);
    }

    public void writeTo(CodedOutputStream output) throws IOException {
        if (type.getOptions().getMessageSetWireFormat()) {
            fields.writeMessageSetTo(output);
            unknownFields.writeAsMessageSetTo(output);
        } else {
            fields.writeTo(output);
            unknownFields.writeTo(output);
        }
    }

    public int getSerializedSize() {
        int size = memoizedSize;
        if (size != -1) return size;

        if (type.getOptions().getMessageSetWireFormat()) {
            size = fields.getMessageSetSerializedSize();
            size += unknownFields.getSerializedSizeAsMessageSet();
        } else {
            size = fields.getSerializedSize();
            size += unknownFields.getSerializedSize();
        }

        memoizedSize = size;
        return size;
    }

    public Builder newBuilderForType() {
        return new Builder(type);
    }

    public Builder toBuilder() {
        return newBuilderForType().mergeFrom(this);
    }

    /**
     * Verifies that the field is a field of this message.
     */
    private void verifyContainingType(FieldDescriptor field) {
        if (field.getContainingType() != type) {
            throw new IllegalArgumentException(
                    "FieldDescriptor does not match message type.");
        }
    }

    // =================================================================

    /**
     * Builder for {@link DynamicMessage}s.
     */
    public static final class Builder extends AbstractMessage.Builder {
        private final Descriptor type;
        private FieldSet fields;
        private UnknownFieldSet unknownFields;

        /**
         * Construct a {@code Builder} for the given type.
         */
        private Builder(Descriptor type) {
            this.type = type;
            this.fields = FieldSet.newFieldSet();
            this.unknownFields = UnknownFieldSet.getDefaultInstance();
        }

        // ---------------------------------------------------------------
        // Implementation of Message.Builder interface.

        public Builder clear() {
            if (fields == null) {
                throw new IllegalStateException("Cannot call clear() after build().");
            }
            fields.clear();
            return this;
        }

        public Builder mergeFrom(Message other) {
            if (other instanceof DynamicMessage) {
                // This should be somewhat faster than calling super.mergeFrom().
                DynamicMessage otherDynamicMessage = (DynamicMessage) other;
                if (otherDynamicMessage.type != type) {
                    throw new IllegalArgumentException(
                            "mergeFrom(Message) can only merge messages of the same type.");
                }
                fields.mergeFrom(otherDynamicMessage.fields);
                mergeUnknownFields(otherDynamicMessage.unknownFields);
                return this;
            } else {
                return super.mergeFrom(other);
            }
        }

        public DynamicMessage build() {
            // If fields == null, we'll throw an appropriate exception later.
            if (fields != null && !isInitialized()) {
                throw newUninitializedMessageException(
                        new DynamicMessage(type, fields, unknownFields));
            }
            return buildPartial();
        }

        /**
         * Helper for DynamicMessage.parseFrom() methods to call.  Throws
         * {@link InvalidProtocolBufferException} instead of
         * {@link UninitializedMessageException}.
         */
        private DynamicMessage buildParsed() throws InvalidProtocolBufferException {
            if (!isInitialized()) {
                throw newUninitializedMessageException(
                        new DynamicMessage(type, fields, unknownFields))
                        .asInvalidProtocolBufferException();
            }
            return buildPartial();
        }

        public DynamicMessage buildPartial() {
            if (fields == null) {
                throw new IllegalStateException(
                        "build() has already been called on this Builder.");
            }
            fields.makeImmutable();
            DynamicMessage result =
                    new DynamicMessage(type, fields, unknownFields);
            fields = null;
            unknownFields = null;
            return result;
        }

        public Builder clone() {
            Builder result = new Builder(type);
            result.fields.mergeFrom(fields);
            return result;
        }

        public boolean isInitialized() {
            return DynamicMessage.isInitialized(type, fields);
        }

        public Descriptor getDescriptorForType() {
            return type;
        }

        public DynamicMessage getDefaultInstanceForType() {
            return getDefaultInstance(type);
        }

        public Map getAllFields() {
            return fields.getAllFields();
        }

        public Builder newBuilderForField(FieldDescriptor field) {
            verifyContainingType(field);

            if (field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
                throw new IllegalArgumentException(
                        "newBuilderForField is only valid for fields with message type.");
            }

            return new Builder(field.getMessageType());
        }

        public boolean hasField(FieldDescriptor field) {
            verifyContainingType(field);
            return fields.hasField(field);
        }

        public Object getField(FieldDescriptor field) {
            verifyContainingType(field);
            Object result = fields.getField(field);
            if (result == null) {
                if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
                    result = getDefaultInstance(field.getMessageType());
                } else {
                    result = field.getDefaultValue();
                }
            }
            return result;
        }

        public Builder setField(FieldDescriptor field, Object value) {
            verifyContainingType(field);
            fields.setField(field, value);
            return this;
        }

        public Builder clearField(FieldDescriptor field) {
            verifyContainingType(field);
            fields.clearField(field);
            return this;
        }

        public int getRepeatedFieldCount(FieldDescriptor field) {
            verifyContainingType(field);
            return fields.getRepeatedFieldCount(field);
        }

        public Object getRepeatedField(FieldDescriptor field, int index) {
            verifyContainingType(field);
            return fields.getRepeatedField(field, index);
        }

        public Builder setRepeatedField(FieldDescriptor field,
                                        int index, Object value) {
            verifyContainingType(field);
            fields.setRepeatedField(field, index, value);
            return this;
        }

        public Builder addRepeatedField(FieldDescriptor field, Object value) {
            verifyContainingType(field);
            fields.addRepeatedField(field, value);
            return this;
        }

        public UnknownFieldSet getUnknownFields() {
            return unknownFields;
        }

        public Builder setUnknownFields(UnknownFieldSet unknownFields) {
            this.unknownFields = unknownFields;
            return this;
        }

        public Builder mergeUnknownFields(UnknownFieldSet unknownFields) {
            this.unknownFields =
                    UnknownFieldSet.newBuilder(this.unknownFields)
                            .mergeFrom(unknownFields)
                            .build();
            return this;
        }

        /**
         * Verifies that the field is a field of this message.
         */
        private void verifyContainingType(FieldDescriptor field) {
            if (field.getContainingType() != type) {
                throw new IllegalArgumentException(
                        "FieldDescriptor does not match message type.");
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy