Home | History | Annotate | Download | only in protobuf
      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.FilterInputStream;
     34 import java.io.IOException;
     35 import java.io.InputStream;
     36 import java.io.OutputStream;
     37 import java.util.Collection;
     38 
     39 /**
     40  * A partial implementation of the {@link MessageLite} interface which
     41  * implements as many methods of that interface as possible in terms of other
     42  * methods.
     43  *
     44  * @author kenton (at) google.com Kenton Varda
     45  */
     46 public abstract class AbstractMessageLite<
     47     MessageType extends AbstractMessageLite<MessageType, BuilderType>,
     48     BuilderType extends AbstractMessageLite.Builder<MessageType, BuilderType>>
     49         implements MessageLite {
     50   protected int memoizedHashCode = 0;
     51 
     52   @Override
     53   public ByteString toByteString() {
     54     try {
     55       final ByteString.CodedBuilder out =
     56         ByteString.newCodedBuilder(getSerializedSize());
     57       writeTo(out.getCodedOutput());
     58       return out.build();
     59     } catch (IOException e) {
     60       throw new RuntimeException(
     61         "Serializing to a ByteString threw an IOException (should " +
     62         "never happen).", e);
     63     }
     64   }
     65 
     66   @Override
     67   public byte[] toByteArray() {
     68     try {
     69       final byte[] result = new byte[getSerializedSize()];
     70       final CodedOutputStream output = CodedOutputStream.newInstance(result);
     71       writeTo(output);
     72       output.checkNoSpaceLeft();
     73       return result;
     74     } catch (IOException e) {
     75       throw new RuntimeException(
     76         "Serializing to a byte array threw an IOException " +
     77         "(should never happen).", e);
     78     }
     79   }
     80 
     81   @Override
     82   public void writeTo(final OutputStream output) throws IOException {
     83     final int bufferSize =
     84         CodedOutputStream.computePreferredBufferSize(getSerializedSize());
     85     final CodedOutputStream codedOutput =
     86         CodedOutputStream.newInstance(output, bufferSize);
     87     writeTo(codedOutput);
     88     codedOutput.flush();
     89   }
     90 
     91   @Override
     92   public void writeDelimitedTo(final OutputStream output) throws IOException {
     93     final int serialized = getSerializedSize();
     94     final int bufferSize = CodedOutputStream.computePreferredBufferSize(
     95         CodedOutputStream.computeRawVarint32Size(serialized) + serialized);
     96     final CodedOutputStream codedOutput =
     97         CodedOutputStream.newInstance(output, bufferSize);
     98     codedOutput.writeRawVarint32(serialized);
     99     writeTo(codedOutput);
    100     codedOutput.flush();
    101   }
    102 
    103 
    104   /**
    105    * Package private helper method for AbstractParser to create
    106    * UninitializedMessageException.
    107    */
    108   UninitializedMessageException newUninitializedMessageException() {
    109     return new UninitializedMessageException(this);
    110   }
    111 
    112   protected static void checkByteStringIsUtf8(ByteString byteString)
    113       throws IllegalArgumentException {
    114     if (!byteString.isValidUtf8()) {
    115       throw new IllegalArgumentException("Byte string is not UTF-8.");
    116     }
    117   }
    118 
    119   protected static <T> void addAll(final Iterable<T> values,
    120       final Collection<? super T> list) {
    121     Builder.addAll(values, list);
    122   }
    123 
    124   /**
    125    * A partial implementation of the {@link Message.Builder} interface which
    126    * implements as many methods of that interface as possible in terms of
    127    * other methods.
    128    */
    129   @SuppressWarnings("unchecked")
    130   public abstract static class Builder<
    131       MessageType extends AbstractMessageLite<MessageType, BuilderType>,
    132       BuilderType extends Builder<MessageType, BuilderType>>
    133       implements MessageLite.Builder {
    134     // The compiler produces an error if this is not declared explicitly.
    135     @Override
    136     public abstract BuilderType clone();
    137 
    138     @Override
    139     public BuilderType mergeFrom(final CodedInputStream input) throws IOException {
    140       return mergeFrom(input, ExtensionRegistryLite.getEmptyRegistry());
    141     }
    142 
    143     // Re-defined here for return type covariance.
    144     @Override
    145     public abstract BuilderType mergeFrom(
    146         final CodedInputStream input, final ExtensionRegistryLite extensionRegistry)
    147         throws IOException;
    148 
    149     @Override
    150     public BuilderType mergeFrom(final ByteString data) throws InvalidProtocolBufferException {
    151       try {
    152         final CodedInputStream input = data.newCodedInput();
    153         mergeFrom(input);
    154         input.checkLastTagWas(0);
    155         return (BuilderType) this;
    156       } catch (InvalidProtocolBufferException e) {
    157         throw e;
    158       } catch (IOException e) {
    159         throw new RuntimeException(
    160           "Reading from a ByteString threw an IOException (should " +
    161           "never happen).", e);
    162       }
    163     }
    164 
    165     @Override
    166     public BuilderType mergeFrom(
    167         final ByteString data, final ExtensionRegistryLite extensionRegistry)
    168         throws InvalidProtocolBufferException {
    169       try {
    170         final CodedInputStream input = data.newCodedInput();
    171         mergeFrom(input, extensionRegistry);
    172         input.checkLastTagWas(0);
    173         return (BuilderType) this;
    174       } catch (InvalidProtocolBufferException e) {
    175         throw e;
    176       } catch (IOException e) {
    177         throw new RuntimeException(
    178           "Reading from a ByteString threw an IOException (should " +
    179           "never happen).", e);
    180       }
    181     }
    182 
    183     @Override
    184     public BuilderType mergeFrom(final byte[] data) throws InvalidProtocolBufferException {
    185       return mergeFrom(data, 0, data.length);
    186     }
    187 
    188     @Override
    189     public BuilderType mergeFrom(final byte[] data, final int off, final int len)
    190         throws InvalidProtocolBufferException {
    191       try {
    192         final CodedInputStream input =
    193             CodedInputStream.newInstance(data, off, len);
    194         mergeFrom(input);
    195         input.checkLastTagWas(0);
    196         return (BuilderType) this;
    197       } catch (InvalidProtocolBufferException e) {
    198         throw e;
    199       } catch (IOException e) {
    200         throw new RuntimeException(
    201           "Reading from a byte array threw an IOException (should " +
    202           "never happen).", e);
    203       }
    204     }
    205 
    206     @Override
    207     public BuilderType mergeFrom(final byte[] data, final ExtensionRegistryLite extensionRegistry)
    208         throws InvalidProtocolBufferException {
    209       return mergeFrom(data, 0, data.length, extensionRegistry);
    210     }
    211 
    212     @Override
    213     public BuilderType mergeFrom(
    214         final byte[] data,
    215         final int off,
    216         final int len,
    217         final ExtensionRegistryLite extensionRegistry)
    218         throws InvalidProtocolBufferException {
    219       try {
    220         final CodedInputStream input =
    221             CodedInputStream.newInstance(data, off, len);
    222         mergeFrom(input, extensionRegistry);
    223         input.checkLastTagWas(0);
    224         return (BuilderType) this;
    225       } catch (InvalidProtocolBufferException e) {
    226         throw e;
    227       } catch (IOException e) {
    228         throw new RuntimeException(
    229           "Reading from a byte array threw an IOException (should " +
    230           "never happen).", e);
    231       }
    232     }
    233 
    234     @Override
    235     public BuilderType mergeFrom(final InputStream input) throws IOException {
    236       final CodedInputStream codedInput = CodedInputStream.newInstance(input);
    237       mergeFrom(codedInput);
    238       codedInput.checkLastTagWas(0);
    239       return (BuilderType) this;
    240     }
    241 
    242     @Override
    243     public BuilderType mergeFrom(
    244         final InputStream input, final ExtensionRegistryLite extensionRegistry) throws IOException {
    245       final CodedInputStream codedInput = CodedInputStream.newInstance(input);
    246       mergeFrom(codedInput, extensionRegistry);
    247       codedInput.checkLastTagWas(0);
    248       return (BuilderType) this;
    249     }
    250 
    251     /**
    252      * An InputStream implementations which reads from some other InputStream
    253      * but is limited to a particular number of bytes.  Used by
    254      * mergeDelimitedFrom().  This is intentionally package-private so that
    255      * UnknownFieldSet can share it.
    256      */
    257     static final class LimitedInputStream extends FilterInputStream {
    258       private int limit;
    259 
    260       LimitedInputStream(InputStream in, int limit) {
    261         super(in);
    262         this.limit = limit;
    263       }
    264 
    265       @Override
    266       public int available() throws IOException {
    267         return Math.min(super.available(), limit);
    268       }
    269 
    270       @Override
    271       public int read() throws IOException {
    272         if (limit <= 0) {
    273           return -1;
    274         }
    275         final int result = super.read();
    276         if (result >= 0) {
    277           --limit;
    278         }
    279         return result;
    280       }
    281 
    282       @Override
    283       public int read(final byte[] b, final int off, int len)
    284                       throws IOException {
    285         if (limit <= 0) {
    286           return -1;
    287         }
    288         len = Math.min(len, limit);
    289         final int result = super.read(b, off, len);
    290         if (result >= 0) {
    291           limit -= result;
    292         }
    293         return result;
    294       }
    295 
    296       @Override
    297       public long skip(final long n) throws IOException {
    298         final long result = super.skip(Math.min(n, limit));
    299         if (result >= 0) {
    300           limit -= result;
    301         }
    302         return result;
    303       }
    304     }
    305 
    306     @Override
    307     public boolean mergeDelimitedFrom(
    308         final InputStream input, final ExtensionRegistryLite extensionRegistry) throws IOException {
    309       final int firstByte = input.read();
    310       if (firstByte == -1) {
    311         return false;
    312       }
    313       final int size = CodedInputStream.readRawVarint32(firstByte, input);
    314       final InputStream limitedInput = new LimitedInputStream(input, size);
    315       mergeFrom(limitedInput, extensionRegistry);
    316       return true;
    317     }
    318 
    319     @Override
    320     public boolean mergeDelimitedFrom(final InputStream input) throws IOException {
    321       return mergeDelimitedFrom(input,
    322           ExtensionRegistryLite.getEmptyRegistry());
    323     }
    324 
    325     @Override
    326     @SuppressWarnings("unchecked") // isInstance takes care of this
    327     public BuilderType mergeFrom(final MessageLite other) {
    328       if (!getDefaultInstanceForType().getClass().isInstance(other)) {
    329         throw new IllegalArgumentException(
    330             "mergeFrom(MessageLite) can only merge messages of the same type.");
    331       }
    332 
    333       return internalMergeFrom((MessageType) other);
    334     }
    335 
    336     protected abstract BuilderType internalMergeFrom(MessageType message);
    337 
    338     /**
    339      * Construct an UninitializedMessageException reporting missing fields in
    340      * the given message.
    341      */
    342     protected static UninitializedMessageException
    343         newUninitializedMessageException(MessageLite message) {
    344       return new UninitializedMessageException(message);
    345     }
    346 
    347     /**
    348      * Adds the {@code values} to the {@code list}.  This is a helper method
    349      * used by generated code.  Users should ignore it.
    350      *
    351      * @throws NullPointerException if {@code values} or any of the elements of
    352      * {@code values} is null. When that happens, some elements of
    353      * {@code values} may have already been added to the result {@code list}.
    354      */
    355     protected static <T> void addAll(final Iterable<T> values,
    356                                      final Collection<? super T> list) {
    357       if (values == null) {
    358         throw new NullPointerException();
    359       }
    360       if (values instanceof LazyStringList) {
    361         // For StringOrByteStringLists, check the underlying elements to avoid
    362         // forcing conversions of ByteStrings to Strings.
    363         checkForNullValues(((LazyStringList) values).getUnderlyingElements());
    364         list.addAll((Collection<T>) values);
    365       } else if (values instanceof Collection) {
    366         checkForNullValues(values);
    367         list.addAll((Collection<T>) values);
    368       } else {
    369         for (final T value : values) {
    370           if (value == null) {
    371             throw new NullPointerException();
    372           }
    373           list.add(value);
    374         }
    375       }
    376     }
    377 
    378     private static void checkForNullValues(final Iterable<?> values) {
    379       for (final Object value : values) {
    380         if (value == null) {
    381           throw new NullPointerException();
    382         }
    383       }
    384     }
    385   }
    386 }
    387