浏览代码

Enable ignoring unknown in json parsing in php (#4839)

* Enable ignoring unknown in json parsing in php

* Update generated descriptor files

* Update failure list for other languages.

* Remove unnecessary php files
Paul Yang 7 年之前
父节点
当前提交
26eeec93e4

+ 2 - 0
conformance/conformance.proto

@@ -82,6 +82,8 @@ message ConformanceRequest {
   // protobuf_test_messages.proto3.TestAllTypesProto3 or
   // protobuf_test_messages.proto3.TestAllTypesProto3 or
   // protobuf_test_messages.proto2.TestAllTypesProto2.
   // protobuf_test_messages.proto2.TestAllTypesProto2.
   string message_type = 4;
   string message_type = 4;
+
+  bool ignore_unknown_json = 5;
 }
 }
 
 
 // Represents a single test case's output.
 // Represents a single test case's output.

+ 5 - 3
conformance/conformance_php.php

@@ -6,8 +6,8 @@ require_once("Conformance/ConformanceRequest.php");
 require_once("Protobuf_test_messages/Proto3/ForeignMessage.php");
 require_once("Protobuf_test_messages/Proto3/ForeignMessage.php");
 require_once("Protobuf_test_messages/Proto3/ForeignEnum.php");
 require_once("Protobuf_test_messages/Proto3/ForeignEnum.php");
 require_once("Protobuf_test_messages/Proto3/TestAllTypesProto3.php");
 require_once("Protobuf_test_messages/Proto3/TestAllTypesProto3.php");
-require_once("Protobuf_test_messages/Proto3/TestAllTypesProto3_NestedMessage.php");
-require_once("Protobuf_test_messages/Proto3/TestAllTypesProto3_NestedEnum.php");
+require_once("Protobuf_test_messages/Proto3/TestAllTypesProto3/NestedMessage.php");
+require_once("Protobuf_test_messages/Proto3/TestAllTypesProto3/NestedEnum.php");
 
 
 require_once("GPBMetadata/Conformance.php");
 require_once("GPBMetadata/Conformance.php");
 require_once("GPBMetadata/Google/Protobuf/TestMessagesProto3.php");
 require_once("GPBMetadata/Google/Protobuf/TestMessagesProto3.php");
@@ -39,8 +39,10 @@ function doTest($request)
         trigger_error("Protobuf request doesn't have specific payload type", E_USER_ERROR);
         trigger_error("Protobuf request doesn't have specific payload type", E_USER_ERROR);
       }
       }
     } elseif ($request->getPayload() == "json_payload") {
     } elseif ($request->getPayload() == "json_payload") {
+      $ignore_json_unknown = $request->getIgnoreUnknownJson();
       try {
       try {
-          $test_message->mergeFromJsonString($request->getJsonPayload());
+          $test_message->mergeFromJsonString($request->getJsonPayload(),
+                                             $ignore_json_unknown);
       } catch (Exception $e) {
       } catch (Exception $e) {
           $response->setParseError($e->getMessage());
           $response->setParseError($e->getMessage());
           return $response;
           return $response;

+ 160 - 86
conformance/conformance_test.cc

@@ -191,6 +191,78 @@ string UpperCase(string str) {
 namespace google {
 namespace google {
 namespace protobuf {
 namespace protobuf {
 
 
+ConformanceTestSuite::ConformanceRequestSetting::ConformanceRequestSetting(
+    ConformanceLevel level, conformance::WireFormat input_format,
+    conformance::WireFormat output_format, bool is_proto3,
+    const string& test_name, const string& input)
+    : level_(level), input_format_(input_format),
+      output_format_(output_format), is_proto3_(is_proto3) {
+  auto newTestMessage = [&is_proto3]() {
+    Message* newMessage;
+    if (is_proto3) {
+      newMessage = new TestAllTypesProto3;
+    } else {
+      newMessage = new TestAllTypesProto2;
+    }
+    return newMessage;
+  };
+
+  string input_format_string;
+  string output_format_string;
+  string rname = is_proto3 ? ".Proto3" : ".Proto2";
+
+  switch (input_format) {
+    case conformance::PROTOBUF: {
+      request_.set_protobuf_payload(input);
+      input_format_string = ".ProtobufInput.";
+      break;
+    }
+
+    case conformance::JSON: {
+      request_.set_json_payload(input);
+      input_format_string = ".JsonInput.";
+      break;
+    }
+
+    default:
+      GOOGLE_LOG(FATAL) << "Unspecified input format";
+  }
+
+  switch (output_format) {
+    case conformance::PROTOBUF: {
+      output_format_string = ".ProtobufOutput";
+      break;
+    }
+
+    case conformance::JSON: {
+      output_format_string = ".JsonOutput";
+      break;
+    }
+
+    default:
+      GOOGLE_LOG(FATAL) << "Unspecified output format";
+  }
+
+  test_name_ = ConformanceLevelToString(level) + rname +
+               input_format_string + test_name +
+               output_format_string;
+
+  if (is_proto3) {
+    request_.set_message_type("protobuf_test_messages.proto3.TestAllTypesProto3");
+  } else {
+    request_.set_message_type("protobuf_test_messages.proto2.TestAllTypesProto2");
+  }
+  request_.set_requested_output_format(output_format);
+}
+
+Message* ConformanceTestSuite::ConformanceRequestSetting::GetTestMessage() const {
+  if (is_proto3_) {
+    return new TestAllTypesProto3();
+  } else {
+    return new TestAllTypesProto2();
+  }
+}
+
 void ConformanceTestSuite::ReportSuccess(const string& test_name) {
 void ConformanceTestSuite::ReportSuccess(const string& test_name) {
   if (expected_to_fail_.erase(test_name) != 0) {
   if (expected_to_fail_.erase(test_name) != 0) {
     StringAppendF(&output_,
     StringAppendF(&output_,
@@ -273,75 +345,36 @@ void ConformanceTestSuite::RunTest(const string& test_name,
 }
 }
 
 
 void ConformanceTestSuite::RunValidInputTest(
 void ConformanceTestSuite::RunValidInputTest(
-    const string& test_name, ConformanceLevel level, const string& input,
-    WireFormat input_format, const string& equivalent_text_format,
-    WireFormat requested_output, bool isProto3) {
-  auto newTestMessage = [&isProto3]() {
-    Message* newMessage;
-    if (isProto3) {
-      newMessage = new TestAllTypesProto3;
-    } else {
-      newMessage = new TestAllTypesProto2;
-    }
-    return newMessage;
-  };
-  Message* reference_message = newTestMessage();
+    const ConformanceRequestSetting& setting,
+    const string& equivalent_text_format) {
+  Message* reference_message = setting.GetTestMessage();
   GOOGLE_CHECK(
   GOOGLE_CHECK(
       TextFormat::ParseFromString(equivalent_text_format, reference_message))
       TextFormat::ParseFromString(equivalent_text_format, reference_message))
-          << "Failed to parse data for test case: " << test_name
+          << "Failed to parse data for test case: " << setting.GetTestName()
           << ", data: " << equivalent_text_format;
           << ", data: " << equivalent_text_format;
   const string equivalent_wire_format = reference_message->SerializeAsString();
   const string equivalent_wire_format = reference_message->SerializeAsString();
-  RunValidBinaryInputTest(test_name, level, input, input_format,
-                          equivalent_wire_format, requested_output, isProto3);
+  RunValidBinaryInputTest(setting, equivalent_wire_format);
 }
 }
 
 
 void ConformanceTestSuite::RunValidBinaryInputTest(
 void ConformanceTestSuite::RunValidBinaryInputTest(
-    const string& test_name, ConformanceLevel level, const string& input,
-    WireFormat input_format, const string& equivalent_wire_format,
-    WireFormat requested_output, bool isProto3) {
-  auto newTestMessage = [&isProto3]() {
-    Message* newMessage;
-    if (isProto3) {
-      newMessage = new TestAllTypesProto3;
-    } else {
-      newMessage = new TestAllTypesProto2;
-    }
-    return newMessage;
-  };
-  Message* reference_message = newTestMessage();
+    const ConformanceRequestSetting& setting,
+    const string& equivalent_wire_format) {
+  const string& test_name = setting.GetTestName();
+  ConformanceLevel level = setting.GetLevel();
+
+  Message* reference_message = setting.GetTestMessage();
   GOOGLE_CHECK(
   GOOGLE_CHECK(
       reference_message->ParseFromString(equivalent_wire_format))
       reference_message->ParseFromString(equivalent_wire_format))
           << "Failed to parse wire data for test case: " << test_name;
           << "Failed to parse wire data for test case: " << test_name;
 
 
-  ConformanceRequest request;
+  const ConformanceRequest& request = setting.GetRequest();
   ConformanceResponse response;
   ConformanceResponse response;
 
 
-  switch (input_format) {
-    case conformance::PROTOBUF: {
-      request.set_protobuf_payload(input);
-      if (isProto3) {
-        request.set_message_type("protobuf_test_messages.proto3.TestAllTypesProto3");
-      } else {
-        request.set_message_type("protobuf_test_messages.proto2.TestAllTypesProto2");
-      }
-      break;
-    }
-
-    case conformance::JSON: {
-      request.set_message_type("protobuf_test_messages.proto3.TestAllTypesProto3");
-      request.set_json_payload(input);
-      break;
-    }
-
-    default:
-      GOOGLE_LOG(FATAL) << "Unspecified input format";
-  }
-
-  request.set_requested_output_format(requested_output);
-
   RunTest(test_name, request, &response);
   RunTest(test_name, request, &response);
 
 
-  Message *test_message = newTestMessage();
+  Message* test_message = setting.GetTestMessage();
+
+  WireFormat requested_output = request.requested_output_format();
 
 
   switch (response.result_case()) {
   switch (response.result_case()) {
     case ConformanceResponse::RESULT_NOT_SET:
     case ConformanceResponse::RESULT_NOT_SET:
@@ -476,56 +509,60 @@ void ConformanceTestSuite::ExpectHardParseFailureForProto(
 void ConformanceTestSuite::RunValidJsonTest(
 void ConformanceTestSuite::RunValidJsonTest(
     const string& test_name, ConformanceLevel level, const string& input_json,
     const string& test_name, ConformanceLevel level, const string& input_json,
     const string& equivalent_text_format) {
     const string& equivalent_text_format) {
-  RunValidInputTest(
-      ConformanceLevelToString(level) + ".Proto3.JsonInput." + test_name +
-      ".ProtobufOutput", level, input_json, conformance::JSON,
-      equivalent_text_format, conformance::PROTOBUF, true);
-  RunValidInputTest(
-      ConformanceLevelToString(level) + ".Proto3.JsonInput." + test_name +
-      ".JsonOutput", level, input_json, conformance::JSON,
-      equivalent_text_format, conformance::JSON, true);
+  ConformanceRequestSetting setting1(
+      level, conformance::JSON, conformance::PROTOBUF,
+      true, test_name, input_json);
+  RunValidInputTest(setting1, equivalent_text_format);
+
+  ConformanceRequestSetting setting2(
+      level, conformance::JSON, conformance::JSON,
+      true, test_name, input_json);
+  RunValidInputTest(setting2, equivalent_text_format);
 }
 }
 
 
 void ConformanceTestSuite::RunValidJsonTestWithProtobufInput(
 void ConformanceTestSuite::RunValidJsonTestWithProtobufInput(
     const string& test_name, ConformanceLevel level, const TestAllTypesProto3& input,
     const string& test_name, ConformanceLevel level, const TestAllTypesProto3& input,
     const string& equivalent_text_format) {
     const string& equivalent_text_format) {
-  RunValidInputTest(
-      ConformanceLevelToString(level) + ".Proto3" + ".ProtobufInput." + test_name +
-      ".JsonOutput", level, input.SerializeAsString(), conformance::PROTOBUF,
-      equivalent_text_format, conformance::JSON, true);
+  ConformanceRequestSetting setting(
+      level, conformance::PROTOBUF, conformance::JSON,
+      true, test_name, input.SerializeAsString());
+  RunValidInputTest(setting, equivalent_text_format);
+}
+
+void ConformanceTestSuite::RunValidJsonIgnoreUnknownTest(
+    const string& test_name, ConformanceLevel level, const string& input_json,
+    const string& equivalent_text_format) {
+  ConformanceRequestSetting setting(
+      level, conformance::JSON, conformance::PROTOBUF,
+      true, test_name, input_json);
+  setting.SetIgnoreUnknownJson(true);
+  RunValidInputTest(setting, equivalent_text_format);
 }
 }
 
 
 void ConformanceTestSuite::RunValidProtobufTest(
 void ConformanceTestSuite::RunValidProtobufTest(
     const string& test_name, ConformanceLevel level,
     const string& test_name, ConformanceLevel level,
     const string& input_protobuf, const string& equivalent_text_format,
     const string& input_protobuf, const string& equivalent_text_format,
     bool isProto3) {
     bool isProto3) {
-  string rname = ".Proto3";
-  if (!isProto3) {
-    rname = ".Proto2";
-  }
-  RunValidInputTest(
-      ConformanceLevelToString(level) + rname + ".ProtobufInput." + test_name +
-      ".ProtobufOutput", level, input_protobuf, conformance::PROTOBUF,
-      equivalent_text_format, conformance::PROTOBUF, isProto3);
+  ConformanceRequestSetting setting1(
+      level, conformance::PROTOBUF, conformance::PROTOBUF,
+      isProto3, test_name, input_protobuf);
+  RunValidInputTest(setting1, equivalent_text_format);
+
   if (isProto3) {
   if (isProto3) {
-    RunValidInputTest(
-        ConformanceLevelToString(level) + rname + ".ProtobufInput." +  test_name +
-        ".JsonOutput", level, input_protobuf, conformance::PROTOBUF,
-        equivalent_text_format, conformance::JSON, isProto3);
+    ConformanceRequestSetting setting2(
+        level, conformance::PROTOBUF, conformance::JSON,
+        true, test_name, input_protobuf);
+    RunValidInputTest(setting2, equivalent_text_format);
   }
   }
 }
 }
 
 
 void ConformanceTestSuite::RunValidBinaryProtobufTest(
 void ConformanceTestSuite::RunValidBinaryProtobufTest(
     const string& test_name, ConformanceLevel level,
     const string& test_name, ConformanceLevel level,
     const string& input_protobuf, bool isProto3) {
     const string& input_protobuf, bool isProto3) {
-  string rname = ".Proto3";
-  if (!isProto3) {
-    rname = ".Proto2";
-  }
-  RunValidBinaryInputTest(
-      ConformanceLevelToString(level) + rname + ".ProtobufInput." + test_name +
-      ".ProtobufOutput", level, input_protobuf, conformance::PROTOBUF,
-      input_protobuf, conformance::PROTOBUF, isProto3);
+  ConformanceRequestSetting setting(
+      level, conformance::PROTOBUF, conformance::PROTOBUF,
+      isProto3, test_name, input_protobuf);
+  RunValidBinaryInputTest(setting, input_protobuf);
 }
 }
 
 
 void ConformanceTestSuite::RunValidProtobufTestWithMessage(
 void ConformanceTestSuite::RunValidProtobufTestWithMessage(
@@ -2535,6 +2572,43 @@ bool ConformanceTestSuite::RunSuite(ConformanceTestRunner* runner,
         }
         }
       )");
       )");
 
 
+  RunValidJsonIgnoreUnknownTest(
+      "IgnoreUnknownJsonNumber", REQUIRED,
+      R"({
+        "unknown": 1
+      })",
+      "");
+  RunValidJsonIgnoreUnknownTest(
+      "IgnoreUnknownJsonString", REQUIRED,
+      R"({
+        "unknown": "a"
+      })",
+      "");
+  RunValidJsonIgnoreUnknownTest(
+      "IgnoreUnknownJsonTrue", REQUIRED,
+      R"({
+        "unknown": true
+      })",
+      "");
+  RunValidJsonIgnoreUnknownTest(
+      "IgnoreUnknownJsonFalse", REQUIRED,
+      R"({
+        "unknown": false
+      })",
+      "");
+  RunValidJsonIgnoreUnknownTest(
+      "IgnoreUnknownJsonNull", REQUIRED,
+      R"({
+        "unknown": null
+      })",
+      "");
+  RunValidJsonIgnoreUnknownTest(
+      "IgnoreUnknownJsonObject", REQUIRED,
+      R"({
+        "unknown": {"a": 1}
+      })",
+      "");
+
   bool ok = true;
   bool ok = true;
   if (!CheckSetEmpty(expected_to_fail_, "nonexistent_tests.txt",
   if (!CheckSetEmpty(expected_to_fail_, "nonexistent_tests.txt",
                      "These tests were listed in the failure list, but they "
                      "These tests were listed in the failure list, but they "

+ 44 - 15
conformance/conformance_test.h

@@ -44,6 +44,7 @@
 #include <google/protobuf/util/type_resolver.h>
 #include <google/protobuf/util/type_resolver.h>
 #include <google/protobuf/wire_format_lite.h>
 #include <google/protobuf/wire_format_lite.h>
 
 
+#include "conformance.pb.h"
 #include "third_party/jsoncpp/json.h"
 #include "third_party/jsoncpp/json.h"
 
 
 namespace conformance {
 namespace conformance {
@@ -146,7 +147,42 @@ class ConformanceTestSuite {
     REQUIRED = 0,
     REQUIRED = 0,
     RECOMMENDED = 1,
     RECOMMENDED = 1,
   };
   };
-  string ConformanceLevelToString(ConformanceLevel level);
+
+  class ConformanceRequestSetting {
+   public:
+    ConformanceRequestSetting(
+        ConformanceLevel level, conformance::WireFormat input_format,
+        conformance::WireFormat output_format, bool is_proto3,
+        const string& test_name, const string& input);
+
+   Message* GetTestMessage() const;
+
+   const string& GetTestName() const {
+     return test_name_;
+   }
+
+   const conformance::ConformanceRequest& GetRequest() const {
+     return request_;
+   }
+
+   const ConformanceLevel GetLevel() const {
+     return level_;
+   }
+
+   void SetIgnoreUnknownJson(bool ignore_unknown_json) {
+     request_.set_ignore_unknown_json(ignore_unknown_json);
+   }
+  
+   private:
+    ConformanceLevel level_;
+    conformance::WireFormat input_format_;
+    conformance::WireFormat output_format_;
+    bool is_proto3_;
+    string test_name_;
+    conformance::ConformanceRequest request_;
+  };
+
+  static string ConformanceLevelToString(ConformanceLevel level);
 
 
   void ReportSuccess(const std::string& test_name);
   void ReportSuccess(const std::string& test_name);
   void ReportFailure(const string& test_name,
   void ReportFailure(const string& test_name,
@@ -160,24 +196,17 @@ class ConformanceTestSuite {
   void RunTest(const std::string& test_name,
   void RunTest(const std::string& test_name,
                const conformance::ConformanceRequest& request,
                const conformance::ConformanceRequest& request,
                conformance::ConformanceResponse* response);
                conformance::ConformanceResponse* response);
-  void RunValidInputTest(const string& test_name,
-                         ConformanceLevel level,
-                         const string& input,
-                         conformance::WireFormat input_format,
-                         const string& equivalent_text_format,
-                         conformance::WireFormat requested_output,
-                         bool isProto3);
-  void RunValidBinaryInputTest(const string& test_name,
-                               ConformanceLevel level,
-                               const string& input,
-                               conformance::WireFormat input_format,
-                               const string& equivalent_wire_format,
-                               conformance::WireFormat requested_output,
-                               bool isProto3);
+  void RunValidInputTest(const ConformanceRequestSetting& setting,
+                         const string& equivalent_text_format);
+  void RunValidBinaryInputTest(const ConformanceRequestSetting& setting,
+                               const string& equivalent_wire_format);
   void RunValidJsonTest(const string& test_name,
   void RunValidJsonTest(const string& test_name,
                         ConformanceLevel level,
                         ConformanceLevel level,
                         const string& input_json,
                         const string& input_json,
                         const string& equivalent_text_format);
                         const string& equivalent_text_format);
+  void RunValidJsonIgnoreUnknownTest(
+      const string& test_name, ConformanceLevel level, const string& input_json,
+      const string& equivalent_text_format);
   void RunValidJsonTestWithProtobufInput(
   void RunValidJsonTestWithProtobufInput(
       const string& test_name,
       const string& test_name,
       ConformanceLevel level,
       ConformanceLevel level,

+ 6 - 0
conformance/failure_list_cpp.txt

@@ -54,3 +54,9 @@ Required.Proto2.ProtobufInput.PrematureEofInPackedField.SINT32
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.SINT64
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.SINT64
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT32
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT32
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT64
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT64
+Required.Proto3.JsonInput.IgnoreUnknownJsonFalse.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonNull.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonNumber.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonObject.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonString.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonTrue.ProtobufOutput

+ 6 - 0
conformance/failure_list_csharp.txt

@@ -1,2 +1,8 @@
 Recommended.Proto3.JsonInput.BytesFieldBase64Url.JsonOutput
 Recommended.Proto3.JsonInput.BytesFieldBase64Url.JsonOutput
 Recommended.Proto3.JsonInput.BytesFieldBase64Url.ProtobufOutput
 Recommended.Proto3.JsonInput.BytesFieldBase64Url.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonFalse.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonNull.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonNumber.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonObject.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonString.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonTrue.ProtobufOutput

+ 6 - 0
conformance/failure_list_java.txt

@@ -45,3 +45,9 @@ Required.Proto3.ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValu
 Required.Proto3.ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE
 Required.Proto3.ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE
 Required.Proto2.ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE
 Required.Proto2.ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE
 Required.Proto2.ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE
 Required.Proto2.ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE
+Required.Proto3.JsonInput.IgnoreUnknownJsonFalse.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonNull.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonNumber.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonObject.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonString.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonTrue.ProtobufOutput

+ 0 - 56
conformance/failure_list_php_c.txt

@@ -1,8 +1,6 @@
 Recommended.FieldMaskNumbersDontRoundTrip.JsonOutput
 Recommended.FieldMaskNumbersDontRoundTrip.JsonOutput
 Recommended.FieldMaskPathsDontRoundTrip.JsonOutput
 Recommended.FieldMaskPathsDontRoundTrip.JsonOutput
 Recommended.FieldMaskTooManyUnderscore.JsonOutput
 Recommended.FieldMaskTooManyUnderscore.JsonOutput
-Recommended.Proto3.JsonInput.BoolFieldIntegerOne
-Recommended.Proto3.JsonInput.BoolFieldIntegerZero
 Recommended.Proto3.JsonInput.DurationHas3FractionalDigits.Validator
 Recommended.Proto3.JsonInput.DurationHas3FractionalDigits.Validator
 Recommended.Proto3.JsonInput.DurationHas6FractionalDigits.Validator
 Recommended.Proto3.JsonInput.DurationHas6FractionalDigits.Validator
 Recommended.Proto3.JsonInput.DurationHas9FractionalDigits.Validator
 Recommended.Proto3.JsonInput.DurationHas9FractionalDigits.Validator
@@ -10,9 +8,6 @@ Recommended.Proto3.JsonInput.DurationHasZeroFractionalDigit.Validator
 Recommended.Proto3.JsonInput.Int64FieldBeString.Validator
 Recommended.Proto3.JsonInput.Int64FieldBeString.Validator
 Recommended.Proto3.JsonInput.MapFieldValueIsNull
 Recommended.Proto3.JsonInput.MapFieldValueIsNull
 Recommended.Proto3.JsonInput.OneofZeroBytes.JsonOutput
 Recommended.Proto3.JsonInput.OneofZeroBytes.JsonOutput
-Recommended.Proto3.JsonInput.OneofZeroBytes.ProtobufOutput
-Recommended.Proto3.JsonInput.OneofZeroString.JsonOutput
-Recommended.Proto3.JsonInput.OneofZeroString.ProtobufOutput
 Recommended.Proto3.JsonInput.RepeatedFieldMessageElementIsNull
 Recommended.Proto3.JsonInput.RepeatedFieldMessageElementIsNull
 Recommended.Proto3.JsonInput.RepeatedFieldPrimitiveElementIsNull
 Recommended.Proto3.JsonInput.RepeatedFieldPrimitiveElementIsNull
 Recommended.Proto3.JsonInput.StringEndsWithEscapeChar
 Recommended.Proto3.JsonInput.StringEndsWithEscapeChar
@@ -21,9 +16,6 @@ Recommended.Proto3.JsonInput.StringFieldUnpairedHighSurrogate
 Recommended.Proto3.JsonInput.StringFieldUnpairedLowSurrogate
 Recommended.Proto3.JsonInput.StringFieldUnpairedLowSurrogate
 Recommended.Proto3.JsonInput.Uint64FieldBeString.Validator
 Recommended.Proto3.JsonInput.Uint64FieldBeString.Validator
 Recommended.Proto3.ProtobufInput.OneofZeroBytes.JsonOutput
 Recommended.Proto3.ProtobufInput.OneofZeroBytes.JsonOutput
-Recommended.Proto3.ProtobufInput.OneofZeroBytes.ProtobufOutput
-Recommended.Proto3.ProtobufInput.OneofZeroString.JsonOutput
-Recommended.Proto3.ProtobufInput.OneofZeroString.ProtobufOutput
 Required.DurationProtoInputTooLarge.JsonOutput
 Required.DurationProtoInputTooLarge.JsonOutput
 Required.DurationProtoInputTooSmall.JsonOutput
 Required.DurationProtoInputTooSmall.JsonOutput
 Required.Proto3.JsonInput.Any.JsonOutput
 Required.Proto3.JsonInput.Any.JsonOutput
@@ -47,63 +39,22 @@ Required.Proto3.JsonInput.AnyWithValueForInteger.ProtobufOutput
 Required.Proto3.JsonInput.AnyWithValueForJsonObject.JsonOutput
 Required.Proto3.JsonInput.AnyWithValueForJsonObject.JsonOutput
 Required.Proto3.JsonInput.AnyWithValueForJsonObject.ProtobufOutput
 Required.Proto3.JsonInput.AnyWithValueForJsonObject.ProtobufOutput
 Required.Proto3.JsonInput.BoolMapField.JsonOutput
 Required.Proto3.JsonInput.BoolMapField.JsonOutput
-Required.Proto3.JsonInput.DoubleFieldInfinity.JsonOutput
-Required.Proto3.JsonInput.DoubleFieldInfinity.ProtobufOutput
 Required.Proto3.JsonInput.DoubleFieldMaxNegativeValue.JsonOutput
 Required.Proto3.JsonInput.DoubleFieldMaxNegativeValue.JsonOutput
 Required.Proto3.JsonInput.DoubleFieldMaxNegativeValue.ProtobufOutput
 Required.Proto3.JsonInput.DoubleFieldMaxNegativeValue.ProtobufOutput
-Required.Proto3.JsonInput.DoubleFieldMaxPositiveValue.JsonOutput
-Required.Proto3.JsonInput.DoubleFieldMaxPositiveValue.ProtobufOutput
-Required.Proto3.JsonInput.DoubleFieldMinNegativeValue.JsonOutput
-Required.Proto3.JsonInput.DoubleFieldMinNegativeValue.ProtobufOutput
 Required.Proto3.JsonInput.DoubleFieldMinPositiveValue.JsonOutput
 Required.Proto3.JsonInput.DoubleFieldMinPositiveValue.JsonOutput
 Required.Proto3.JsonInput.DoubleFieldMinPositiveValue.ProtobufOutput
 Required.Proto3.JsonInput.DoubleFieldMinPositiveValue.ProtobufOutput
 Required.Proto3.JsonInput.DoubleFieldNan.JsonOutput
 Required.Proto3.JsonInput.DoubleFieldNan.JsonOutput
-Required.Proto3.JsonInput.DoubleFieldNan.ProtobufOutput
-Required.Proto3.JsonInput.DoubleFieldNegativeInfinity.JsonOutput
-Required.Proto3.JsonInput.DoubleFieldNegativeInfinity.ProtobufOutput
-Required.Proto3.JsonInput.DoubleFieldQuotedValue.JsonOutput
-Required.Proto3.JsonInput.DoubleFieldQuotedValue.ProtobufOutput
 Required.Proto3.JsonInput.DurationMaxValue.JsonOutput
 Required.Proto3.JsonInput.DurationMaxValue.JsonOutput
 Required.Proto3.JsonInput.DurationMaxValue.ProtobufOutput
 Required.Proto3.JsonInput.DurationMaxValue.ProtobufOutput
 Required.Proto3.JsonInput.DurationMinValue.JsonOutput
 Required.Proto3.JsonInput.DurationMinValue.JsonOutput
 Required.Proto3.JsonInput.DurationMinValue.ProtobufOutput
 Required.Proto3.JsonInput.DurationMinValue.ProtobufOutput
 Required.Proto3.JsonInput.DurationRepeatedValue.JsonOutput
 Required.Proto3.JsonInput.DurationRepeatedValue.JsonOutput
 Required.Proto3.JsonInput.DurationRepeatedValue.ProtobufOutput
 Required.Proto3.JsonInput.DurationRepeatedValue.ProtobufOutput
-Required.Proto3.JsonInput.EnumFieldNumericValueNonZero.JsonOutput
-Required.Proto3.JsonInput.EnumFieldNumericValueNonZero.ProtobufOutput
-Required.Proto3.JsonInput.EnumFieldNumericValueZero.JsonOutput
-Required.Proto3.JsonInput.EnumFieldNumericValueZero.ProtobufOutput
-Required.Proto3.JsonInput.EnumFieldUnknownValue.Validator
 Required.Proto3.JsonInput.FieldMask.JsonOutput
 Required.Proto3.JsonInput.FieldMask.JsonOutput
 Required.Proto3.JsonInput.FieldMask.ProtobufOutput
 Required.Proto3.JsonInput.FieldMask.ProtobufOutput
 Required.Proto3.JsonInput.FloatFieldInfinity.JsonOutput
 Required.Proto3.JsonInput.FloatFieldInfinity.JsonOutput
-Required.Proto3.JsonInput.FloatFieldInfinity.ProtobufOutput
 Required.Proto3.JsonInput.FloatFieldNan.JsonOutput
 Required.Proto3.JsonInput.FloatFieldNan.JsonOutput
-Required.Proto3.JsonInput.FloatFieldNan.ProtobufOutput
 Required.Proto3.JsonInput.FloatFieldNegativeInfinity.JsonOutput
 Required.Proto3.JsonInput.FloatFieldNegativeInfinity.JsonOutput
-Required.Proto3.JsonInput.FloatFieldNegativeInfinity.ProtobufOutput
-Required.Proto3.JsonInput.FloatFieldQuotedValue.JsonOutput
-Required.Proto3.JsonInput.FloatFieldQuotedValue.ProtobufOutput
-Required.Proto3.JsonInput.FloatFieldTooLarge
-Required.Proto3.JsonInput.FloatFieldTooSmall
-Required.Proto3.JsonInput.Int32FieldExponentialFormat.JsonOutput
-Required.Proto3.JsonInput.Int32FieldExponentialFormat.ProtobufOutput
-Required.Proto3.JsonInput.Int32FieldFloatTrailingZero.JsonOutput
-Required.Proto3.JsonInput.Int32FieldFloatTrailingZero.ProtobufOutput
-Required.Proto3.JsonInput.Int32FieldMaxFloatValue.JsonOutput
-Required.Proto3.JsonInput.Int32FieldMaxFloatValue.ProtobufOutput
-Required.Proto3.JsonInput.Int32FieldMinFloatValue.JsonOutput
-Required.Proto3.JsonInput.Int32FieldMinFloatValue.ProtobufOutput
-Required.Proto3.JsonInput.Int32FieldStringValue.JsonOutput
-Required.Proto3.JsonInput.Int32FieldStringValue.ProtobufOutput
-Required.Proto3.JsonInput.Int32FieldStringValueEscaped.JsonOutput
-Required.Proto3.JsonInput.Int32FieldStringValueEscaped.ProtobufOutput
-Required.Proto3.JsonInput.Int64FieldMaxValue.JsonOutput
-Required.Proto3.JsonInput.Int64FieldMaxValue.ProtobufOutput
-Required.Proto3.JsonInput.Int64FieldMinValue.JsonOutput
-Required.Proto3.JsonInput.Int64FieldMinValue.ProtobufOutput
-Required.Proto3.JsonInput.MessageField.JsonOutput
-Required.Proto3.JsonInput.MessageField.ProtobufOutput
 Required.Proto3.JsonInput.OptionalBoolWrapper.JsonOutput
 Required.Proto3.JsonInput.OptionalBoolWrapper.JsonOutput
 Required.Proto3.JsonInput.OptionalBoolWrapper.ProtobufOutput
 Required.Proto3.JsonInput.OptionalBoolWrapper.ProtobufOutput
 Required.Proto3.JsonInput.OptionalBytesWrapper.JsonOutput
 Required.Proto3.JsonInput.OptionalBytesWrapper.JsonOutput
@@ -130,8 +81,6 @@ Required.Proto3.JsonInput.RepeatedBytesWrapper.JsonOutput
 Required.Proto3.JsonInput.RepeatedBytesWrapper.ProtobufOutput
 Required.Proto3.JsonInput.RepeatedBytesWrapper.ProtobufOutput
 Required.Proto3.JsonInput.RepeatedDoubleWrapper.JsonOutput
 Required.Proto3.JsonInput.RepeatedDoubleWrapper.JsonOutput
 Required.Proto3.JsonInput.RepeatedDoubleWrapper.ProtobufOutput
 Required.Proto3.JsonInput.RepeatedDoubleWrapper.ProtobufOutput
-Required.Proto3.JsonInput.RepeatedFieldWrongElementTypeExpectingMessagesGotInt
-Required.Proto3.JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotInt
 Required.Proto3.JsonInput.RepeatedFloatWrapper.JsonOutput
 Required.Proto3.JsonInput.RepeatedFloatWrapper.JsonOutput
 Required.Proto3.JsonInput.RepeatedFloatWrapper.ProtobufOutput
 Required.Proto3.JsonInput.RepeatedFloatWrapper.ProtobufOutput
 Required.Proto3.JsonInput.RepeatedInt32Wrapper.JsonOutput
 Required.Proto3.JsonInput.RepeatedInt32Wrapper.JsonOutput
@@ -146,7 +95,6 @@ Required.Proto3.JsonInput.RepeatedUint64Wrapper.JsonOutput
 Required.Proto3.JsonInput.RepeatedUint64Wrapper.ProtobufOutput
 Required.Proto3.JsonInput.RepeatedUint64Wrapper.ProtobufOutput
 Required.Proto3.JsonInput.StringFieldEscape.JsonOutput
 Required.Proto3.JsonInput.StringFieldEscape.JsonOutput
 Required.Proto3.JsonInput.StringFieldEscape.ProtobufOutput
 Required.Proto3.JsonInput.StringFieldEscape.ProtobufOutput
-Required.Proto3.JsonInput.StringFieldNotAString
 Required.Proto3.JsonInput.StringFieldSurrogatePair.JsonOutput
 Required.Proto3.JsonInput.StringFieldSurrogatePair.JsonOutput
 Required.Proto3.JsonInput.StringFieldSurrogatePair.ProtobufOutput
 Required.Proto3.JsonInput.StringFieldSurrogatePair.ProtobufOutput
 Required.Proto3.JsonInput.StringFieldUnicodeEscape.JsonOutput
 Required.Proto3.JsonInput.StringFieldUnicodeEscape.JsonOutput
@@ -155,10 +103,6 @@ Required.Proto3.JsonInput.StringFieldUnicodeEscapeWithLowercaseHexLetters.JsonOu
 Required.Proto3.JsonInput.StringFieldUnicodeEscapeWithLowercaseHexLetters.ProtobufOutput
 Required.Proto3.JsonInput.StringFieldUnicodeEscapeWithLowercaseHexLetters.ProtobufOutput
 Required.Proto3.JsonInput.Struct.JsonOutput
 Required.Proto3.JsonInput.Struct.JsonOutput
 Required.Proto3.JsonInput.Struct.ProtobufOutput
 Required.Proto3.JsonInput.Struct.ProtobufOutput
-Required.Proto3.JsonInput.Uint32FieldMaxFloatValue.JsonOutput
-Required.Proto3.JsonInput.Uint32FieldMaxFloatValue.ProtobufOutput
-Required.Proto3.JsonInput.Uint64FieldMaxValue.JsonOutput
-Required.Proto3.JsonInput.Uint64FieldMaxValue.ProtobufOutput
 Required.Proto3.JsonInput.ValueAcceptBool.JsonOutput
 Required.Proto3.JsonInput.ValueAcceptBool.JsonOutput
 Required.Proto3.JsonInput.ValueAcceptBool.ProtobufOutput
 Required.Proto3.JsonInput.ValueAcceptBool.ProtobufOutput
 Required.Proto3.JsonInput.ValueAcceptFloat.JsonOutput
 Required.Proto3.JsonInput.ValueAcceptFloat.JsonOutput

+ 6 - 0
conformance/failure_list_python-post26.txt

@@ -1,2 +1,8 @@
 JsonInput.StringFieldSurrogateInWrongOrder
 JsonInput.StringFieldSurrogateInWrongOrder
 JsonInput.StringFieldUnpairedHighSurrogate
 JsonInput.StringFieldUnpairedHighSurrogate
+Required.Proto3.JsonInput.IgnoreUnknownJsonFalse.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonNull.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonNumber.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonObject.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonString.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonTrue.ProtobufOutput

+ 6 - 0
conformance/failure_list_python.txt

@@ -19,3 +19,9 @@ Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_0
 Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_1
 Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_1
 Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_2
 Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_2
 Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_3
 Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_3
+Required.Proto3.JsonInput.IgnoreUnknownJsonFalse.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonNull.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonNumber.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonObject.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonString.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonTrue.ProtobufOutput

+ 6 - 0
conformance/failure_list_python_cpp.txt

@@ -52,3 +52,9 @@ Required.Proto2.ProtobufInput.PrematureEofInPackedField.SINT32
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.SINT64
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.SINT64
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT32
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT32
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT64
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT64
+Required.Proto3.JsonInput.IgnoreUnknownJsonFalse.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonNull.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonNumber.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonObject.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonString.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonTrue.ProtobufOutput

+ 6 - 0
conformance/failure_list_ruby.txt

@@ -135,3 +135,9 @@ Required.Proto3.ProtobufInput.FloatFieldNormalizeSignalingNan.JsonOutput
 Required.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.JsonOutput
 Required.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.JsonOutput
 Required.TimestampProtoInputTooLarge.JsonOutput
 Required.TimestampProtoInputTooLarge.JsonOutput
 Required.TimestampProtoInputTooSmall.JsonOutput
 Required.TimestampProtoInputTooSmall.JsonOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonFalse.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonNull.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonNumber.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonObject.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonString.ProtobufOutput
+Required.Proto3.JsonInput.IgnoreUnknownJsonTrue.ProtobufOutput

+ 38 - 9
csharp/src/Google.Protobuf.Conformance/Conformance.cs

@@ -24,21 +24,22 @@ namespace Conformance {
     static ConformanceReflection() {
     static ConformanceReflection() {
       byte[] descriptorData = global::System.Convert.FromBase64String(
       byte[] descriptorData = global::System.Convert.FromBase64String(
           string.Concat(
           string.Concat(
-            "ChFjb25mb3JtYW5jZS5wcm90bxILY29uZm9ybWFuY2UiowEKEkNvbmZvcm1h",
+            "ChFjb25mb3JtYW5jZS5wcm90bxILY29uZm9ybWFuY2UiwAEKEkNvbmZvcm1h",
             "bmNlUmVxdWVzdBIaChBwcm90b2J1Zl9wYXlsb2FkGAEgASgMSAASFgoManNv",
             "bmNlUmVxdWVzdBIaChBwcm90b2J1Zl9wYXlsb2FkGAEgASgMSAASFgoManNv",
             "bl9wYXlsb2FkGAIgASgJSAASOAoXcmVxdWVzdGVkX291dHB1dF9mb3JtYXQY",
             "bl9wYXlsb2FkGAIgASgJSAASOAoXcmVxdWVzdGVkX291dHB1dF9mb3JtYXQY",
             "AyABKA4yFy5jb25mb3JtYW5jZS5XaXJlRm9ybWF0EhQKDG1lc3NhZ2VfdHlw",
             "AyABKA4yFy5jb25mb3JtYW5jZS5XaXJlRm9ybWF0EhQKDG1lc3NhZ2VfdHlw",
-            "ZRgEIAEoCUIJCgdwYXlsb2FkIrEBChNDb25mb3JtYW5jZVJlc3BvbnNlEhUK",
-            "C3BhcnNlX2Vycm9yGAEgASgJSAASGQoPc2VyaWFsaXplX2Vycm9yGAYgASgJ",
-            "SAASFwoNcnVudGltZV9lcnJvchgCIAEoCUgAEhoKEHByb3RvYnVmX3BheWxv",
-            "YWQYAyABKAxIABIWCgxqc29uX3BheWxvYWQYBCABKAlIABIRCgdza2lwcGVk",
-            "GAUgASgJSABCCAoGcmVzdWx0KjUKCldpcmVGb3JtYXQSDwoLVU5TUEVDSUZJ",
-            "RUQQABIMCghQUk9UT0JVRhABEggKBEpTT04QAkIhCh9jb20uZ29vZ2xlLnBy",
-            "b3RvYnVmLmNvbmZvcm1hbmNlYgZwcm90bzM="));
+            "ZRgEIAEoCRIbChNpZ25vcmVfdW5rbm93bl9qc29uGAUgASgIQgkKB3BheWxv",
+            "YWQisQEKE0NvbmZvcm1hbmNlUmVzcG9uc2USFQoLcGFyc2VfZXJyb3IYASAB",
+            "KAlIABIZCg9zZXJpYWxpemVfZXJyb3IYBiABKAlIABIXCg1ydW50aW1lX2Vy",
+            "cm9yGAIgASgJSAASGgoQcHJvdG9idWZfcGF5bG9hZBgDIAEoDEgAEhYKDGpz",
+            "b25fcGF5bG9hZBgEIAEoCUgAEhEKB3NraXBwZWQYBSABKAlIAEIICgZyZXN1",
+            "bHQqNQoKV2lyZUZvcm1hdBIPCgtVTlNQRUNJRklFRBAAEgwKCFBST1RPQlVG",
+            "EAESCAoESlNPThACQiEKH2NvbS5nb29nbGUucHJvdG9idWYuY29uZm9ybWFu",
+            "Y2ViBnByb3RvMw=="));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Conformance.WireFormat), }, new pbr::GeneratedClrTypeInfo[] {
           new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Conformance.WireFormat), }, new pbr::GeneratedClrTypeInfo[] {
-            new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.ConformanceRequest), global::Conformance.ConformanceRequest.Parser, new[]{ "ProtobufPayload", "JsonPayload", "RequestedOutputFormat", "MessageType" }, new[]{ "Payload" }, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.ConformanceRequest), global::Conformance.ConformanceRequest.Parser, new[]{ "ProtobufPayload", "JsonPayload", "RequestedOutputFormat", "MessageType", "IgnoreUnknownJson" }, new[]{ "Payload" }, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.ConformanceResponse), global::Conformance.ConformanceResponse.Parser, new[]{ "ParseError", "SerializeError", "RuntimeError", "ProtobufPayload", "JsonPayload", "Skipped" }, new[]{ "Result" }, null, null)
             new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.ConformanceResponse), global::Conformance.ConformanceResponse.Parser, new[]{ "ParseError", "SerializeError", "RuntimeError", "ProtobufPayload", "JsonPayload", "Skipped" }, new[]{ "Result" }, null, null)
           }));
           }));
     }
     }
@@ -89,6 +90,7 @@ namespace Conformance {
     public ConformanceRequest(ConformanceRequest other) : this() {
     public ConformanceRequest(ConformanceRequest other) : this() {
       requestedOutputFormat_ = other.requestedOutputFormat_;
       requestedOutputFormat_ = other.requestedOutputFormat_;
       messageType_ = other.messageType_;
       messageType_ = other.messageType_;
+      ignoreUnknownJson_ = other.ignoreUnknownJson_;
       switch (other.PayloadCase) {
       switch (other.PayloadCase) {
         case PayloadOneofCase.ProtobufPayload:
         case PayloadOneofCase.ProtobufPayload:
           ProtobufPayload = other.ProtobufPayload;
           ProtobufPayload = other.ProtobufPayload;
@@ -158,6 +160,17 @@ namespace Conformance {
       }
       }
     }
     }
 
 
+    /// <summary>Field number for the "ignore_unknown_json" field.</summary>
+    public const int IgnoreUnknownJsonFieldNumber = 5;
+    private bool ignoreUnknownJson_;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public bool IgnoreUnknownJson {
+      get { return ignoreUnknownJson_; }
+      set {
+        ignoreUnknownJson_ = value;
+      }
+    }
+
     private object payload_;
     private object payload_;
     /// <summary>Enum of possible cases for the "payload" oneof.</summary>
     /// <summary>Enum of possible cases for the "payload" oneof.</summary>
     public enum PayloadOneofCase {
     public enum PayloadOneofCase {
@@ -194,6 +207,7 @@ namespace Conformance {
       if (JsonPayload != other.JsonPayload) return false;
       if (JsonPayload != other.JsonPayload) return false;
       if (RequestedOutputFormat != other.RequestedOutputFormat) return false;
       if (RequestedOutputFormat != other.RequestedOutputFormat) return false;
       if (MessageType != other.MessageType) return false;
       if (MessageType != other.MessageType) return false;
+      if (IgnoreUnknownJson != other.IgnoreUnknownJson) return false;
       if (PayloadCase != other.PayloadCase) return false;
       if (PayloadCase != other.PayloadCase) return false;
       return Equals(_unknownFields, other._unknownFields);
       return Equals(_unknownFields, other._unknownFields);
     }
     }
@@ -205,6 +219,7 @@ namespace Conformance {
       if (payloadCase_ == PayloadOneofCase.JsonPayload) hash ^= JsonPayload.GetHashCode();
       if (payloadCase_ == PayloadOneofCase.JsonPayload) hash ^= JsonPayload.GetHashCode();
       if (RequestedOutputFormat != 0) hash ^= RequestedOutputFormat.GetHashCode();
       if (RequestedOutputFormat != 0) hash ^= RequestedOutputFormat.GetHashCode();
       if (MessageType.Length != 0) hash ^= MessageType.GetHashCode();
       if (MessageType.Length != 0) hash ^= MessageType.GetHashCode();
+      if (IgnoreUnknownJson != false) hash ^= IgnoreUnknownJson.GetHashCode();
       hash ^= (int) payloadCase_;
       hash ^= (int) payloadCase_;
       if (_unknownFields != null) {
       if (_unknownFields != null) {
         hash ^= _unknownFields.GetHashCode();
         hash ^= _unknownFields.GetHashCode();
@@ -235,6 +250,10 @@ namespace Conformance {
         output.WriteRawTag(34);
         output.WriteRawTag(34);
         output.WriteString(MessageType);
         output.WriteString(MessageType);
       }
       }
+      if (IgnoreUnknownJson != false) {
+        output.WriteRawTag(40);
+        output.WriteBool(IgnoreUnknownJson);
+      }
       if (_unknownFields != null) {
       if (_unknownFields != null) {
         _unknownFields.WriteTo(output);
         _unknownFields.WriteTo(output);
       }
       }
@@ -255,6 +274,9 @@ namespace Conformance {
       if (MessageType.Length != 0) {
       if (MessageType.Length != 0) {
         size += 1 + pb::CodedOutputStream.ComputeStringSize(MessageType);
         size += 1 + pb::CodedOutputStream.ComputeStringSize(MessageType);
       }
       }
+      if (IgnoreUnknownJson != false) {
+        size += 1 + 1;
+      }
       if (_unknownFields != null) {
       if (_unknownFields != null) {
         size += _unknownFields.CalculateSize();
         size += _unknownFields.CalculateSize();
       }
       }
@@ -272,6 +294,9 @@ namespace Conformance {
       if (other.MessageType.Length != 0) {
       if (other.MessageType.Length != 0) {
         MessageType = other.MessageType;
         MessageType = other.MessageType;
       }
       }
+      if (other.IgnoreUnknownJson != false) {
+        IgnoreUnknownJson = other.IgnoreUnknownJson;
+      }
       switch (other.PayloadCase) {
       switch (other.PayloadCase) {
         case PayloadOneofCase.ProtobufPayload:
         case PayloadOneofCase.ProtobufPayload:
           ProtobufPayload = other.ProtobufPayload;
           ProtobufPayload = other.ProtobufPayload;
@@ -308,6 +333,10 @@ namespace Conformance {
             MessageType = input.ReadString();
             MessageType = input.ReadString();
             break;
             break;
           }
           }
+          case 40: {
+            IgnoreUnknownJson = input.ReadBool();
+            break;
+          }
         }
         }
       }
       }
     }
     }

+ 5 - 2
php/ext/google/protobuf/encode_decode.c

@@ -1587,8 +1587,11 @@ PHP_METHOD(Message, mergeFromJsonString) {
 
 
   char *data = NULL;
   char *data = NULL;
   PHP_PROTO_SIZE data_len;
   PHP_PROTO_SIZE data_len;
+  zend_bool ignore_json_unknown = false;
 
 
-  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &data_len) ==
+  if (zend_parse_parameters(
+          ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &data, &data_len,
+          &ignore_json_unknown) ==
       FAILURE) {
       FAILURE) {
     return;
     return;
   }
   }
@@ -1607,7 +1610,7 @@ PHP_METHOD(Message, mergeFromJsonString) {
     stackenv_init(&se, "Error occurred during parsing: %s");
     stackenv_init(&se, "Error occurred during parsing: %s");
 
 
     upb_sink_reset(&sink, get_fill_handlers(desc), msg);
     upb_sink_reset(&sink, get_fill_handlers(desc), msg);
-    parser = upb_json_parser_create(&se.env, method, &sink);
+    parser = upb_json_parser_create(&se.env, method, &sink, ignore_json_unknown);
     upb_bufsrc_putbuf(data, data_len, upb_json_parser_input(parser));
     upb_bufsrc_putbuf(data, data_len, upb_json_parser_input(parser));
 
 
     stackenv_uninit(&se);
     stackenv_uninit(&se);

+ 85 - 43
php/ext/google/protobuf/upb.c

@@ -14344,6 +14344,9 @@ struct upb_json_parser {
 
 
   /* Intermediate result of parsing a unicode escape sequence. */
   /* Intermediate result of parsing a unicode escape sequence. */
   uint32_t digit;
   uint32_t digit;
+
+  /* Whether to proceed if unknown field is met. */
+  bool ignore_json_unknown;
 };
 };
 
 
 struct upb_json_parsermethod {
 struct upb_json_parsermethod {
@@ -14864,6 +14867,11 @@ static bool end_number(upb_json_parser *p, const char *ptr) {
     return false;
     return false;
   }
   }
 
 
+  if (p->top->f == NULL) {
+    multipart_end(p);
+    return true;
+  }
+
   return parse_number(p, false);
   return parse_number(p, false);
 }
 }
 
 
@@ -15016,6 +15024,10 @@ static bool parse_number(upb_json_parser *p, bool is_quoted) {
 static bool parser_putbool(upb_json_parser *p, bool val) {
 static bool parser_putbool(upb_json_parser *p, bool val) {
   bool ok;
   bool ok;
 
 
+  if (p->top->f == NULL) {
+    return true;
+  }
+
   if (upb_fielddef_type(p->top->f) != UPB_TYPE_BOOL) {
   if (upb_fielddef_type(p->top->f) != UPB_TYPE_BOOL) {
     upb_status_seterrf(&p->status,
     upb_status_seterrf(&p->status,
                        "Boolean value specified for non-bool field: %s",
                        "Boolean value specified for non-bool field: %s",
@@ -15031,7 +15043,10 @@ static bool parser_putbool(upb_json_parser *p, bool val) {
 }
 }
 
 
 static bool start_stringval(upb_json_parser *p) {
 static bool start_stringval(upb_json_parser *p) {
-  UPB_ASSERT(p->top->f);
+  if (p->top->f == NULL) {
+    multipart_startaccum(p);
+    return true;
+  }
 
 
   if (upb_fielddef_isstring(p->top->f)) {
   if (upb_fielddef_isstring(p->top->f)) {
     upb_jsonparser_frame *inner;
     upb_jsonparser_frame *inner;
@@ -15082,6 +15097,11 @@ static bool start_stringval(upb_json_parser *p) {
 static bool end_stringval(upb_json_parser *p) {
 static bool end_stringval(upb_json_parser *p) {
   bool ok = true;
   bool ok = true;
 
 
+  if (p->top->f == NULL) {
+    multipart_end(p);
+    return true;
+  }
+
   switch (upb_fielddef_type(p->top->f)) {
   switch (upb_fielddef_type(p->top->f)) {
     case UPB_TYPE_BYTES:
     case UPB_TYPE_BYTES:
       if (!base64_push(p, getsel_for_handlertype(p, UPB_HANDLER_STRING),
       if (!base64_push(p, getsel_for_handlertype(p, UPB_HANDLER_STRING),
@@ -15273,6 +15293,10 @@ static bool handle_mapentry(upb_json_parser *p) {
 static bool end_membername(upb_json_parser *p) {
 static bool end_membername(upb_json_parser *p) {
   UPB_ASSERT(!p->top->f);
   UPB_ASSERT(!p->top->f);
 
 
+  if (!p->top->m) {
+    return true;
+  }
+
   if (p->top->is_map) {
   if (p->top->is_map) {
     return handle_mapentry(p);
     return handle_mapentry(p);
   } else {
   } else {
@@ -15284,10 +15308,11 @@ static bool end_membername(upb_json_parser *p) {
       p->top->f = upb_value_getconstptr(v);
       p->top->f = upb_value_getconstptr(v);
       multipart_end(p);
       multipart_end(p);
 
 
+      return true;
+    } else if (p->ignore_json_unknown) {
+      multipart_end(p);
       return true;
       return true;
     } else {
     } else {
-      /* TODO(haberman): Ignore unknown fields if requested/configured to do
-       * so. */
       upb_status_seterrf(&p->status, "No such field: %.*s\n", (int)len, buf);
       upb_status_seterrf(&p->status, "No such field: %.*s\n", (int)len, buf);
       upb_env_reporterror(p->env, &p->status);
       upb_env_reporterror(p->env, &p->status);
       return false;
       return false;
@@ -15319,7 +15344,18 @@ static void end_member(upb_json_parser *p) {
 }
 }
 
 
 static bool start_subobject(upb_json_parser *p) {
 static bool start_subobject(upb_json_parser *p) {
-  UPB_ASSERT(p->top->f);
+  if (p->top->f == NULL) {
+    upb_jsonparser_frame *inner;
+    if (!check_stack(p)) return false;
+
+    inner = p->top + 1;
+    inner->m = NULL;
+    inner->f = NULL;
+    inner->is_map = false;
+    inner->is_mapentry = false;
+    p->top = inner;
+    return true;
+  }
 
 
   if (upb_fielddef_ismap(p->top->f)) {
   if (upb_fielddef_ismap(p->top->f)) {
     upb_jsonparser_frame *inner;
     upb_jsonparser_frame *inner;
@@ -15378,9 +15414,12 @@ static void end_subobject(upb_json_parser *p) {
     upb_sink_endseq(&p->top->sink, sel);
     upb_sink_endseq(&p->top->sink, sel);
   } else {
   } else {
     upb_selector_t sel;
     upb_selector_t sel;
+    bool is_unknown = p->top->m == NULL;
     p->top--;
     p->top--;
-    sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSUBMSG);
-    upb_sink_endsubmsg(&p->top->sink, sel);
+    if (!is_unknown) {
+      sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSUBMSG);
+      upb_sink_endsubmsg(&p->top->sink, sel);
+    }
   }
   }
 }
 }
 
 
@@ -15462,11 +15501,11 @@ static void end_object(upb_json_parser *p) {
  * final state once, when the closing '"' is seen. */
  * final state once, when the closing '"' is seen. */
 
 
 
 
-#line 1310 "upb/json/parser.rl"
+#line 1349 "upb/json/parser.rl"
 
 
 
 
 
 
-#line 1222 "upb/json/parser.c"
+#line 1261 "upb/json/parser.c"
 static const char _json_actions[] = {
 static const char _json_actions[] = {
 	0, 1, 0, 1, 2, 1, 3, 1, 
 	0, 1, 0, 1, 2, 1, 3, 1, 
 	5, 1, 6, 1, 7, 1, 8, 1, 
 	5, 1, 6, 1, 7, 1, 8, 1, 
@@ -15615,7 +15654,7 @@ static const int json_en_value_machine = 27;
 static const int json_en_main = 1;
 static const int json_en_main = 1;
 
 
 
 
-#line 1313 "upb/json/parser.rl"
+#line 1352 "upb/json/parser.rl"
 
 
 size_t parse(void *closure, const void *hd, const char *buf, size_t size,
 size_t parse(void *closure, const void *hd, const char *buf, size_t size,
              const upb_bufhandle *handle) {
              const upb_bufhandle *handle) {
@@ -15637,7 +15676,7 @@ size_t parse(void *closure, const void *hd, const char *buf, size_t size,
   capture_resume(parser, buf);
   capture_resume(parser, buf);
 
 
   
   
-#line 1393 "upb/json/parser.c"
+#line 1432 "upb/json/parser.c"
 	{
 	{
 	int _klen;
 	int _klen;
 	unsigned int _trans;
 	unsigned int _trans;
@@ -15712,118 +15751,118 @@ _match:
 		switch ( *_acts++ )
 		switch ( *_acts++ )
 		{
 		{
 	case 0:
 	case 0:
-#line 1225 "upb/json/parser.rl"
+#line 1264 "upb/json/parser.rl"
 	{ p--; {cs = stack[--top]; goto _again;} }
 	{ p--; {cs = stack[--top]; goto _again;} }
 	break;
 	break;
 	case 1:
 	case 1:
-#line 1226 "upb/json/parser.rl"
+#line 1265 "upb/json/parser.rl"
 	{ p--; {stack[top++] = cs; cs = 10; goto _again;} }
 	{ p--; {stack[top++] = cs; cs = 10; goto _again;} }
 	break;
 	break;
 	case 2:
 	case 2:
-#line 1230 "upb/json/parser.rl"
+#line 1269 "upb/json/parser.rl"
 	{ start_text(parser, p); }
 	{ start_text(parser, p); }
 	break;
 	break;
 	case 3:
 	case 3:
-#line 1231 "upb/json/parser.rl"
+#line 1270 "upb/json/parser.rl"
 	{ CHECK_RETURN_TOP(end_text(parser, p)); }
 	{ CHECK_RETURN_TOP(end_text(parser, p)); }
 	break;
 	break;
 	case 4:
 	case 4:
-#line 1237 "upb/json/parser.rl"
+#line 1276 "upb/json/parser.rl"
 	{ start_hex(parser); }
 	{ start_hex(parser); }
 	break;
 	break;
 	case 5:
 	case 5:
-#line 1238 "upb/json/parser.rl"
+#line 1277 "upb/json/parser.rl"
 	{ hexdigit(parser, p); }
 	{ hexdigit(parser, p); }
 	break;
 	break;
 	case 6:
 	case 6:
-#line 1239 "upb/json/parser.rl"
+#line 1278 "upb/json/parser.rl"
 	{ CHECK_RETURN_TOP(end_hex(parser)); }
 	{ CHECK_RETURN_TOP(end_hex(parser)); }
 	break;
 	break;
 	case 7:
 	case 7:
-#line 1245 "upb/json/parser.rl"
+#line 1284 "upb/json/parser.rl"
 	{ CHECK_RETURN_TOP(escape(parser, p)); }
 	{ CHECK_RETURN_TOP(escape(parser, p)); }
 	break;
 	break;
 	case 8:
 	case 8:
-#line 1251 "upb/json/parser.rl"
+#line 1290 "upb/json/parser.rl"
 	{ p--; {cs = stack[--top]; goto _again;} }
 	{ p--; {cs = stack[--top]; goto _again;} }
 	break;
 	break;
 	case 9:
 	case 9:
-#line 1254 "upb/json/parser.rl"
+#line 1293 "upb/json/parser.rl"
 	{ {stack[top++] = cs; cs = 19; goto _again;} }
 	{ {stack[top++] = cs; cs = 19; goto _again;} }
 	break;
 	break;
 	case 10:
 	case 10:
-#line 1256 "upb/json/parser.rl"
+#line 1295 "upb/json/parser.rl"
 	{ p--; {stack[top++] = cs; cs = 27; goto _again;} }
 	{ p--; {stack[top++] = cs; cs = 27; goto _again;} }
 	break;
 	break;
 	case 11:
 	case 11:
-#line 1261 "upb/json/parser.rl"
+#line 1300 "upb/json/parser.rl"
 	{ start_member(parser); }
 	{ start_member(parser); }
 	break;
 	break;
 	case 12:
 	case 12:
-#line 1262 "upb/json/parser.rl"
+#line 1301 "upb/json/parser.rl"
 	{ CHECK_RETURN_TOP(end_membername(parser)); }
 	{ CHECK_RETURN_TOP(end_membername(parser)); }
 	break;
 	break;
 	case 13:
 	case 13:
-#line 1265 "upb/json/parser.rl"
+#line 1304 "upb/json/parser.rl"
 	{ end_member(parser); }
 	{ end_member(parser); }
 	break;
 	break;
 	case 14:
 	case 14:
-#line 1271 "upb/json/parser.rl"
+#line 1310 "upb/json/parser.rl"
 	{ start_object(parser); }
 	{ start_object(parser); }
 	break;
 	break;
 	case 15:
 	case 15:
-#line 1274 "upb/json/parser.rl"
+#line 1313 "upb/json/parser.rl"
 	{ end_object(parser); }
 	{ end_object(parser); }
 	break;
 	break;
 	case 16:
 	case 16:
-#line 1280 "upb/json/parser.rl"
+#line 1319 "upb/json/parser.rl"
 	{ CHECK_RETURN_TOP(start_array(parser)); }
 	{ CHECK_RETURN_TOP(start_array(parser)); }
 	break;
 	break;
 	case 17:
 	case 17:
-#line 1284 "upb/json/parser.rl"
+#line 1323 "upb/json/parser.rl"
 	{ end_array(parser); }
 	{ end_array(parser); }
 	break;
 	break;
 	case 18:
 	case 18:
-#line 1289 "upb/json/parser.rl"
+#line 1328 "upb/json/parser.rl"
 	{ start_number(parser, p); }
 	{ start_number(parser, p); }
 	break;
 	break;
 	case 19:
 	case 19:
-#line 1290 "upb/json/parser.rl"
+#line 1329 "upb/json/parser.rl"
 	{ CHECK_RETURN_TOP(end_number(parser, p)); }
 	{ CHECK_RETURN_TOP(end_number(parser, p)); }
 	break;
 	break;
 	case 20:
 	case 20:
-#line 1292 "upb/json/parser.rl"
+#line 1331 "upb/json/parser.rl"
 	{ CHECK_RETURN_TOP(start_stringval(parser)); }
 	{ CHECK_RETURN_TOP(start_stringval(parser)); }
 	break;
 	break;
 	case 21:
 	case 21:
-#line 1293 "upb/json/parser.rl"
+#line 1332 "upb/json/parser.rl"
 	{ CHECK_RETURN_TOP(end_stringval(parser)); }
 	{ CHECK_RETURN_TOP(end_stringval(parser)); }
 	break;
 	break;
 	case 22:
 	case 22:
-#line 1295 "upb/json/parser.rl"
+#line 1334 "upb/json/parser.rl"
 	{ CHECK_RETURN_TOP(parser_putbool(parser, true)); }
 	{ CHECK_RETURN_TOP(parser_putbool(parser, true)); }
 	break;
 	break;
 	case 23:
 	case 23:
-#line 1297 "upb/json/parser.rl"
+#line 1336 "upb/json/parser.rl"
 	{ CHECK_RETURN_TOP(parser_putbool(parser, false)); }
 	{ CHECK_RETURN_TOP(parser_putbool(parser, false)); }
 	break;
 	break;
 	case 24:
 	case 24:
-#line 1299 "upb/json/parser.rl"
+#line 1338 "upb/json/parser.rl"
 	{ /* null value */ }
 	{ /* null value */ }
 	break;
 	break;
 	case 25:
 	case 25:
-#line 1301 "upb/json/parser.rl"
+#line 1340 "upb/json/parser.rl"
 	{ CHECK_RETURN_TOP(start_subobject(parser)); }
 	{ CHECK_RETURN_TOP(start_subobject(parser)); }
 	break;
 	break;
 	case 26:
 	case 26:
-#line 1302 "upb/json/parser.rl"
+#line 1341 "upb/json/parser.rl"
 	{ end_subobject(parser); }
 	{ end_subobject(parser); }
 	break;
 	break;
 	case 27:
 	case 27:
-#line 1307 "upb/json/parser.rl"
+#line 1346 "upb/json/parser.rl"
 	{ p--; {cs = stack[--top]; goto _again;} }
 	{ p--; {cs = stack[--top]; goto _again;} }
 	break;
 	break;
-#line 1579 "upb/json/parser.c"
+#line 1618 "upb/json/parser.c"
 		}
 		}
 	}
 	}
 
 
@@ -15836,7 +15875,7 @@ _again:
 	_out: {}
 	_out: {}
 	}
 	}
 
 
-#line 1334 "upb/json/parser.rl"
+#line 1373 "upb/json/parser.rl"
 
 
   if (p != pe) {
   if (p != pe) {
     upb_status_seterrf(&parser->status, "Parse error at '%.*s'\n", pe - p, p);
     upb_status_seterrf(&parser->status, "Parse error at '%.*s'\n", pe - p, p);
@@ -15877,13 +15916,13 @@ static void json_parser_reset(upb_json_parser *p) {
 
 
   /* Emit Ragel initialization of the parser. */
   /* Emit Ragel initialization of the parser. */
   
   
-#line 1633 "upb/json/parser.c"
+#line 1672 "upb/json/parser.c"
 	{
 	{
 	cs = json_start;
 	cs = json_start;
 	top = 0;
 	top = 0;
 	}
 	}
 
 
-#line 1374 "upb/json/parser.rl"
+#line 1413 "upb/json/parser.rl"
   p->current_state = cs;
   p->current_state = cs;
   p->parser_top = top;
   p->parser_top = top;
   accumulate_clear(p);
   accumulate_clear(p);
@@ -15970,7 +16009,8 @@ static void add_jsonname_table(upb_json_parsermethod *m, const upb_msgdef* md) {
 
 
 upb_json_parser *upb_json_parser_create(upb_env *env,
 upb_json_parser *upb_json_parser_create(upb_env *env,
                                         const upb_json_parsermethod *method,
                                         const upb_json_parsermethod *method,
-                                        upb_sink *output) {
+                                        upb_sink *output,
+                                        bool ignore_json_unknown) {
 #ifndef NDEBUG
 #ifndef NDEBUG
   const size_t size_before = upb_env_bytesallocated(env);
   const size_t size_before = upb_env_bytesallocated(env);
 #endif
 #endif
@@ -15989,6 +16029,8 @@ upb_json_parser *upb_json_parser_create(upb_env *env,
   p->top->m = upb_handlers_msgdef(output->handlers);
   p->top->m = upb_handlers_msgdef(output->handlers);
   set_name_table(p, p->top);
   set_name_table(p, p->top);
 
 
+  p->ignore_json_unknown = ignore_json_unknown;
+
   /* If this fails, uncomment and increase the value in parser.h. */
   /* If this fails, uncomment and increase the value in parser.h. */
   /* fprintf(stderr, "%zd\n", upb_env_bytesallocated(env) - size_before); */
   /* fprintf(stderr, "%zd\n", upb_env_bytesallocated(env) - size_before); */
   UPB_ASSERT_DEBUGVAR(upb_env_bytesallocated(env) - size_before <=
   UPB_ASSERT_DEBUGVAR(upb_env_bytesallocated(env) - size_before <=

+ 5 - 4
php/ext/google/protobuf/upb.h

@@ -9457,7 +9457,7 @@ UPB_DECLARE_DERIVED_TYPE(upb::json::ParserMethod, upb::RefCounted,
 class upb::json::Parser {
 class upb::json::Parser {
  public:
  public:
   static Parser* Create(Environment* env, const ParserMethod* method,
   static Parser* Create(Environment* env, const ParserMethod* method,
-                        Sink* output);
+                        Sink* output, bool ignore_json_unknown);
 
 
   BytesSink* input();
   BytesSink* input();
 
 
@@ -9491,7 +9491,8 @@ UPB_BEGIN_EXTERN_C
 
 
 upb_json_parser* upb_json_parser_create(upb_env* e,
 upb_json_parser* upb_json_parser_create(upb_env* e,
                                         const upb_json_parsermethod* m,
                                         const upb_json_parsermethod* m,
-                                        upb_sink* output);
+                                        upb_sink* output,
+                                        bool ignore_json_unknown);
 upb_bytessink *upb_json_parser_input(upb_json_parser *p);
 upb_bytessink *upb_json_parser_input(upb_json_parser *p);
 
 
 upb_json_parsermethod* upb_json_parsermethod_new(const upb_msgdef* md,
 upb_json_parsermethod* upb_json_parsermethod_new(const upb_msgdef* md,
@@ -9511,8 +9512,8 @@ UPB_END_EXTERN_C
 namespace upb {
 namespace upb {
 namespace json {
 namespace json {
 inline Parser* Parser::Create(Environment* env, const ParserMethod* method,
 inline Parser* Parser::Create(Environment* env, const ParserMethod* method,
-                              Sink* output) {
-  return upb_json_parser_create(env, method, output);
+                              Sink* output, bool ignore_json_unknown) {
+  return upb_json_parser_create(env, method, output, ignore_json_unknown);
 }
 }
 inline BytesSink* Parser::input() {
 inline BytesSink* Parser::input() {
   return upb_json_parser_input(this);
   return upb_json_parser_input(this);