Web Inspector: It should be possible to initialize generated ObjC protocol types...
authorbburg@apple.com <bburg@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 7 Mar 2016 18:41:30 +0000 (18:41 +0000)
committerbburg@apple.com <bburg@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 7 Mar 2016 18:41:30 +0000 (18:41 +0000)
https://bugs.webkit.org/show_bug.cgi?id=155102
<rdar://problem/25002015>

Reviewed by Timothy Hatcher.

In Objective-C code, we sometimes prefer to parse JSON using Cocoa rather
than the InspectorValue classes. Support initializing protocol objects
directly from an NSDictionary payload. This delegates validation of values to
the setter methods that already exist on the protocol object classes.

* inspector/scripts/codegen/generate_objc_header.py:
(ObjCHeaderGenerator._generate_type_interface):
* inspector/scripts/codegen/generate_objc_protocol_types_implementation.py:
(ObjCProtocolTypesImplementationGenerator.generate_type_implementation):
(ObjCProtocolTypesImplementationGenerator._generate_init_method_for_payload):
* inspector/scripts/codegen/objc_generator.py:
(ObjCGenerator.payload_to_objc_expression_for_member):
Add a new helper method to generate an expression to unpack the value
from an NSDictionary. If it's not a primitive, the setter performs
validation of the value's kind using -[NSObject isKindOfClass:].

Rebaseline relevant tests.

* inspector/scripts/tests/expected/commands-with-async-attribute.json-result:
* inspector/scripts/tests/expected/commands-with-optional-call-return-parameters.json-result:
* inspector/scripts/tests/expected/events-with-optional-parameters.json-result:
* inspector/scripts/tests/expected/generate-domains-with-feature-guards.json-result:
* inspector/scripts/tests/expected/shadowed-optional-type-setters.json-result:
* inspector/scripts/tests/expected/type-declaration-object-type.json-result:
* inspector/scripts/tests/expected/type-requiring-runtime-casts.json-result:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@197689 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/inspector/scripts/codegen/generate_objc_header.py
Source/JavaScriptCore/inspector/scripts/codegen/generate_objc_protocol_types_implementation.py
Source/JavaScriptCore/inspector/scripts/codegen/objc_generator.py
Source/JavaScriptCore/inspector/scripts/tests/expected/commands-with-async-attribute.json-result
Source/JavaScriptCore/inspector/scripts/tests/expected/commands-with-optional-call-return-parameters.json-result
Source/JavaScriptCore/inspector/scripts/tests/expected/events-with-optional-parameters.json-result
Source/JavaScriptCore/inspector/scripts/tests/expected/generate-domains-with-feature-guards.json-result
Source/JavaScriptCore/inspector/scripts/tests/expected/shadowed-optional-type-setters.json-result
Source/JavaScriptCore/inspector/scripts/tests/expected/type-declaration-object-type.json-result
Source/JavaScriptCore/inspector/scripts/tests/expected/type-requiring-runtime-casts.json-result

index bd85c28..59797ce 100644 (file)
@@ -1,3 +1,37 @@
+2016-03-07  Brian Burg  <bburg@apple.com>
+
+        Web Inspector: It should be possible to initialize generated ObjC protocol types from an NSDictionary payload
+        https://bugs.webkit.org/show_bug.cgi?id=155102
+        <rdar://problem/25002015>
+
+        Reviewed by Timothy Hatcher.
+
+        In Objective-C code, we sometimes prefer to parse JSON using Cocoa rather
+        than the InspectorValue classes. Support initializing protocol objects
+        directly from an NSDictionary payload. This delegates validation of values to
+        the setter methods that already exist on the protocol object classes.
+
+        * inspector/scripts/codegen/generate_objc_header.py:
+        (ObjCHeaderGenerator._generate_type_interface):
+        * inspector/scripts/codegen/generate_objc_protocol_types_implementation.py:
+        (ObjCProtocolTypesImplementationGenerator.generate_type_implementation):
+        (ObjCProtocolTypesImplementationGenerator._generate_init_method_for_payload):
+        * inspector/scripts/codegen/objc_generator.py:
+        (ObjCGenerator.payload_to_objc_expression_for_member):
+        Add a new helper method to generate an expression to unpack the value
+        from an NSDictionary. If it's not a primitive, the setter performs
+        validation of the value's kind using -[NSObject isKindOfClass:].
+
+        Rebaseline relevant tests.
+
+        * inspector/scripts/tests/expected/commands-with-async-attribute.json-result:
+        * inspector/scripts/tests/expected/commands-with-optional-call-return-parameters.json-result:
+        * inspector/scripts/tests/expected/events-with-optional-parameters.json-result:
+        * inspector/scripts/tests/expected/generate-domains-with-feature-guards.json-result:
+        * inspector/scripts/tests/expected/shadowed-optional-type-setters.json-result:
+        * inspector/scripts/tests/expected/type-declaration-object-type.json-result:
+        * inspector/scripts/tests/expected/type-requiring-runtime-casts.json-result:
+
 2016-03-07  Benjamin Poulain  <benjamin@webkit.org>
 
         [JSC] Simplify the overflow check of ArithAbs
index 58259f4..8386f38 100755 (executable)
@@ -159,6 +159,11 @@ class ObjCHeaderGenerator(ObjCGenerator):
         objc_name = self.objc_name_for_type(declaration.type)
         lines.append('__attribute__((visibility ("default")))')
         lines.append('@interface %s : %sJSONObject' % (objc_name, ObjCGenerator.OBJC_STATIC_PREFIX))
+
+        # The initializer that takes a payload is only needed by the frontend.
+        if self.get_generator_setting('generate_frontend', False):
+            lines.append('- (instancetype)initWithPayload:(NSDictionary<NSString *, id> *)payload;')
+
         required_members = filter(lambda member: not member.is_optional, declaration.type_members)
         optional_members = filter(lambda member: member.is_optional, declaration.type_members)
         if required_members:
index 1043554..eaa5506 100755 (executable)
@@ -90,6 +90,10 @@ class ObjCProtocolTypesImplementationGenerator(ObjCGenerator):
     def generate_type_implementation(self, domain, declaration):
         lines = []
         lines.append('@implementation %s' % self.objc_name_for_type(declaration.type))
+        # The initializer that takes a payload is only needed by the frontend.
+        if self.get_generator_setting('generate_frontend', False):
+            lines.append('')
+            lines.append(self._generate_init_method_for_payload(domain, declaration))
         required_members = filter(lambda member: not member.is_optional, declaration.type_members)
         if required_members:
             lines.append('')
@@ -103,6 +107,26 @@ class ObjCProtocolTypesImplementationGenerator(ObjCGenerator):
         lines.append('@end')
         return '\n'.join(lines)
 
+    def _generate_init_method_for_payload(self, domain, declaration):
+        lines = []
+        lines.append('- (instancetype)initWithPayload:(nonnull NSDictionary<NSString *, id> *)payload')
+        lines.append('{')
+        lines.append('    if (!(self = [super init]))')
+        lines.append('        return nil;')
+        lines.append('')
+
+        for member in declaration.type_members:
+            var_name = ObjCGenerator.identifier_to_objc_identifier(member.member_name)
+            if not member.is_optional:
+                lines.append('    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"%s"], @"%s");' % (var_name, var_name))
+            conversion_expression = self.payload_to_objc_expression_for_member(declaration, member)
+            lines.append('    self.%s = %s;' % (var_name, conversion_expression))
+            lines.append('')
+
+        lines.append('    return self;')
+        lines.append('}')
+        return '\n'.join(lines)
+
     def _generate_init_method_for_required_members(self, domain, declaration, required_members):
         pairs = []
         for member in required_members:
index 2399e7a..29ff4a0 100755 (executable)
@@ -457,6 +457,31 @@ class ObjCGenerator(Generator):
                 return 'objcIntegerArray(%s)' % sub_expression
             return 'objcArray<%s>(%s)' % (objc_class, sub_expression)
 
+    def payload_to_objc_expression_for_member(self, declaration, member):
+        _type = member.type
+        if isinstance(_type, AliasedType):
+            _type = _type.aliased_type
+        if isinstance(_type, PrimitiveType):
+            sub_expression = 'payload[@"%s"]' % member.member_name
+            raw_name = _type.raw_name()
+            if raw_name is 'boolean':
+                return '[%s boolValue]' % sub_expression
+            if raw_name is 'integer':
+                return '[%s integerValue]' % sub_expression
+            if raw_name is 'number':
+                return '[%s doubleValue]' % sub_expression
+            if raw_name in ['any', 'object', 'array', 'string']:
+                return sub_expression  # The setter will check the incoming value.
+            return None
+        if isinstance(member.type, EnumType):
+            sub_expression = 'payload[@"%s"]' % member.member_name
+            if member.type.is_anonymous:
+                return 'fromProtocolString<%s>(%s)' % (self.objc_enum_name_for_anonymous_enum_member(declaration, member), sub_expression)
+            else:
+                return 'fromProtocolString<%s>(%s)' % (self.objc_enum_name_for_non_anonymous_enum(member.type), sub_expression)
+        if isinstance(_type, (ObjectType, ArrayType)):
+            return 'payload[@"%s"]' % member.member_name
+
     # JSON object setter/getter selectors for types.
 
     @staticmethod
index 9699d83..36ed489 100644 (file)
@@ -1489,6 +1489,7 @@ typedef NS_ENUM(NSInteger, TestProtocolDatabaseExecuteSQLAsyncPrintColor) {
 
 __attribute__((visibility ("default")))
 @interface TestProtocolDatabaseError : RWIProtocolJSONObject
+- (instancetype)initWithPayload:(NSDictionary<NSString *, id> *)payload;
 - (instancetype)initWithMessage:(NSString *)message code:(int)code;
 /* required */ @property (nonatomic, copy) NSString *message;
 /* required */ @property (nonatomic, assign) int code;
@@ -1592,6 +1593,20 @@ using namespace Inspector;
 
 @implementation TestProtocolDatabaseError
 
+- (instancetype)initWithPayload:(nonnull NSDictionary<NSString *, id> *)payload
+{
+    if (!(self = [super init]))
+        return nil;
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"message"], @"message");
+    self.message = payload[@"message"];
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"code"], @"code");
+    self.code = [payload[@"code"] integerValue];
+
+    return self;
+}
+
 - (instancetype)initWithMessage:(NSString *)message code:(int)code;
 {
     self = [super init];
index 5f55a26..f7e30b9 100644 (file)
@@ -1346,6 +1346,7 @@ typedef NS_ENUM(NSInteger, TestProtocolDatabaseExecuteNoOptionalParametersPrintC
 
 __attribute__((visibility ("default")))
 @interface TestProtocolDatabaseError : RWIProtocolJSONObject
+- (instancetype)initWithPayload:(NSDictionary<NSString *, id> *)payload;
 - (instancetype)initWithMessage:(NSString *)message code:(int)code;
 /* required */ @property (nonatomic, copy) NSString *message;
 /* required */ @property (nonatomic, assign) int code;
@@ -1447,6 +1448,20 @@ using namespace Inspector;
 
 @implementation TestProtocolDatabaseError
 
+- (instancetype)initWithPayload:(nonnull NSDictionary<NSString *, id> *)payload
+{
+    if (!(self = [super init]))
+        return nil;
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"message"], @"message");
+    self.message = payload[@"message"];
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"code"], @"code");
+    self.code = [payload[@"code"] integerValue];
+
+    return self;
+}
+
 - (instancetype)initWithMessage:(NSString *)message code:(int)code;
 {
     self = [super init];
index 7fb5353..9770dcf 100644 (file)
@@ -962,6 +962,7 @@ using namespace Inspector;
 
 __attribute__((visibility ("default")))
 @interface TestProtocolDatabaseError : RWIProtocolJSONObject
+- (instancetype)initWithPayload:(NSDictionary<NSString *, id> *)payload;
 - (instancetype)initWithMessage:(NSString *)message code:(int)code;
 /* required */ @property (nonatomic, copy) NSString *message;
 /* required */ @property (nonatomic, assign) int code;
@@ -1065,6 +1066,20 @@ using namespace Inspector;
 
 @implementation TestProtocolDatabaseError
 
+- (instancetype)initWithPayload:(nonnull NSDictionary<NSString *, id> *)payload
+{
+    if (!(self = [super init]))
+        return nil;
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"message"], @"message");
+    self.message = payload[@"message"];
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"code"], @"code");
+    self.code = [payload[@"code"] integerValue];
+
+    return self;
+}
+
 - (instancetype)initWithMessage:(NSString *)message code:(int)code;
 {
     self = [super init];
index 617c045..c04f88d 100644 (file)
@@ -1013,6 +1013,7 @@ using namespace Inspector;
 
 __attribute__((visibility ("default")))
 @interface TestProtocolNetwork2NetworkError : RWIProtocolJSONObject
+- (instancetype)initWithPayload:(NSDictionary<NSString *, id> *)payload;
 - (instancetype)initWithMessage:(NSString *)message code:(int)code;
 /* required */ @property (nonatomic, copy) NSString *message;
 /* required */ @property (nonatomic, assign) int code;
@@ -1120,6 +1121,20 @@ using namespace Inspector;
 
 @implementation TestProtocolNetwork2NetworkError
 
+- (instancetype)initWithPayload:(nonnull NSDictionary<NSString *, id> *)payload
+{
+    if (!(self = [super init]))
+        return nil;
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"message"], @"message");
+    self.message = payload[@"message"];
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"code"], @"code");
+    self.code = [payload[@"code"] integerValue];
+
+    return self;
+}
+
 - (instancetype)initWithMessage:(NSString *)message code:(int)code;
 {
     self = [super init];
index 924965d..74c77c2 100644 (file)
@@ -840,6 +840,7 @@ typedef NS_ENUM(NSInteger, TestProtocolRuntimeKeyPathType) {
 
 __attribute__((visibility ("default")))
 @interface TestProtocolRuntimeKeyPath : RWIProtocolJSONObject
+- (instancetype)initWithPayload:(NSDictionary<NSString *, id> *)payload;
 - (instancetype)initWithType:(TestProtocolRuntimeKeyPathType)type;
 /* required */ @property (nonatomic, assign) TestProtocolRuntimeKeyPathType type;
 /* optional */ @property (nonatomic, copy) NSString *string;
@@ -938,6 +939,21 @@ using namespace Inspector;
 
 @implementation TestProtocolRuntimeKeyPath
 
+- (instancetype)initWithPayload:(nonnull NSDictionary<NSString *, id> *)payload
+{
+    if (!(self = [super init]))
+        return nil;
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"type"], @"type");
+    self.type = fromProtocolString<TestProtocolRuntimeKeyPathType>(payload[@"type"]);
+
+    self.string = payload[@"string"];
+
+    self.array = payload[@"array"];
+
+    return self;
+}
+
 - (instancetype)initWithType:(TestProtocolRuntimeKeyPathType)type;
 {
     self = [super init];
index bda5f86..2cc791a 100644 (file)
@@ -1211,6 +1211,7 @@ using namespace Inspector;
 
 __attribute__((visibility ("default")))
 @interface TestProtocolDatabaseError : RWIProtocolJSONObject
+- (instancetype)initWithPayload:(NSDictionary<NSString *, id> *)payload;
 - (instancetype)initWithMessage:(NSString *)message code:(int)code;
 /* required */ @property (nonatomic, copy) NSString *message;
 /* required */ @property (nonatomic, assign) int code;
@@ -1218,6 +1219,7 @@ __attribute__((visibility ("default")))
 
 __attribute__((visibility ("default")))
 @interface TestProtocolDatabaseOptionalParameterBundle : RWIProtocolJSONObject
+- (instancetype)initWithPayload:(NSDictionary<NSString *, id> *)payload;
 /* optional */ @property (nonatomic, copy) NSArray/*<NSString>*/ *columnNames;
 /* optional */ @property (nonatomic, copy) NSString *notes;
 /* optional */ @property (nonatomic, assign) double timestamp;
@@ -1229,6 +1231,7 @@ __attribute__((visibility ("default")))
 
 __attribute__((visibility ("default")))
 @interface TestProtocolDatabaseParameterBundle : RWIProtocolJSONObject
+- (instancetype)initWithPayload:(NSDictionary<NSString *, id> *)payload;
 - (instancetype)initWithColumnNames:(NSArray/*<NSString>*/ *)columnNames notes:(NSString *)notes timestamp:(double)timestamp values:(RWIProtocolJSONObject *)values payload:(RWIProtocolJSONObject *)payload error:(TestProtocolDatabaseError *)error errorList:(NSArray/*<TestProtocolDatabaseError>*/ *)errorList;
 /* required */ @property (nonatomic, copy) NSArray/*<NSString>*/ *columnNames;
 /* required */ @property (nonatomic, copy) NSString *notes;
@@ -1241,6 +1244,7 @@ __attribute__((visibility ("default")))
 
 __attribute__((visibility ("default")))
 @interface TestProtocolDatabaseObjectWithPropertyNameConflicts : RWIProtocolJSONObject
+- (instancetype)initWithPayload:(NSDictionary<NSString *, id> *)payload;
 - (instancetype)initWithInteger:(NSString *)integer array:(NSString *)array string:(NSString *)string value:(NSString *)value object:(NSString *)object;
 /* required */ @property (nonatomic, copy) NSString *integer;
 /* required */ @property (nonatomic, copy) NSString *array;
@@ -1251,10 +1255,12 @@ __attribute__((visibility ("default")))
 
 __attribute__((visibility ("default")))
 @interface TestProtocolDatabaseDummyObject : RWIProtocolJSONObject
+- (instancetype)initWithPayload:(NSDictionary<NSString *, id> *)payload;
 @end
 
 __attribute__((visibility ("default")))
 @interface TestProtocolTestParameterBundle : RWIProtocolJSONObject
+- (instancetype)initWithPayload:(NSDictionary<NSString *, id> *)payload;
 - (instancetype)initWithColumnNames:(NSArray/*<NSString>*/ *)columnNames notes:(NSString *)notes timestamp:(double)timestamp values:(RWIProtocolJSONObject *)values payload:(RWIProtocolJSONObject *)payload error:(TestProtocolDatabaseError *)error;
 /* required */ @property (nonatomic, copy) NSArray/*<NSString>*/ *columnNames;
 /* required */ @property (nonatomic, copy) NSString *notes;
@@ -1356,6 +1362,20 @@ using namespace Inspector;
 
 @implementation TestProtocolDatabaseError
 
+- (instancetype)initWithPayload:(nonnull NSDictionary<NSString *, id> *)payload
+{
+    if (!(self = [super init]))
+        return nil;
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"message"], @"message");
+    self.message = payload[@"message"];
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"code"], @"code");
+    self.code = [payload[@"code"] integerValue];
+
+    return self;
+}
+
 - (instancetype)initWithMessage:(NSString *)message code:(int)code;
 {
     self = [super init];
@@ -1394,6 +1414,28 @@ using namespace Inspector;
 
 @implementation TestProtocolDatabaseOptionalParameterBundle
 
+- (instancetype)initWithPayload:(nonnull NSDictionary<NSString *, id> *)payload
+{
+    if (!(self = [super init]))
+        return nil;
+
+    self.columnNames = payload[@"columnNames"];
+
+    self.notes = payload[@"notes"];
+
+    self.timestamp = [payload[@"timestamp"] doubleValue];
+
+    self.values = payload[@"values"];
+
+    self.payload = payload[@"payload"];
+
+    self.error = payload[@"error"];
+
+    self.errorList = payload[@"errorList"];
+
+    return self;
+}
+
 - (void)setColumnNames:(NSArray/*<NSString>*/ *)columnNames
 {
     [super setInspectorArray:inspectorStringArray(columnNames) forKey:@"columnNames"];
@@ -1469,6 +1511,35 @@ using namespace Inspector;
 
 @implementation TestProtocolDatabaseParameterBundle
 
+- (instancetype)initWithPayload:(nonnull NSDictionary<NSString *, id> *)payload
+{
+    if (!(self = [super init]))
+        return nil;
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"columnNames"], @"columnNames");
+    self.columnNames = payload[@"columnNames"];
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"notes"], @"notes");
+    self.notes = payload[@"notes"];
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"timestamp"], @"timestamp");
+    self.timestamp = [payload[@"timestamp"] doubleValue];
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"values"], @"values");
+    self.values = payload[@"values"];
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"payload"], @"payload");
+    self.payload = payload[@"payload"];
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"error"], @"error");
+    self.error = payload[@"error"];
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"errorList"], @"errorList");
+    self.errorList = payload[@"errorList"];
+
+    return self;
+}
+
 - (instancetype)initWithColumnNames:(NSArray/*<NSString>*/ *)columnNames notes:(NSString *)notes timestamp:(double)timestamp values:(RWIProtocolJSONObject *)values payload:(RWIProtocolJSONObject *)payload error:(TestProtocolDatabaseError *)error errorList:(NSArray/*<TestProtocolDatabaseError>*/ *)errorList;
 {
     self = [super init];
@@ -1569,6 +1640,29 @@ using namespace Inspector;
 
 @implementation TestProtocolDatabaseObjectWithPropertyNameConflicts
 
+- (instancetype)initWithPayload:(nonnull NSDictionary<NSString *, id> *)payload
+{
+    if (!(self = [super init]))
+        return nil;
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"integer"], @"integer");
+    self.integer = payload[@"integer"];
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"array"], @"array");
+    self.array = payload[@"array"];
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"string"], @"string");
+    self.string = payload[@"string"];
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"value"], @"value");
+    self.value = payload[@"value"];
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"object"], @"object");
+    self.object = payload[@"object"];
+
+    return self;
+}
+
 - (instancetype)initWithInteger:(NSString *)integer array:(NSString *)array string:(NSString *)string value:(NSString *)value object:(NSString *)object;
 {
     self = [super init];
@@ -1644,11 +1738,45 @@ using namespace Inspector;
 
 @implementation TestProtocolDatabaseDummyObject
 
+- (instancetype)initWithPayload:(nonnull NSDictionary<NSString *, id> *)payload
+{
+    if (!(self = [super init]))
+        return nil;
+
+    return self;
+}
+
 @end
 
 
 @implementation TestProtocolTestParameterBundle
 
+- (instancetype)initWithPayload:(nonnull NSDictionary<NSString *, id> *)payload
+{
+    if (!(self = [super init]))
+        return nil;
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"columnNames"], @"columnNames");
+    self.columnNames = payload[@"columnNames"];
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"notes"], @"notes");
+    self.notes = payload[@"notes"];
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"timestamp"], @"timestamp");
+    self.timestamp = [payload[@"timestamp"] doubleValue];
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"values"], @"values");
+    self.values = payload[@"values"];
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"payload"], @"payload");
+    self.payload = payload[@"payload"];
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"error"], @"error");
+    self.error = payload[@"error"];
+
+    return self;
+}
+
 - (instancetype)initWithColumnNames:(NSArray/*<NSString>*/ *)columnNames notes:(NSString *)notes timestamp:(double)timestamp values:(RWIProtocolJSONObject *)values payload:(RWIProtocolJSONObject *)payload error:(TestProtocolDatabaseError *)error;
 {
     self = [super init];
index 1800ed6..685ccd3 100644 (file)
@@ -1161,6 +1161,7 @@ typedef NS_ENUM(NSInteger, TestProtocolTestCastedAnimals) {
 
 __attribute__((visibility ("default")))
 @interface TestProtocolTestTypeNeedingCast : RWIProtocolJSONObject
+- (instancetype)initWithPayload:(NSDictionary<NSString *, id> *)payload;
 - (instancetype)initWithString:(NSString *)string number:(int)number animals:(TestProtocolTestCastedAnimals)animals identifier:(int)identifier tree:(TestProtocolTestRecursiveObject1 *)tree;
 /* required */ @property (nonatomic, copy) NSString *string;
 /* required */ @property (nonatomic, assign) int number;
@@ -1171,11 +1172,13 @@ __attribute__((visibility ("default")))
 
 __attribute__((visibility ("default")))
 @interface TestProtocolTestRecursiveObject1 : RWIProtocolJSONObject
+- (instancetype)initWithPayload:(NSDictionary<NSString *, id> *)payload;
 /* optional */ @property (nonatomic, retain) TestProtocolTestRecursiveObject2 *obj;
 @end
 
 __attribute__((visibility ("default")))
 @interface TestProtocolTestRecursiveObject2 : RWIProtocolJSONObject
+- (instancetype)initWithPayload:(NSDictionary<NSString *, id> *)payload;
 /* optional */ @property (nonatomic, retain) TestProtocolTestRecursiveObject1 *obj;
 @end
 
@@ -1271,6 +1274,29 @@ using namespace Inspector;
 
 @implementation TestProtocolTestTypeNeedingCast
 
+- (instancetype)initWithPayload:(nonnull NSDictionary<NSString *, id> *)payload
+{
+    if (!(self = [super init]))
+        return nil;
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"string"], @"string");
+    self.string = payload[@"string"];
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"number"], @"number");
+    self.number = [payload[@"number"] integerValue];
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"animals"], @"animals");
+    self.animals = fromProtocolString<TestProtocolTestCastedAnimals>(payload[@"animals"]);
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"identifier"], @"identifier");
+    self.identifier = [payload[@"id"] integerValue];
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"tree"], @"tree");
+    self.tree = payload[@"tree"];
+
+    return self;
+}
+
 - (instancetype)initWithString:(NSString *)string number:(int)number animals:(TestProtocolTestCastedAnimals)animals identifier:(int)identifier tree:(TestProtocolTestRecursiveObject1 *)tree;
 {
     self = [super init];
@@ -1343,6 +1369,16 @@ using namespace Inspector;
 
 @implementation TestProtocolTestRecursiveObject1
 
+- (instancetype)initWithPayload:(nonnull NSDictionary<NSString *, id> *)payload
+{
+    if (!(self = [super init]))
+        return nil;
+
+    self.obj = payload[@"obj"];
+
+    return self;
+}
+
 - (void)setObj:(TestProtocolTestRecursiveObject2 *)obj
 {
     [super setObject:obj forKey:@"obj"];
@@ -1357,6 +1393,16 @@ using namespace Inspector;
 
 @implementation TestProtocolTestRecursiveObject2
 
+- (instancetype)initWithPayload:(nonnull NSDictionary<NSString *, id> *)payload
+{
+    if (!(self = [super init]))
+        return nil;
+
+    self.obj = payload[@"obj"];
+
+    return self;
+}
+
 - (void)setObj:(TestProtocolTestRecursiveObject1 *)obj
 {
     [super setObject:obj forKey:@"obj"];