Home | History | Annotate | Download | only in nano
      1 // Protocol Buffers - Google's data interchange format
      2 // Copyright 2013 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.nano;
     32 
     33 import java.io.IOException;
     34 import java.util.Arrays;
     35 
     36 /**
     37  * Abstract interface implemented by Protocol Message objects.
     38  *
     39  * @author wink (at) google.com Wink Saville
     40  */
     41 public abstract class MessageNano {
     42     protected volatile int cachedSize = -1;
     43 
     44     /**
     45      * Get the number of bytes required to encode this message.
     46      * Returns the cached size or calls getSerializedSize which
     47      * sets the cached size. This is used internally when serializing
     48      * so the size is only computed once. If a member is modified
     49      * then this could be stale call getSerializedSize if in doubt.
     50      */
     51     public int getCachedSize() {
     52         if (cachedSize < 0) {
     53             // getSerializedSize sets cachedSize
     54             getSerializedSize();
     55         }
     56         return cachedSize;
     57     }
     58 
     59     /**
     60      * Computes the number of bytes required to encode this message.
     61      * The size is cached and the cached result can be retrieved
     62      * using getCachedSize().
     63      */
     64     public int getSerializedSize() {
     65         int size = computeSerializedSize();
     66         cachedSize = size;
     67         return size;
     68     }
     69 
     70     /**
     71      * Computes the number of bytes required to encode this message. This does not update the
     72      * cached size.
     73      */
     74     protected int computeSerializedSize() {
     75       // This is overridden if the generated message has serialized fields.
     76       return 0;
     77     }
     78 
     79     /**
     80      * Serializes the message and writes it to {@code output}.
     81      *
     82      * @param output the output to receive the serialized form.
     83      * @throws IOException if an error occurred writing to {@code output}.
     84      */
     85     public void writeTo(CodedOutputByteBufferNano output) throws IOException {
     86         // Does nothing by default. Overridden by subclasses which have data to write.
     87     }
     88 
     89     /**
     90      * Parse {@code input} as a message of this type and merge it with the
     91      * message being built.
     92      */
     93     public abstract MessageNano mergeFrom(CodedInputByteBufferNano input) throws IOException;
     94 
     95     /**
     96      * Serialize to a byte array.
     97      * @return byte array with the serialized data.
     98      */
     99     public static final byte[] toByteArray(MessageNano msg) {
    100         final byte[] result = new byte[msg.getSerializedSize()];
    101         toByteArray(msg, result, 0, result.length);
    102         return result;
    103     }
    104 
    105     /**
    106      * Serialize to a byte array starting at offset through length. The
    107      * method getSerializedSize must have been called prior to calling
    108      * this method so the proper length is know.  If an attempt to
    109      * write more than length bytes OutOfSpaceException will be thrown
    110      * and if length bytes are not written then IllegalStateException
    111      * is thrown.
    112      */
    113     public static final void toByteArray(MessageNano msg, byte[] data, int offset, int length) {
    114         try {
    115             final CodedOutputByteBufferNano output =
    116                 CodedOutputByteBufferNano.newInstance(data, offset, length);
    117             msg.writeTo(output);
    118             output.checkNoSpaceLeft();
    119         } catch (IOException e) {
    120             throw new RuntimeException("Serializing to a byte array threw an IOException "
    121                     + "(should never happen).", e);
    122         }
    123     }
    124 
    125     /**
    126      * Parse {@code data} as a message of this type and merge it with the
    127      * message being built.
    128      */
    129     public static final <T extends MessageNano> T mergeFrom(T msg, final byte[] data)
    130         throws InvalidProtocolBufferNanoException {
    131         return mergeFrom(msg, data, 0, data.length);
    132     }
    133 
    134     /**
    135      * Parse {@code data} as a message of this type and merge it with the
    136      * message being built.
    137      */
    138     public static final <T extends MessageNano> T mergeFrom(T msg, final byte[] data,
    139             final int off, final int len) throws InvalidProtocolBufferNanoException {
    140         try {
    141             final CodedInputByteBufferNano input =
    142                 CodedInputByteBufferNano.newInstance(data, off, len);
    143             msg.mergeFrom(input);
    144             input.checkLastTagWas(0);
    145             return msg;
    146         } catch (InvalidProtocolBufferNanoException e) {
    147             throw e;
    148         } catch (IOException e) {
    149             throw new RuntimeException("Reading from a byte array threw an IOException (should "
    150                     + "never happen).");
    151         }
    152     }
    153 
    154     /**
    155      * Compares two {@code MessageNano}s and returns true if the message's are the same class and
    156      * have serialized form equality (i.e. all of the field values are the same).
    157      */
    158     public static final boolean messageNanoEquals(MessageNano a, MessageNano b) {
    159         if (a == b) {
    160             return true;
    161         }
    162         if (a == null || b == null) {
    163             return false;
    164         }
    165         if (a.getClass() != b.getClass()) {
    166           return false;
    167         }
    168         final int serializedSize = a.getSerializedSize();
    169         if (b.getSerializedSize() != serializedSize) {
    170             return false;
    171         }
    172         final byte[] aByteArray = new byte[serializedSize];
    173         final byte[] bByteArray = new byte[serializedSize];
    174         toByteArray(a, aByteArray, 0, serializedSize);
    175         toByteArray(b, bByteArray, 0, serializedSize);
    176         return Arrays.equals(aByteArray, bByteArray);
    177     }
    178 
    179     /**
    180      * Returns a string that is (mostly) compatible with ProtoBuffer's TextFormat. Note that groups
    181      * (which are deprecated) are not serialized with the correct field name.
    182      *
    183      * <p>This is implemented using reflection, so it is not especially fast nor is it guaranteed
    184      * to find all fields if you have method removal turned on for proguard.
    185      */
    186     @Override
    187     public String toString() {
    188         return MessageNanoPrinter.print(this);
    189     }
    190 
    191     /**
    192      * Provides support for cloning. This only works if you specify the generate_clone method.
    193      */
    194     @Override
    195     public MessageNano clone() throws CloneNotSupportedException {
    196         return (MessageNano) super.clone();
    197     }
    198 }
    199