aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Makefile.am1
-rw-r--r--csharp/src/Google.Protobuf.Test/JsonParserTest.cs44
-rw-r--r--csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs4
-rw-r--r--csharp/src/Google.Protobuf/Google.Protobuf.csproj1
-rw-r--r--csharp/src/Google.Protobuf/InvalidJsonException.cs53
-rw-r--r--csharp/src/Google.Protobuf/JsonParser.cs4
-rw-r--r--csharp/src/Google.Protobuf/JsonTokenizer.cs42
-rw-r--r--csharp/src/Google.Protobuf/MessageParser.cs2
8 files changed, 111 insertions, 40 deletions
diff --git a/Makefile.am b/Makefile.am
index 7db38f05..0a26fa1b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -119,6 +119,7 @@ csharp_EXTRA_DIST= \
csharp/src/Google.Protobuf/Google.Protobuf.nuspec \
csharp/src/Google.Protobuf/IDeepCloneable.cs \
csharp/src/Google.Protobuf/IMessage.cs \
+ csharp/src/Google.Protobuf/InvalidJsonException.cs \
csharp/src/Google.Protobuf/InvalidProtocolBufferException.cs \
csharp/src/Google.Protobuf/JsonFormatter.cs \
csharp/src/Google.Protobuf/JsonParser.cs \
diff --git a/csharp/src/Google.Protobuf.Test/JsonParserTest.cs b/csharp/src/Google.Protobuf.Test/JsonParserTest.cs
index b1c7b46c..29b3088c 100644
--- a/csharp/src/Google.Protobuf.Test/JsonParserTest.cs
+++ b/csharp/src/Google.Protobuf.Test/JsonParserTest.cs
@@ -370,19 +370,19 @@ namespace Google.Protobuf
}
[Test]
- [TestCase("+0")]
- [TestCase("00")]
- [TestCase("-00")]
- [TestCase("--1")]
- [TestCase("+1")]
- [TestCase("1.5", Ignore = true, Reason = "Desired behaviour unclear")]
- [TestCase("1e10")]
- [TestCase("2147483648")]
- [TestCase("-2147483649")]
- public void NumberToInt32_Invalid(string jsonValue)
+ [TestCase("+0", typeof(InvalidJsonException))]
+ [TestCase("00", typeof(InvalidJsonException))]
+ [TestCase("-00", typeof(InvalidJsonException))]
+ [TestCase("--1", typeof(InvalidJsonException))]
+ [TestCase("+1", typeof(InvalidJsonException))]
+ [TestCase("1.5", typeof(InvalidProtocolBufferException), Ignore = true, Reason = "Desired behaviour unclear")]
+ [TestCase("1e10", typeof(InvalidProtocolBufferException))]
+ [TestCase("2147483648", typeof(InvalidProtocolBufferException))]
+ [TestCase("-2147483649", typeof(InvalidProtocolBufferException))]
+ public void NumberToInt32_Invalid(string jsonValue, System.Type expectedExceptionType)
{
string json = "{ \"singleInt32\": " + jsonValue + "}";
- Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
+ Assert.Throws(expectedExceptionType, () => TestAllTypes.Parser.ParseJson(json));
}
[Test]
@@ -486,7 +486,7 @@ namespace Google.Protobuf
public void NumberToDouble_Invalid(string jsonValue)
{
string json = "{ \"singleDouble\": " + jsonValue + "}";
- Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
+ Assert.Throws<InvalidJsonException>(() => TestAllTypes.Parser.ParseJson(json));
}
[Test]
@@ -506,17 +506,17 @@ namespace Google.Protobuf
}
[Test]
- [TestCase("3.402824e38")]
- [TestCase("-3.402824e38")]
- [TestCase("1,0")]
- [TestCase("1.0.0")]
- [TestCase("+1")]
- [TestCase("00")]
- [TestCase("--1")]
- public void NumberToFloat_Invalid(string jsonValue)
+ [TestCase("3.402824e38", typeof(InvalidProtocolBufferException))]
+ [TestCase("-3.402824e38", typeof(InvalidProtocolBufferException))]
+ [TestCase("1,0", typeof(InvalidJsonException))]
+ [TestCase("1.0.0", typeof(InvalidJsonException))]
+ [TestCase("+1", typeof(InvalidJsonException))]
+ [TestCase("00", typeof(InvalidJsonException))]
+ [TestCase("--1", typeof(InvalidJsonException))]
+ public void NumberToFloat_Invalid(string jsonValue, System.Type expectedExceptionType)
{
string json = "{ \"singleFloat\": " + jsonValue + "}";
- Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
+ Assert.Throws(expectedExceptionType, () => TestAllTypes.Parser.ParseJson(json));
}
// The simplest way of testing that the value has parsed correctly is to reformat it,
@@ -721,7 +721,7 @@ namespace Google.Protobuf
public void DataAfterObject()
{
string json = "{} 10";
- Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
+ Assert.Throws<InvalidJsonException>(() => TestAllTypes.Parser.ParseJson(json));
}
}
}
diff --git a/csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs b/csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs
index 868d9f75..1b3c8e9f 100644
--- a/csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs
+++ b/csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs
@@ -223,7 +223,7 @@ namespace Google.Protobuf
{
Assert.IsNotNull(tokenizer.Next());
}
- Assert.Throws<InvalidProtocolBufferException>(() => tokenizer.Next());
+ Assert.Throws<InvalidJsonException>(() => tokenizer.Next());
}
[Test]
@@ -346,7 +346,7 @@ namespace Google.Protobuf
}
Assert.AreEqual(expectedTokens[i], actualToken);
}
- Assert.Throws<InvalidProtocolBufferException>(() => tokenizer.Next());
+ Assert.Throws<InvalidJsonException>(() => tokenizer.Next());
}
}
}
diff --git a/csharp/src/Google.Protobuf/Google.Protobuf.csproj b/csharp/src/Google.Protobuf/Google.Protobuf.csproj
index 00399438..24fe7746 100644
--- a/csharp/src/Google.Protobuf/Google.Protobuf.csproj
+++ b/csharp/src/Google.Protobuf/Google.Protobuf.csproj
@@ -84,6 +84,7 @@
<Compile Include="FieldCodec.cs" />
<Compile Include="FrameworkPortability.cs" />
<Compile Include="IDeepCloneable.cs" />
+ <Compile Include="InvalidJsonException.cs" />
<Compile Include="JsonFormatter.cs" />
<Compile Include="JsonParser.cs" />
<Compile Include="JsonToken.cs" />
diff --git a/csharp/src/Google.Protobuf/InvalidJsonException.cs b/csharp/src/Google.Protobuf/InvalidJsonException.cs
new file mode 100644
index 00000000..b5434201
--- /dev/null
+++ b/csharp/src/Google.Protobuf/InvalidJsonException.cs
@@ -0,0 +1,53 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System.IO;
+
+namespace Google.Protobuf
+{
+ /// <summary>
+ /// Thrown when an attempt is made to parse invalid JSON, e.g. using
+ /// a non-string property key, or including a redundant comma. Parsing a protocol buffer
+ /// message represented in JSON using <see cref="JsonParser"/> can throw both this
+ /// exception and <see cref="InvalidProtocolBufferException"/> depending on the situation. This
+ /// exception is only thrown for "pure JSON" errors, whereas <c>InvalidProtocolBufferException</c>
+ /// is thrown when the JSON may be valid in and of itself, but cannot be parsed as a protocol buffer
+ /// message.
+ /// </summary>
+ public sealed class InvalidJsonException : IOException
+ {
+ internal InvalidJsonException(string message)
+ : base(message)
+ {
+ }
+ }
+} \ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/JsonParser.cs b/csharp/src/Google.Protobuf/JsonParser.cs
index 6d2638d9..8da57745 100644
--- a/csharp/src/Google.Protobuf/JsonParser.cs
+++ b/csharp/src/Google.Protobuf/JsonParser.cs
@@ -337,6 +337,8 @@ namespace Google.Protobuf
/// </summary>
/// <typeparam name="T">The type of message to create.</typeparam>
/// <param name="json">The JSON to parse.</param>
+ /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
+ /// <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception>
public T Parse<T>(string json) where T : IMessage, new()
{
return Parse<T>(new StringReader(json));
@@ -347,6 +349,8 @@ namespace Google.Protobuf
/// </summary>
/// <typeparam name="T">The type of message to create.</typeparam>
/// <param name="jsonReader">Reader providing the JSON to parse.</param>
+ /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
+ /// <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception>
public T Parse<T>(TextReader jsonReader) where T : IMessage, new()
{
T message = new T();
diff --git a/csharp/src/Google.Protobuf/JsonTokenizer.cs b/csharp/src/Google.Protobuf/JsonTokenizer.cs
index 108ccebe..5ed1e449 100644
--- a/csharp/src/Google.Protobuf/JsonTokenizer.cs
+++ b/csharp/src/Google.Protobuf/JsonTokenizer.cs
@@ -88,6 +88,7 @@ namespace Google.Protobuf
/// </remarks>
/// <returns>The next token in the stream. This is never null.</returns>
/// <exception cref="InvalidOperationException">This method is called after an EndDocument token has been returned</exception>
+ /// <exception cref="InvalidJsonException">The input text does not comply with RFC 7159</exception>
internal JsonToken Next()
{
if (bufferedToken != null)
@@ -182,7 +183,7 @@ namespace Google.Protobuf
ValidateAndModifyStateForValue("Invalid state to read a number token: ");
return JsonToken.Value(number);
default:
- throw new InvalidProtocolBufferException("Invalid first character of token: " + next.Value);
+ throw new InvalidJsonException("Invalid first character of token: " + next.Value);
}
}
}
@@ -191,7 +192,7 @@ namespace Google.Protobuf
{
if ((validStates & state) == 0)
{
- throw new InvalidProtocolBufferException(errorPrefix + state);
+ throw reader.CreateException(errorPrefix + state);
}
}
@@ -207,13 +208,13 @@ namespace Google.Protobuf
char c = reader.ReadOrFail("Unexpected end of text while reading string");
if (c < ' ')
{
- throw new InvalidProtocolBufferException(string.Format(CultureInfo.InvariantCulture, "Invalid character in string literal: U+{0:x4}", (int) c));
+ throw reader.CreateException(string.Format(CultureInfo.InvariantCulture, "Invalid character in string literal: U+{0:x4}", (int) c));
}
if (c == '"')
{
if (haveHighSurrogate)
{
- throw new InvalidProtocolBufferException("Invalid use of surrogate pair code units");
+ throw reader.CreateException("Invalid use of surrogate pair code units");
}
return value.ToString();
}
@@ -226,7 +227,7 @@ namespace Google.Protobuf
// followed by an escaped low surrogate or vice versa... and that couldn't even be represented in UTF-8.
if (haveHighSurrogate != char.IsLowSurrogate(c))
{
- throw new InvalidProtocolBufferException("Invalid use of surrogate pair code units");
+ throw reader.CreateException("Invalid use of surrogate pair code units");
}
haveHighSurrogate = char.IsHighSurrogate(c);
value.Append(c);
@@ -260,7 +261,7 @@ namespace Google.Protobuf
case 'u':
return ReadUnicodeEscape();
default:
- throw new InvalidProtocolBufferException(string.Format(CultureInfo.InvariantCulture, "Invalid character in character escape sequence: U+{0:x4}", (int) c));
+ throw reader.CreateException(string.Format(CultureInfo.InvariantCulture, "Invalid character in character escape sequence: U+{0:x4}", (int) c));
}
}
@@ -288,7 +289,7 @@ namespace Google.Protobuf
}
else
{
- throw new InvalidProtocolBufferException(string.Format(CultureInfo.InvariantCulture, "Invalid character in character escape sequence: U+{0:x4}", (int) c));
+ throw reader.CreateException(string.Format(CultureInfo.InvariantCulture, "Invalid character in character escape sequence: U+{0:x4}", (int) c));
}
result = (result << 4) + nybble;
}
@@ -306,11 +307,11 @@ namespace Google.Protobuf
char? next = reader.Read();
if (next == null)
{
- throw new InvalidProtocolBufferException("Unexpected end of text while reading literal token " + text);
+ throw reader.CreateException("Unexpected end of text while reading literal token " + text);
}
if (next.Value != text[i])
{
- throw new InvalidProtocolBufferException("Unexpected character while reading literal token " + text);
+ throw reader.CreateException("Unexpected character while reading literal token " + text);
}
}
}
@@ -354,7 +355,7 @@ namespace Google.Protobuf
}
catch (OverflowException)
{
- throw new InvalidProtocolBufferException("Numeric value out of range: " + builder);
+ throw reader.CreateException("Numeric value out of range: " + builder);
}
}
@@ -363,14 +364,14 @@ namespace Google.Protobuf
char first = reader.ReadOrFail("Invalid numeric literal");
if (first < '0' || first > '9')
{
- throw new InvalidProtocolBufferException("Invalid numeric literal");
+ throw reader.CreateException("Invalid numeric literal");
}
builder.Append(first);
int digitCount;
char? next = ConsumeDigits(builder, out digitCount);
if (first == '0' && digitCount != 0)
{
- throw new InvalidProtocolBufferException("Invalid numeric literal: leading 0 for non-zero value.");
+ throw reader.CreateException("Invalid numeric literal: leading 0 for non-zero value.");
}
return next;
}
@@ -382,7 +383,7 @@ namespace Google.Protobuf
char? next = ConsumeDigits(builder, out digitCount);
if (digitCount == 0)
{
- throw new InvalidProtocolBufferException("Invalid numeric literal: fraction with no trailing digits");
+ throw reader.CreateException("Invalid numeric literal: fraction with no trailing digits");
}
return next;
}
@@ -393,7 +394,7 @@ namespace Google.Protobuf
char? next = reader.Read();
if (next == null)
{
- throw new InvalidProtocolBufferException("Invalid numeric literal: exponent with no trailing digits");
+ throw reader.CreateException("Invalid numeric literal: exponent with no trailing digits");
}
if (next == '-' || next == '+')
{
@@ -407,7 +408,7 @@ namespace Google.Protobuf
next = ConsumeDigits(builder, out digitCount);
if (digitCount == 0)
{
- throw new InvalidProtocolBufferException("Invalid numeric literal: exponent without value");
+ throw reader.CreateException("Invalid numeric literal: exponent without value");
}
return next;
}
@@ -615,7 +616,7 @@ namespace Google.Protobuf
char? next = Read();
if (next == null)
{
- throw new InvalidProtocolBufferException(messageOnFailure);
+ throw CreateException(messageOnFailure);
}
return next.Value;
}
@@ -628,6 +629,15 @@ namespace Google.Protobuf
}
nextChar = c;
}
+
+ /// <summary>
+ /// Creates a new exception appropriate for the current state of the reader.
+ /// </summary>
+ internal InvalidJsonException CreateException(string message)
+ {
+ // TODO: Keep track of and use the location.
+ return new InvalidJsonException(message);
+ }
}
}
}
diff --git a/csharp/src/Google.Protobuf/MessageParser.cs b/csharp/src/Google.Protobuf/MessageParser.cs
index 70c52ba6..8f2717c5 100644
--- a/csharp/src/Google.Protobuf/MessageParser.cs
+++ b/csharp/src/Google.Protobuf/MessageParser.cs
@@ -148,6 +148,8 @@ namespace Google.Protobuf
/// </summary>
/// <param name="json">The JSON to parse.</param>
/// <returns>The parsed message.</returns>
+ /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
+ /// <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception>
public T ParseJson(string json)
{
T message = factory();