AbstractMessageLite.java revision d0332953cda33fb4f8e24ebff9c49159b69c43d6
1// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc.  All rights reserved.
3// http://code.google.com/p/protobuf/
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
31package com.google.protobuf;
32
33import java.io.FilterInputStream;
34import java.io.InputStream;
35import java.io.IOException;
36import java.io.OutputStream;
37import 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@google.com Kenton Varda
45 */
46public abstract class AbstractMessageLite implements MessageLite {
47  public ByteString toByteString() {
48    try {
49      final ByteString.CodedBuilder out =
50        ByteString.newCodedBuilder(getSerializedSize());
51      writeTo(out.getCodedOutput());
52      return out.build();
53    } catch (IOException e) {
54      throw new RuntimeException(
55        "Serializing to a ByteString threw an IOException (should " +
56        "never happen).", e);
57    }
58  }
59
60  public byte[] toByteArray() {
61    try {
62      final byte[] result = new byte[getSerializedSize()];
63      final CodedOutputStream output = CodedOutputStream.newInstance(result);
64      writeTo(output);
65      output.checkNoSpaceLeft();
66      return result;
67    } catch (IOException e) {
68      throw new RuntimeException(
69        "Serializing to a byte array threw an IOException " +
70        "(should never happen).", e);
71    }
72  }
73
74  public void writeTo(final OutputStream output) throws IOException {
75    final int bufferSize =
76        CodedOutputStream.computePreferredBufferSize(getSerializedSize());
77    final CodedOutputStream codedOutput =
78        CodedOutputStream.newInstance(output, bufferSize);
79    writeTo(codedOutput);
80    codedOutput.flush();
81  }
82
83  public void writeDelimitedTo(final OutputStream output) throws IOException {
84    final int serialized = getSerializedSize();
85    final int bufferSize = CodedOutputStream.computePreferredBufferSize(
86        CodedOutputStream.computeRawVarint32Size(serialized) + serialized);
87    final CodedOutputStream codedOutput =
88        CodedOutputStream.newInstance(output, bufferSize);
89    codedOutput.writeRawVarint32(serialized);
90    writeTo(codedOutput);
91    codedOutput.flush();
92  }
93
94  /**
95   * A partial implementation of the {@link Message.Builder} interface which
96   * implements as many methods of that interface as possible in terms of
97   * other methods.
98   */
99  @SuppressWarnings("unchecked")
100  public static abstract class Builder<BuilderType extends Builder>
101      implements MessageLite.Builder {
102    // The compiler produces an error if this is not declared explicitly.
103    @Override
104    public abstract BuilderType clone();
105
106    public BuilderType mergeFrom(final CodedInputStream input)
107                                 throws IOException {
108      return mergeFrom(input, ExtensionRegistryLite.getEmptyRegistry());
109    }
110
111    // Re-defined here for return type covariance.
112    public abstract BuilderType mergeFrom(
113        final CodedInputStream input,
114        final ExtensionRegistryLite extensionRegistry)
115        throws IOException;
116
117    public BuilderType mergeFrom(final ByteString data)
118        throws InvalidProtocolBufferException {
119      try {
120        final CodedInputStream input = data.newCodedInput();
121        mergeFrom(input);
122        input.checkLastTagWas(0);
123        return (BuilderType) this;
124      } catch (InvalidProtocolBufferException e) {
125        throw e;
126      } catch (IOException e) {
127        throw new RuntimeException(
128          "Reading from a ByteString threw an IOException (should " +
129          "never happen).", e);
130      }
131    }
132
133    public BuilderType mergeFrom(
134        final ByteString data,
135        final ExtensionRegistryLite extensionRegistry)
136        throws InvalidProtocolBufferException {
137      try {
138        final CodedInputStream input = data.newCodedInput();
139        mergeFrom(input, extensionRegistry);
140        input.checkLastTagWas(0);
141        return (BuilderType) this;
142      } catch (InvalidProtocolBufferException e) {
143        throw e;
144      } catch (IOException e) {
145        throw new RuntimeException(
146          "Reading from a ByteString threw an IOException (should " +
147          "never happen).", e);
148      }
149    }
150
151    public BuilderType mergeFrom(final byte[] data)
152        throws InvalidProtocolBufferException {
153      return mergeFrom(data, 0, data.length);
154    }
155
156    public BuilderType mergeFrom(final byte[] data, final int off,
157                                 final int len)
158                                 throws InvalidProtocolBufferException {
159      try {
160        final CodedInputStream input =
161            CodedInputStream.newInstance(data, off, len);
162        mergeFrom(input);
163        input.checkLastTagWas(0);
164        return (BuilderType) this;
165      } catch (InvalidProtocolBufferException e) {
166        throw e;
167      } catch (IOException e) {
168        throw new RuntimeException(
169          "Reading from a byte array threw an IOException (should " +
170          "never happen).", e);
171      }
172    }
173
174    public BuilderType mergeFrom(
175        final byte[] data,
176        final ExtensionRegistryLite extensionRegistry)
177        throws InvalidProtocolBufferException {
178      return mergeFrom(data, 0, data.length, extensionRegistry);
179    }
180
181    public BuilderType mergeFrom(
182        final byte[] data, final int off, final int len,
183        final ExtensionRegistryLite extensionRegistry)
184        throws InvalidProtocolBufferException {
185      try {
186        final CodedInputStream input =
187            CodedInputStream.newInstance(data, off, len);
188        mergeFrom(input, extensionRegistry);
189        input.checkLastTagWas(0);
190        return (BuilderType) this;
191      } catch (InvalidProtocolBufferException e) {
192        throw e;
193      } catch (IOException e) {
194        throw new RuntimeException(
195          "Reading from a byte array threw an IOException (should " +
196          "never happen).", e);
197      }
198    }
199
200    public BuilderType mergeFrom(final InputStream input) throws IOException {
201      final CodedInputStream codedInput = CodedInputStream.newInstance(input);
202      mergeFrom(codedInput);
203      codedInput.checkLastTagWas(0);
204      return (BuilderType) this;
205    }
206
207    public BuilderType mergeFrom(
208        final InputStream input,
209        final ExtensionRegistryLite extensionRegistry)
210        throws IOException {
211      final CodedInputStream codedInput = CodedInputStream.newInstance(input);
212      mergeFrom(codedInput, extensionRegistry);
213      codedInput.checkLastTagWas(0);
214      return (BuilderType) this;
215    }
216
217    /**
218     * An InputStream implementations which reads from some other InputStream
219     * but is limited to a particular number of bytes.  Used by
220     * mergeDelimitedFrom().  This is intentionally package-private so that
221     * UnknownFieldSet can share it.
222     */
223    static final class LimitedInputStream extends FilterInputStream {
224      private int limit;
225
226      LimitedInputStream(InputStream in, int limit) {
227        super(in);
228        this.limit = limit;
229      }
230
231      @Override
232      public int available() throws IOException {
233        return Math.min(super.available(), limit);
234      }
235
236      @Override
237      public int read() throws IOException {
238        if (limit <= 0) {
239          return -1;
240        }
241        final int result = super.read();
242        if (result >= 0) {
243          --limit;
244        }
245        return result;
246      }
247
248      @Override
249      public int read(final byte[] b, final int off, int len)
250                      throws IOException {
251        if (limit <= 0) {
252          return -1;
253        }
254        len = Math.min(len, limit);
255        final int result = super.read(b, off, len);
256        if (result >= 0) {
257          limit -= result;
258        }
259        return result;
260      }
261
262      @Override
263      public long skip(final long n) throws IOException {
264        final long result = super.skip(Math.min(n, limit));
265        if (result >= 0) {
266          limit -= result;
267        }
268        return result;
269      }
270    }
271
272    public boolean mergeDelimitedFrom(
273        final InputStream input,
274        final ExtensionRegistryLite extensionRegistry)
275        throws IOException {
276      final int firstByte = input.read();
277      if (firstByte == -1) {
278        return false;
279      }
280      final int size = CodedInputStream.readRawVarint32(firstByte, input);
281      final InputStream limitedInput = new LimitedInputStream(input, size);
282      mergeFrom(limitedInput, extensionRegistry);
283      return true;
284    }
285
286    public boolean mergeDelimitedFrom(final InputStream input)
287        throws IOException {
288      return mergeDelimitedFrom(input,
289          ExtensionRegistryLite.getEmptyRegistry());
290    }
291
292    /**
293     * Construct an UninitializedMessageException reporting missing fields in
294     * the given message.
295     */
296    protected static UninitializedMessageException
297        newUninitializedMessageException(MessageLite message) {
298      return new UninitializedMessageException(message);
299    }
300
301    /**
302     * Adds the {@code values} to the {@code list}.  This is a helper method
303     * used by generated code.  Users should ignore it.
304     *
305     * @throws NullPointerException if any of the elements of {@code values} is
306     * null.
307     */
308    protected static <T> void addAll(final Iterable<T> values,
309                                     final Collection<? super T> list) {
310      for (final T value : values) {
311        if (value == null) {
312          throw new NullPointerException();
313        }
314      }
315      if (values instanceof Collection) {
316        @SuppressWarnings("unsafe") final
317        Collection<T> collection = (Collection<T>) values;
318        list.addAll(collection);
319      } else {
320        for (final T value : values) {
321          list.add(value);
322        }
323      }
324    }
325  }
326}
327