blob: b0d601bd78f67d046343348c5a719bc7d6a82aec [file] [log] [blame]
Jon Skeet68036862008-10-22 13:30:34 +01001// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc.
3// http://code.google.com/p/protobuf/
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16using System;
17using System.Collections;
18using System.Collections.Generic;
19using System.Text;
20using Google.ProtocolBuffers.Collections;
21using Google.ProtocolBuffers.Descriptors;
22
23namespace Google.ProtocolBuffers {
24 /// <summary>
25 /// TODO(jonskeet): Write summary text.
26 /// </summary>
27 public sealed class UninitializedMessageException : Exception {
28
29 private readonly IList<string> missingFields;
30
31 public UninitializedMessageException(IMessage message)
32 : this(FindMissingFields(message)) {
33 }
34
35 private UninitializedMessageException(IList<string> missingFields)
36 : base(BuildDescription(missingFields)) {
37 this.missingFields = Lists.AsReadOnly(missingFields);
38 }
39
40
41 /// <summary>
42 /// Converts this exception into an InvalidProtocolBufferException.
43 /// When a parsed message is missing required fields, this should be thrown
44 /// instead of UninitializedMessageException.
45 /// </summary>
46 public InvalidProtocolBufferException AsInvalidProtocolBufferException() {
47 return new InvalidProtocolBufferException(Message);
48 }
49
50 /// <summary>
51 /// Constructs the description string for a given list of missing fields.
52 /// </summary>
53 private static string BuildDescription(IEnumerable<string> missingFields) {
54 StringBuilder description = new StringBuilder("Message missing required fields: ");
55 bool first = true;
56 foreach(string field in missingFields) {
57 if (first) {
58 first = false;
59 } else {
60 description.Append(", ");
61 }
62 description.Append(field);
63 }
64 return description.ToString();
65 }
66
67 /// <summary>
68 /// Returns a list of the full "paths" of missing required
69 /// fields in the specified message.
70 /// </summary>
71 private static IList<String> FindMissingFields(IMessage message) {
72 List<String> results = new List<String>();
73 FindMissingFields(message, "", results);
74 return results;
75 }
76
77 /// <summary>
78 /// Recursive helper implementing FindMissingFields.
79 /// </summary>
80 private static void FindMissingFields(IMessage message, String prefix, List<String> results) {
81 foreach (FieldDescriptor field in message.DescriptorForType.Fields) {
82 if (field.IsRequired && !message.HasField(field)) {
83 results.Add(prefix + field.Name);
84 }
85 }
86
87 foreach (KeyValuePair<FieldDescriptor, object> entry in message.AllFields) {
88 FieldDescriptor field = entry.Key;
89 object value = entry.Value;
90
91 if (field.MappedType == MappedType.Message) {
92 if (field.IsRepeated) {
93 int i = 0;
94 foreach (object element in (IEnumerable) value) {
95 FindMissingFields((IMessage) element, SubMessagePrefix(prefix, field, i++), results);
96 }
97 } else {
98 if (message.HasField(field)) {
99 FindMissingFields((IMessage) value, SubMessagePrefix(prefix, field, -1), results);
100 }
101 }
102 }
103 }
104 }
105
106 private static String SubMessagePrefix(String prefix, FieldDescriptor field, int index) {
107 StringBuilder result = new StringBuilder(prefix);
108 if (field.IsExtension) {
109 result.Append('(')
110 .Append(field.FullName)
111 .Append(')');
112 } else {
113 result.Append(field.Name);
114 }
115 if (index != -1) {
116 result.Append('[')
117 .Append(index)
118 .Append(']');
119 }
120 result.Append('.');
121 return result.ToString();
122 }
123 }
124}
125
126
127