|
@@ -56,17 +56,19 @@ namespace Google.Protobuf
|
|
public sealed class JsonFormatter
|
|
public sealed class JsonFormatter
|
|
{
|
|
{
|
|
internal const string AnyTypeUrlField = "@type";
|
|
internal const string AnyTypeUrlField = "@type";
|
|
|
|
+ internal const string AnyDiagnosticValueField = "@value";
|
|
internal const string AnyWellKnownTypeValueField = "value";
|
|
internal const string AnyWellKnownTypeValueField = "value";
|
|
private const string TypeUrlPrefix = "type.googleapis.com";
|
|
private const string TypeUrlPrefix = "type.googleapis.com";
|
|
private const string NameValueSeparator = ": ";
|
|
private const string NameValueSeparator = ": ";
|
|
private const string PropertySeparator = ", ";
|
|
private const string PropertySeparator = ", ";
|
|
|
|
|
|
- private static JsonFormatter defaultInstance = new JsonFormatter(Settings.Default);
|
|
|
|
-
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Returns a formatter using the default settings.
|
|
/// Returns a formatter using the default settings.
|
|
/// </summary>
|
|
/// </summary>
|
|
- public static JsonFormatter Default { get { return defaultInstance; } }
|
|
|
|
|
|
+ public static JsonFormatter Default { get; } = new JsonFormatter(Settings.Default);
|
|
|
|
+
|
|
|
|
+ // A JSON formatter which *only* exists
|
|
|
|
+ private static readonly JsonFormatter diagnosticFormatter = new JsonFormatter(Settings.Default);
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
/// The JSON representation of the first 160 characters of Unicode.
|
|
/// The JSON representation of the first 160 characters of Unicode.
|
|
@@ -149,6 +151,29 @@ namespace Google.Protobuf
|
|
return builder.ToString();
|
|
return builder.ToString();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// Converts a message to JSON for diagnostic purposes with no extra context.
|
|
|
|
+ /// </summary>
|
|
|
|
+ /// <remarks>
|
|
|
|
+ /// <para>
|
|
|
|
+ /// This differs from calling <see cref="Format(IMessage)"/> on the default JSON
|
|
|
|
+ /// formatter in its handling of <see cref="Any"/>. As no type registry is available
|
|
|
|
+ /// in <see cref="object.ToString"/> calls, the normal way of resolving the type of
|
|
|
|
+ /// an <c>Any</c> message cannot be applied. Instead, a JSON property named <c>@value</c>
|
|
|
|
+ /// is included with the base64 data from the <see cref="Any.Value"/> property of the message.
|
|
|
|
+ /// </para>
|
|
|
|
+ /// <para>The value returned by this method is only designed to be used for diagnostic
|
|
|
|
+ /// purposes. It may not be parsable by <see cref="JsonParser"/>, and may not be parsable
|
|
|
|
+ /// by other Protocol Buffer implementations.</para>
|
|
|
|
+ /// </remarks>
|
|
|
|
+ /// <param name="message">The message to format for diagnostic purposes.</param>
|
|
|
|
+ /// <returns>The diagnostic-only JSON representation of the message</returns>
|
|
|
|
+ public static string ToDiagnosticString(IMessage message)
|
|
|
|
+ {
|
|
|
|
+ Preconditions.CheckNotNull(message, nameof(message));
|
|
|
|
+ return diagnosticFormatter.Format(message);
|
|
|
|
+ }
|
|
|
|
+
|
|
private void WriteMessage(StringBuilder builder, IMessage message)
|
|
private void WriteMessage(StringBuilder builder, IMessage message)
|
|
{
|
|
{
|
|
if (message == null)
|
|
if (message == null)
|
|
@@ -516,6 +541,12 @@ namespace Google.Protobuf
|
|
|
|
|
|
private void WriteAny(StringBuilder builder, IMessage value)
|
|
private void WriteAny(StringBuilder builder, IMessage value)
|
|
{
|
|
{
|
|
|
|
+ if (ReferenceEquals(this, diagnosticFormatter))
|
|
|
|
+ {
|
|
|
|
+ WriteDiagnosticOnlyAny(builder, value);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
string typeUrl = (string) value.Descriptor.Fields[Any.TypeUrlFieldNumber].Accessor.GetValue(value);
|
|
string typeUrl = (string) value.Descriptor.Fields[Any.TypeUrlFieldNumber].Accessor.GetValue(value);
|
|
ByteString data = (ByteString) value.Descriptor.Fields[Any.ValueFieldNumber].Accessor.GetValue(value);
|
|
ByteString data = (ByteString) value.Descriptor.Fields[Any.ValueFieldNumber].Accessor.GetValue(value);
|
|
string typeName = GetTypeName(typeUrl);
|
|
string typeName = GetTypeName(typeUrl);
|
|
@@ -544,6 +575,23 @@ namespace Google.Protobuf
|
|
builder.Append(" }");
|
|
builder.Append(" }");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ private void WriteDiagnosticOnlyAny(StringBuilder builder, IMessage value)
|
|
|
|
+ {
|
|
|
|
+ string typeUrl = (string) value.Descriptor.Fields[Any.TypeUrlFieldNumber].Accessor.GetValue(value);
|
|
|
|
+ ByteString data = (ByteString) value.Descriptor.Fields[Any.ValueFieldNumber].Accessor.GetValue(value);
|
|
|
|
+ builder.Append("{ ");
|
|
|
|
+ WriteString(builder, AnyTypeUrlField);
|
|
|
|
+ builder.Append(NameValueSeparator);
|
|
|
|
+ WriteString(builder, typeUrl);
|
|
|
|
+ builder.Append(PropertySeparator);
|
|
|
|
+ WriteString(builder, AnyDiagnosticValueField);
|
|
|
|
+ builder.Append(NameValueSeparator);
|
|
|
|
+ builder.Append('"');
|
|
|
|
+ builder.Append(data.ToBase64());
|
|
|
|
+ builder.Append('"');
|
|
|
|
+ builder.Append(" }");
|
|
|
|
+ }
|
|
|
|
+
|
|
internal static string GetTypeName(String typeUrl)
|
|
internal static string GetTypeName(String typeUrl)
|
|
{
|
|
{
|
|
string[] parts = typeUrl.Split('/');
|
|
string[] parts = typeUrl.Split('/');
|