Index: third_party/protobuf/java/core/src/main/java/com/google/protobuf/TextFormat.java |
diff --git a/third_party/protobuf/java/core/src/main/java/com/google/protobuf/TextFormat.java b/third_party/protobuf/java/core/src/main/java/com/google/protobuf/TextFormat.java |
index c1c328fc7d8d6ab01fa5521c73e3814ec9c39692..49708242156ca5ded0314f0ef0845c46b46cd694 100644 |
--- a/third_party/protobuf/java/core/src/main/java/com/google/protobuf/TextFormat.java |
+++ b/third_party/protobuf/java/core/src/main/java/com/google/protobuf/TextFormat.java |
@@ -661,6 +661,14 @@ public final class TextFormat { |
nextToken(); |
} |
+ int getPreviousLine() { |
+ return previousLine; |
+ } |
+ |
+ int getPreviousColumn() { |
+ return previousColumn; |
+ } |
+ |
int getLine() { |
return line; |
} |
@@ -1374,6 +1382,28 @@ public final class TextFormat { |
return text; |
} |
+ // Check both unknown fields and unknown extensions and log warming messages |
+ // or throw exceptions according to the flag. |
+ private void checkUnknownFields(final List<String> unknownFields) |
+ throws ParseException { |
+ if (unknownFields.isEmpty()) { |
+ return; |
+ } |
+ |
+ StringBuilder msg = new StringBuilder("Input contains unknown fields and/or extensions:"); |
+ for (String field : unknownFields) { |
+ msg.append('\n').append(field); |
+ } |
+ |
+ if (allowUnknownFields) { |
+ logger.warning(msg.toString()); |
+ } else { |
+ String[] lineColumn = unknownFields.get(0).split(":"); |
+ throw new ParseException(Integer.valueOf(lineColumn[0]), |
+ Integer.valueOf(lineColumn[1]), msg.toString()); |
+ } |
+ } |
+ |
/** |
* Parse a text-format message from {@code input} and merge the contents |
* into {@code builder}. Extensions will be recognized if they are |
@@ -1387,9 +1417,13 @@ public final class TextFormat { |
MessageReflection.BuilderAdapter target = |
new MessageReflection.BuilderAdapter(builder); |
+ List<String> unknownFields = new ArrayList<String>(); |
+ |
while (!tokenizer.atEnd()) { |
- mergeField(tokenizer, extensionRegistry, target); |
+ mergeField(tokenizer, extensionRegistry, target, unknownFields); |
} |
+ |
+ checkUnknownFields(unknownFields); |
} |
@@ -1399,9 +1433,11 @@ public final class TextFormat { |
*/ |
private void mergeField(final Tokenizer tokenizer, |
final ExtensionRegistry extensionRegistry, |
- final MessageReflection.MergeTarget target) |
+ final MessageReflection.MergeTarget target, |
+ List<String> unknownFields) |
throws ParseException { |
- mergeField(tokenizer, extensionRegistry, target, parseInfoTreeBuilder); |
+ mergeField(tokenizer, extensionRegistry, target, parseInfoTreeBuilder, |
+ unknownFields); |
} |
/** |
@@ -1411,7 +1447,8 @@ public final class TextFormat { |
private void mergeField(final Tokenizer tokenizer, |
final ExtensionRegistry extensionRegistry, |
final MessageReflection.MergeTarget target, |
- TextFormatParseInfoTree.Builder parseTreeBuilder) |
+ TextFormatParseInfoTree.Builder parseTreeBuilder, |
+ List<String> unknownFields) |
throws ParseException { |
FieldDescriptor field = null; |
int startLine = tokenizer.getLine(); |
@@ -1432,13 +1469,9 @@ public final class TextFormat { |
extensionRegistry, name.toString()); |
if (extension == null) { |
- if (!allowUnknownFields) { |
- throw tokenizer.parseExceptionPreviousToken( |
- "Extension \"" + name + "\" not found in the ExtensionRegistry."); |
- } else { |
- logger.warning( |
- "Extension \"" + name + "\" not found in the ExtensionRegistry."); |
- } |
+ unknownFields.add((tokenizer.getPreviousLine() + 1) + ":" + |
+ (tokenizer.getPreviousColumn() + 1) + ":\t" + |
+ type.getFullName() + ".[" + name + "]"); |
} else { |
if (extension.descriptor.getContainingType() != type) { |
throw tokenizer.parseExceptionPreviousToken( |
@@ -1473,16 +1506,9 @@ public final class TextFormat { |
} |
if (field == null) { |
- if (!allowUnknownFields) { |
- throw tokenizer.unknownFieldParseExceptionPreviousToken( |
- name, |
- "Message type \"" + type.getFullName() |
- + "\" has no field named \"" + name + "\"."); |
- } else { |
- logger.warning( |
- "Message type \"" + type.getFullName() |
- + "\" has no field named \"" + name + "\"."); |
- } |
+ unknownFields.add((tokenizer.getPreviousLine() + 1) + ":" + |
+ (tokenizer.getPreviousColumn() + 1) + ":\t" + |
+ type.getFullName() + "." + name); |
} |
} |
@@ -1511,15 +1537,15 @@ public final class TextFormat { |
TextFormatParseInfoTree.Builder childParseTreeBuilder = |
parseTreeBuilder.getBuilderForSubMessageField(field); |
consumeFieldValues(tokenizer, extensionRegistry, target, field, extension, |
- childParseTreeBuilder); |
+ childParseTreeBuilder, unknownFields); |
} else { |
consumeFieldValues(tokenizer, extensionRegistry, target, field, extension, |
- parseTreeBuilder); |
+ parseTreeBuilder, unknownFields); |
} |
} else { |
tokenizer.consume(":"); // required |
- consumeFieldValues( |
- tokenizer, extensionRegistry, target, field, extension, parseTreeBuilder); |
+ consumeFieldValues(tokenizer, extensionRegistry, target, field, |
+ extension, parseTreeBuilder, unknownFields); |
} |
if (parseTreeBuilder != null) { |
@@ -1544,23 +1570,32 @@ public final class TextFormat { |
final MessageReflection.MergeTarget target, |
final FieldDescriptor field, |
final ExtensionRegistry.ExtensionInfo extension, |
- final TextFormatParseInfoTree.Builder parseTreeBuilder) |
+ final TextFormatParseInfoTree.Builder parseTreeBuilder, |
+ List<String> unknownFields) |
throws ParseException { |
// Support specifying repeated field values as a comma-separated list. |
// Ex."foo: [1, 2, 3]" |
if (field.isRepeated() && tokenizer.tryConsume("[")) { |
- while (true) { |
- consumeFieldValue(tokenizer, extensionRegistry, target, field, extension, |
- parseTreeBuilder); |
- if (tokenizer.tryConsume("]")) { |
- // End of list. |
- break; |
+ if (!tokenizer.tryConsume("]")) { // Allow "foo: []" to be treated as empty. |
+ while (true) { |
+ consumeFieldValue( |
+ tokenizer, |
+ extensionRegistry, |
+ target, |
+ field, |
+ extension, |
+ parseTreeBuilder, |
+ unknownFields); |
+ if (tokenizer.tryConsume("]")) { |
+ // End of list. |
+ break; |
+ } |
+ tokenizer.consume(","); |
} |
- tokenizer.consume(","); |
} |
} else { |
- consumeFieldValue( |
- tokenizer, extensionRegistry, target, field, extension, parseTreeBuilder); |
+ consumeFieldValue(tokenizer, extensionRegistry, target, field, |
+ extension, parseTreeBuilder, unknownFields); |
} |
} |
@@ -1574,7 +1609,8 @@ public final class TextFormat { |
final MessageReflection.MergeTarget target, |
final FieldDescriptor field, |
final ExtensionRegistry.ExtensionInfo extension, |
- final TextFormatParseInfoTree.Builder parseTreeBuilder) |
+ final TextFormatParseInfoTree.Builder parseTreeBuilder, |
+ List<String> unknownFields) |
throws ParseException { |
Object value = null; |
@@ -1596,7 +1632,8 @@ public final class TextFormat { |
throw tokenizer.parseException( |
"Expected \"" + endToken + "\"."); |
} |
- mergeField(tokenizer, extensionRegistry, subField, parseTreeBuilder); |
+ mergeField(tokenizer, extensionRegistry, subField, parseTreeBuilder, |
+ unknownFields); |
} |
value = subField.finish(); |