From f3c75580e4e7b18c372e1f83e4283701c01bcaca Mon Sep 17 00:00:00 2001 From: Joshua Humphries Date: Tue, 20 Oct 2015 16:24:48 -0400 Subject: throw IOException instead of InvalidProtocolBufferException when appropriate --- .../java/com/google/protobuf/GeneratedMessage.java | 60 ++++++++++++++++++++-- .../protobuf/InvalidProtocolBufferException.java | 12 +++++ .../src/main/java/com/google/protobuf/Parser.java | 12 +++++ 3 files changed, 80 insertions(+), 4 deletions(-) (limited to 'java/core') diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java index d84fa75c..ceb97a4e 100644 --- a/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java +++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java @@ -36,15 +36,13 @@ import com.google.protobuf.Descriptors.EnumValueDescriptor; import com.google.protobuf.Descriptors.FieldDescriptor; import com.google.protobuf.Descriptors.FileDescriptor; import com.google.protobuf.Descriptors.OneofDescriptor; -import com.google.protobuf.GeneratedMessageLite.ExtendableMessage; -import com.google.protobuf.GeneratedMessageLite.GeneratedExtension; import java.io.IOException; +import java.io.InputStream; import java.io.ObjectStreamException; import java.io.Serializable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; @@ -276,6 +274,60 @@ public abstract class GeneratedMessage extends AbstractMessage return unknownFields.mergeFieldFrom(tag, input); } + protected static M parseWithIOException(Parser parser, InputStream input) + throws IOException { + try { + return parser.parseFrom(input); + } catch (InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } + } + + protected static M parseWithIOException(Parser parser, InputStream input, + ExtensionRegistryLite extensions) throws IOException { + try { + return parser.parseFrom(input, extensions); + } catch (InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } + } + + protected static M parseWithIOException(Parser parser, + CodedInputStream input) throws IOException { + try { + return parser.parseFrom(input); + } catch (InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } + } + + protected static M parseWithIOException(Parser parser, + CodedInputStream input, ExtensionRegistryLite extensions) throws IOException { + try { + return parser.parseFrom(input, extensions); + } catch (InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } + } + + protected static M parseDelimitedWithIOException(Parser parser, + InputStream input) throws IOException { + try { + return parser.parseDelimitedFrom(input); + } catch (InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } + } + + protected static M parseDelimitedWithIOException(Parser parser, + InputStream input, ExtensionRegistryLite extensions) throws IOException { + try { + return parser.parseDelimitedFrom(input, extensions); + } catch (InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } + } + @Override public void writeTo(final CodedOutputStream output) throws IOException { MessageReflection.writeMessageTo(this, getAllFieldsRaw(), output, false); @@ -667,7 +719,7 @@ public abstract class GeneratedMessage extends AbstractMessage "No map fields found in " + getClass().getName()); } - /** Like {@link internalGetMapField} but return a mutable version. */ + /** Like {@link #internalGetMapField} but return a mutable version. */ @SuppressWarnings({"unused", "rawtypes"}) protected MapField internalGetMutableMapField(int fieldNumber) { // Note that we can't use descriptor names here because this method will diff --git a/java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java b/java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java index 0a761052..85ce7b24 100644 --- a/java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java +++ b/java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java @@ -46,6 +46,10 @@ public class InvalidProtocolBufferException extends IOException { super(description); } + public InvalidProtocolBufferException(IOException e) { + super(e.getMessage(), e); + } + /** * Attaches an unfinished message to the exception to support best-effort * parsing in {@code Parser} interface. @@ -66,6 +70,14 @@ public class InvalidProtocolBufferException extends IOException { return unfinishedMessage; } + /** + * Unwraps the underlying {@link IOException} if this exception was caused by an I/O + * problem. Otherwise, returns {@code this}. + */ + public IOException unwrapIOException() { + return getCause() instanceof IOException ? (IOException) getCause() : this; + } + static InvalidProtocolBufferException truncatedMessage() { return new InvalidProtocolBufferException( "While parsing a protocol message, the input ended unexpectedly " + diff --git a/java/core/src/main/java/com/google/protobuf/Parser.java b/java/core/src/main/java/com/google/protobuf/Parser.java index 227c02b7..3fa11c3b 100644 --- a/java/core/src/main/java/com/google/protobuf/Parser.java +++ b/java/core/src/main/java/com/google/protobuf/Parser.java @@ -30,6 +30,7 @@ package com.google.protobuf; +import java.io.IOException; import java.io.InputStream; /** @@ -37,9 +38,20 @@ import java.io.InputStream; * * The implementation should be stateless and thread-safe. * + *

All methods may throw {@link InvalidProtocolBufferException}. In the event of invalid data, + * like an encoding error, the cause of the thrown exception will be {@code null}. However, if an + * I/O problem occurs, an exception is thrown with an {@link IOException} cause. + * * @author liujisi@google.com (Pherl Liu) */ public interface Parser { + + // NB(jh): Other parts of the protobuf API that parse messages distinguish between an I/O problem + // (like failure reading bytes from a socket) and invalid data (encoding error) via the type of + // thrown exception. But it would be source-incompatible to make the methods in this interface do + // so since they were originally spec'ed to only throw InvalidProtocolBufferException. So callers + // must inspect the cause of the exception to distinguish these two cases. + /** * Parses a message of {@code MessageType} from the input. * -- cgit v1.2.3