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