|
|
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.
// http://code.google.com/p/protobuf/
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using Google.ProtocolBuffers.Collections;
using Google.ProtocolBuffers.Descriptors;
namespace Google.ProtocolBuffers {
public class UninitializedMessageException : Exception {
private readonly IList<string> missingFields;
public UninitializedMessageException(IMessage message)
: this(FindMissingFields(message)) {
}
private UninitializedMessageException(IList<string> missingFields)
: base(BuildDescription(missingFields)) {
this.missingFields = Lists.AsReadOnly(missingFields);
}
/// <summary>
/// Converts this exception into an InvalidProtocolBufferException.
/// When a parsed message is missing required fields, this should be thrown
/// instead of UninitializedMessageException.
/// </summary>
public InvalidProtocolBufferException AsInvalidProtocolBufferException() {
return new InvalidProtocolBufferException(Message);
}
/// <summary>
/// Constructs the description string for a given list of missing fields.
/// </summary>
private static string BuildDescription(IEnumerable<string> missingFields) {
StringBuilder description = new StringBuilder("Message missing required fields: ");
bool first = true;
foreach(string field in missingFields) {
if (first) {
first = false;
} else {
description.Append(", ");
}
description.Append(field);
}
return description.ToString();
}
/// <summary>
/// Returns a list of the full "paths" of missing required
/// fields in the specified message.
/// </summary>
private static IList<String> FindMissingFields(IMessage message) {
List<String> results = new List<String>();
FindMissingFields(message, "", results);
return results;
}
/// <summary>
/// Recursive helper implementing FindMissingFields.
/// </summary>
private static void FindMissingFields(IMessage message, String prefix, List<String> results) {
foreach (FieldDescriptor field in message.DescriptorForType.Fields) {
if (field.IsRequired && !message.HasField(field)) {
results.Add(prefix + field.Name);
}
}
foreach (KeyValuePair<FieldDescriptor, object> entry in message.AllFields) {
FieldDescriptor field = entry.Key;
object value = entry.Value;
if (field.MappedType == MappedType.Message) {
if (field.IsRepeated) {
int i = 0;
foreach (object element in (IEnumerable) value) {
FindMissingFields((IMessage) element, SubMessagePrefix(prefix, field, i++), results);
}
} else {
if (message.HasField(field)) {
FindMissingFields((IMessage) value, SubMessagePrefix(prefix, field, -1), results);
}
}
}
}
}
private static String SubMessagePrefix(String prefix, FieldDescriptor field, int index) {
StringBuilder result = new StringBuilder(prefix);
if (field.IsExtension) {
result.Append('(')
.Append(field.FullName)
.Append(')');
} else {
result.Append(field.Name);
}
if (index != -1) {
result.Append('[')
.Append(index)
.Append(']');
}
result.Append('.');
return result.ToString();
}
}
}
|