From a53b0e29098725ecc20e8355e955c1307ce3dd8d Mon Sep 17 00:00:00 2001 From: Maros Marsalek Date: Fri, 16 Sep 2016 16:17:58 +0200 Subject: VPP-413 DTOs generated by JVpp improvements: - hashCode & equals - toString Change-Id: I5f8bc8868c216862a307dcc8f6b423f0ce29e7b5 Signed-off-by: Maros Marsalek --- vpp-api/java/jvpp/gen/jvppgen/dto_gen.py | 187 ++++++++++++++++++++++++++----- vpp-api/java/jvpp/gen/jvppgen/util.py | 6 + 2 files changed, 162 insertions(+), 31 deletions(-) (limited to 'vpp-api/java/jvpp') diff --git a/vpp-api/java/jvpp/gen/jvppgen/dto_gen.py b/vpp-api/java/jvpp/gen/jvppgen/dto_gen.py index 785e47e9ef7..0f74a1dedd9 100644 --- a/vpp-api/java/jvpp/gen/jvppgen/dto_gen.py +++ b/vpp-api/java/jvpp/gen/jvppgen/dto_gen.py @@ -40,7 +40,7 @@ field_template = Template(""" public $type $name;\n""") send_template = Template(""" @Override public int send(final $base_package.JVpp jvpp) throws org.openvpp.jvpp.VppInvocationException { return (($plugin_package.JVpp${plugin_name})jvpp).$method_name($args); - }\n""") + }""") def generate_dtos(func_list, base_package, plugin_package, plugin_name, dto_package, inputfile): @@ -58,15 +58,8 @@ def generate_dtos(func_list, base_package, plugin_package, plugin_name, dto_pack if util.is_ignored(func['name']) or util.is_control_ping(camel_case_dto_name): continue - fields = "" - for t in zip(func['types'], func['args']): - # for retval don't generate dto field in Reply - field_name = util.underscore_to_camelcase(t[1]) - if util.is_reply(camel_case_dto_name) and util.is_retval_field(field_name): - continue - fields += field_template.substitute(type=util.jni_2_java_type_mapping[t[0]], - name=field_name) - methods = "" + fields = generate_dto_fields(camel_case_dto_name, func) + methods = generate_dto_base_methods(camel_case_dto_name, func) base_type = "" # Generate request/reply or dump/dumpReply even if structure can be used as notification @@ -77,17 +70,17 @@ def generate_dtos(func_list, base_package, plugin_package, plugin_name, dto_pack if util.is_details(camel_case_dto_name): # FIXME assumption that dump calls end with "Dump" suffix. Not enforced in vpe.api base_type += "JVppReply<%s.%s.%s>" % (plugin_package, dto_package, request_dto_name + "Dump") - generate_dump_reply_dto(request_dto_name, base_package, plugin_package, dto_package, camel_case_dto_name, - camel_case_method_name, func) + generate_dump_reply_dto(request_dto_name, base_package, plugin_package, dto_package, + camel_case_dto_name, camel_case_method_name, func) else: base_type += "JVppReply<%s.%s.%s>" % (plugin_package, dto_package, request_dto_name) else: args = "" if fields is "" else "this" - methods = send_template.substitute(method_name=camel_case_method_name, - base_package=base_package, - plugin_package=plugin_package, - plugin_name=plugin_name, - args=args) + methods += send_template.substitute(method_name=camel_case_method_name, + base_package=base_package, + plugin_package=plugin_package, + plugin_name=plugin_name, + args=args) if util.is_dump(camel_case_dto_name): base_type += "JVppDump" description = "dump request DTO" @@ -95,24 +88,143 @@ def generate_dtos(func_list, base_package, plugin_package, plugin_name, dto_pack base_type += "JVppRequest" description = "request DTO" - write_dto_file(base_package, plugin_package, base_type, camel_case_dto_name, description, dto_package, dto_path, fields, func, - inputfile, methods) + write_dto_file(base_package, plugin_package, base_type, camel_case_dto_name, description, dto_package, + dto_path, fields, func, inputfile, methods) # for structures that are also used as notifications, generate dedicated notification DTO if util.is_notification(func["name"]): base_type = "JVppNotification" description = "notification DTO" camel_case_dto_name = util.add_notification_suffix(camel_case_dto_name) - methods = "" dto_path = os.path.join(dto_package, camel_case_dto_name + ".java") - write_dto_file(base_package, plugin_package, base_type, camel_case_dto_name, description, dto_package, dto_path, fields, func, - inputfile, methods) + methods = generate_dto_base_methods(camel_case_dto_name, func) + write_dto_file(base_package, plugin_package, base_type, camel_case_dto_name, description, dto_package, + dto_path, fields, func, inputfile, methods) flush_dump_reply_dtos(inputfile) -def write_dto_file(base_package, plugin_package, base_type, camel_case_dto_name, description, dto_package, dto_path, fields, func, - inputfile, methods): +def generate_dto_base_methods(camel_case_dto_name, func): + methods = generate_dto_hash(func) + methods += generate_dto_equals(camel_case_dto_name, func) + methods += generate_dto_tostring(camel_case_dto_name, func) + return methods + + +def generate_dto_fields(camel_case_dto_name, func): + fields = "" + for t in zip(func['types'], func['args']): + # for retval don't generate dto field in Reply + field_name = util.underscore_to_camelcase(t[1]) + if util.is_reply(camel_case_dto_name) and util.is_retval_field(field_name): + continue + fields += field_template.substitute(type=util.jni_2_java_type_mapping[t[0]], + name=field_name) + return fields + + +tostring_field_template = Template(""" \"$field_name=\" + $field_name + ", " +\n""") +tostring_array_field_template = Template(""" \"$field_name=\" + java.util.Arrays.toString($field_name) + ", " +\n""") +tostring_template = Template(""" @Override + public String toString() { + return "$cls_name{" + +$fields_tostring "}"; + }\n\n""") + + +def generate_dto_tostring(camel_case_dto_name, func): + tostring_fields = "" + for t in zip(func['types'], func['args']): + + field_name = util.underscore_to_camelcase(t[1]) + # for retval don't generate dto field in Reply + if util.is_retval_field(field_name): + continue + + # handle array types + if util.is_array(util.jni_2_java_type_mapping[t[0]]): + tostring_fields += tostring_array_field_template.substitute(field_name=field_name) + else: + tostring_fields += tostring_field_template.substitute(field_name=field_name) + + return tostring_template.substitute(cls_name=camel_case_dto_name, + fields_tostring=tostring_fields[:-8]) + + +equals_field_template = Template(""" if (!java.util.Objects.equals(this.$field_name, other.$field_name)) { + return false; + }\n""") +equals_array_field_template = Template(""" if (!java.util.Arrays.equals(this.$field_name, other.$field_name)) { + return false; + }\n""") +equals_template = Template(""" @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + final $cls_name other = ($cls_name) o; + +$comparisons + return true; + }\n\n""") + + +def generate_dto_equals(camel_case_dto_name, func): + equals_fields = "" + for t in zip(func['types'], func['args']): + field_name = util.underscore_to_camelcase(t[1]) + # for retval don't generate dto field in Reply + if util.is_retval_field(field_name): + continue + + # handle array types + if util.is_array(util.jni_2_java_type_mapping[t[0]]): + equals_fields += equals_array_field_template.substitute(field_name=field_name) + else: + equals_fields += equals_field_template.substitute(field_name=field_name) + + return equals_template.substitute(cls_name=camel_case_dto_name, + comparisons=equals_fields) + + +hash_template = Template(""" @Override + public int hashCode() { + return java.util.Objects.hash($fields); + }\n\n""") +hash_single_array_type_template = Template(""" @Override + public int hashCode() { + return java.util.Arrays.hashCode($fields); + }\n\n""") + + +def generate_dto_hash(func): + hash_fields = "" + + # Special handling for hashCode in case just a single array field is present. Cannot use Objects.equals since the + # array is mistaken for a varargs parameter. Instead use Arrays.hashCode in such case. + if len(func['args']) == 1: + single_type = func['types'][0] + single_type_name = func['args'][0] + if util.is_array(util.jni_2_java_type_mapping[single_type]): + return hash_single_array_type_template.substitute(fields=util.underscore_to_camelcase(single_type_name)) + + for t in zip(func['types'], func['args']): + field_name = util.underscore_to_camelcase(t[1]) + # for retval don't generate dto field in Reply + if util.is_retval_field(field_name): + continue + + hash_fields += field_name + ", " + + return hash_template.substitute(fields=hash_fields[:-2]) + + +def write_dto_file(base_package, plugin_package, base_type, camel_case_dto_name, description, dto_package, dto_path, + fields, func, inputfile, methods): dto_file = open(dto_path, 'w') dto_file.write(dto_template.substitute(inputfile=inputfile, description=description, @@ -131,6 +243,7 @@ def write_dto_file(base_package, plugin_package, base_type, camel_case_dto_name, dump_dto_suffix = "ReplyDump" dump_reply_artificial_dtos = {} + # Returns request name or special one from unconventional_naming_rep_req map def get_request_name(camel_case_dto_name, func_name): return util.underscore_to_camelcase_upper( @@ -157,26 +270,38 @@ def flush_dump_reply_dtos(inputfile): dto_file.close() -def generate_dump_reply_dto(request_dto_name, base_package, plugin_package, dto_package, camel_case_dto_name, camel_case_method_name, - func): +def generate_dump_reply_dto(request_dto_name, base_package, plugin_package, dto_package, camel_case_dto_name, + camel_case_method_name, func): base_type = "JVppReplyDump<%s.%s.%s, %s.%s.%s>" % ( plugin_package, dto_package, util.remove_reply_suffix(camel_case_dto_name) + "Dump", plugin_package, dto_package, camel_case_dto_name) fields = " public java.util.List<%s> %s = new java.util.ArrayList<>();" % (camel_case_dto_name, camel_case_method_name) cls_name = camel_case_dto_name + dump_dto_suffix + # using artificial type for fields, just to bypass the is_array check in base methods generators + # the type is not really used + artificial_type = 'jstring' # In case of already existing artificial reply dump DTO, just update it # Used for sub-dump dtos if request_dto_name in dump_reply_artificial_dtos.keys(): - dump_reply_artificial_dtos[request_dto_name]['fields'] = \ - dump_reply_artificial_dtos[request_dto_name]['fields'] + '\n' + fields + dump_reply_artificial_dtos[request_dto_name]['fields'] += '\n' + fields + dump_reply_artificial_dtos[request_dto_name]['field_names'].append(func['name']) + dump_reply_artificial_dtos[request_dto_name]['field_types'].append(artificial_type) + methods = '\n' + generate_dto_base_methods(dump_reply_artificial_dtos[request_dto_name]['cls_name'], + {'args': dump_reply_artificial_dtos[request_dto_name]['field_names'], + 'types': dump_reply_artificial_dtos[request_dto_name]['field_types']}) + dump_reply_artificial_dtos[request_dto_name]['methods'] = methods else: + methods = '\n' + generate_dto_base_methods(cls_name, {'args': [func['name']], + 'types': [artificial_type]}) dump_reply_artificial_dtos[request_dto_name] = ({'docs': util.api_message_to_javadoc(func), 'cls_name': cls_name, 'fields': fields, - 'methods': "", + 'field_names': [func['name']], + 'field_types': [artificial_type], + # strip too many newlines at the end of base method block + 'methods': methods, 'plugin_package': plugin_package, 'base_package': base_package, 'base_type': base_type, - 'dto_package': dto_package, - }) + 'dto_package': dto_package}) diff --git a/vpp-api/java/jvpp/gen/jvppgen/util.py b/vpp-api/java/jvpp/gen/jvppgen/util.py index 0018e014dc4..712f17866c3 100644 --- a/vpp-api/java/jvpp/gen/jvppgen/util.py +++ b/vpp-api/java/jvpp/gen/jvppgen/util.py @@ -45,6 +45,7 @@ def is_reply(name): def is_details(name): return name.lower().endswith(reply_suffixes[1]) or name.lower().endswith(reply_suffixes[2]) + def is_retval_field(name): return name == 'retval' @@ -184,6 +185,7 @@ def remove_suffix(camel_case_name_with_suffix, suffix): def is_control_ping(camel_case_name_with_suffix): return camel_case_name_with_suffix.lower().startswith("controlping"); + def api_message_to_javadoc(api_message): """ Converts vpe.api message description to javadoc """ str = pprint.pformat(api_message, indent=4, width=120, depth=None) @@ -196,3 +198,7 @@ notification_dto_suffix = "Notification" def add_notification_suffix(camel_case_dto_name): camel_case_dto_name += notification_dto_suffix return camel_case_dto_name + + +def is_array(java_type_as_string): + return java_type_as_string.endswith("[]") -- cgit 1.2.3-korg