def _write_datamodel(writer: IndentedWriter, entity: Entity, output: pathlib.Path, package: str, import_list: Set) -> None: writer.writeln(f"package {package}.{_package(entity.package)}.datamodel;") writer.newline() if import_list is not None: import_list.update({"java.io.Serializable"}) for dependency in _get_dependencies(entity): import_list.add( f"{package}.{_package(dependency.package)}.logic." + dependency.name) for import_item in sorted(import_list): writer.writeln(f"import {import_item};") else: import_list = set() writer.newline() import_list = _write_datamodel_class(writer, entity.root, import_list) return import_list
def _write_logic_inner(writer: IndentedWriter, message: Message) -> None: if len(message.extends) > 1: shared_interface = _get_shared_interface(message) writer.writeln(f"interface {message.name} : {message.name}Entity {{") indented_writer = writer.indented() writer.writeln("}") writer.newline() for extends in message.extends: _write_logic_class(writer, extends.root, shared_interface) writer.newline() else: _write_logic_class(writer, message)
def _write_datamodel(writer: IndentedWriter, entity: Entity, output: pathlib.Path) -> None: dependency_statements: Set[str] = set() dependencies = _dependencies(entity.root) if dependencies: for dependency in dependencies: name = dependency.root.name path = _rel_import(entity.package, dependency.package, name) statement = f"import {{ {name} }} from '{str(path)}';" dependency_statements.add(statement) if dependency_statements: for dependency_statement in sorted(dependency_statements): writer.writeln(dependency_statement) writer.newline() _write_enums(writer, entity.root) _write_datamodel_class(writer, entity.root)
def _write_logic(writer: IndentedWriter, entity: Entity, package: str) -> None: writer.writeln(f"package {package}.{_package(entity.package)}.logic;") writer.newline() import_list = [ f"{package}.{_package(entity.package)}.datamodel.{entity.name}Entity", f"java.io.Serializable", "androidx.annotation.NonNull", "androidx.annotation.Nullable", "java.util.List" ] for dependency in _get_dependencies(entity): import_list.append(f"{package}.{_package(dependency.package)}.logic." + dependency.name) for import_item in sorted(set(import_list)): writer.writeln(f"import {import_item};") writer.newline() _write_logic_class(writer, entity.root)
def _write_logic_class(writer: IndentedWriter, message: Message) -> None: writer.write("public") if writer.indent > 0: writer.append(" static") writer.appendln(f" class {message.name} extends {message.name}Entity {{") writer.newline() indented_writer = writer.indented() constructor_parameters, super_import_list = _get_super_constructor_parameters( message) constructor_parameters_string = [] super_arguments_string = [] for constructor_parameter in constructor_parameters: name = constructor_parameter[0] type = constructor_parameter[1] constructor_parameters_string.append(f'@NonNull {type} {name}') super_arguments_string.append(f'{name}') indented_writer.writeln( f'public {message.name}({", ".join(constructor_parameters_string)}) {{' ) indented_writer.indented().writeln( f'super({", ".join(super_arguments_string)});') indented_writer.writeln("}") for submessage in message.messages: name = submessage.name if submessage.is_array: if submessage.extends is None or submessage.properties or submessage.messages: _write_logic_class(indented_writer, submessage) else: if submessage.extends is None or submessage.is_non_empty: _write_logic_class(indented_writer, submessage) writer.writeln(f"}}")
def _write_datamodel_inner(writer: IndentedWriter, message: Message, import_list: Set, prefix: str = '') -> Set: if len(message.extends) > 1: shared_interface = _get_shared_interface(message) writer.writeln(f"interface {message.name}Entity : Entity {{") indented_writer = writer.indented() for enum in shared_interface.enums: indented_writer.writeln(f"enum class {enum[0]} {{") indented_writer.indented().writeln(f'{", ".join(enum[1])}') indented_writer.writeln(f"}}") writer.newline() for variable in shared_interface.variables: indented_writer.writeln(f"var {variable.name}: {variable.type}") writer.writeln("}") writer.newline() for extends in message.extends: import_list.update( _write_datamodel_class(writer, extends.root, import_list, prefix, shared_interface)) writer.newline() return import_list else: return _write_datamodel_class(writer, message, import_list, prefix)
def _write_logic(writer: IndentedWriter, entity: Entity, package: str) -> None: writer.writeln(f"package {package}.{_package(entity.package)}.logic") writer.newline() import_list = [ f"{package}.{_package(entity.package)}.datamodel.{entity.name}Entity" ] for dependency in _get_dependencies( entity, False ): # set this to True to reduce imports, but will give false negatives at the moment import_list.append(f"{package}.{_package(dependency.package)}.logic." + dependency.name) import_list.append( f"{package}.{_package(dependency.package)}.datamodel." + dependency.name + "Entity") for import_item in sorted(set(import_list)): writer.writeln(f"import {import_item}") writer.newline() _write_logic_inner(writer, entity.root)
def _write_service(writer: IndentedWriter, entity: Entity, package: str) -> None: writer.writeln(f"package {package}.{_package(entity.package)}.service;") writer.newline() dependencies: List[str] = [] if entity.key_ids: dependencies.append("retrofit2.http.Query") import_non_null = False import_nullable = False for key_id in entity.key_ids: for key_property in entity.key_properties(key_id): if key_property.nullable: import_nullable = True else: import_non_null = True if "GET" in entity.methods or "PUT" in entity.methods or "POST" in entity.methods or "DELETE" in entity.methods: dependencies.append("io.reactivex.Single") if entity.version != -1: dependencies.append("retrofit2.http.Headers") if "PUT" in entity.methods or "POST" in entity.methods: import_non_null = True dependencies.append("retrofit2.http.Body") for method in entity.methods: dependencies.append(f"retrofit2.http.{method}") if "GET" in entity.methods or "PUT" in entity.methods or "POST" in entity.methods: dependencies.append( f"{package}.{_package(entity.package)}.logic.{entity.name}") if import_non_null: dependencies.append("androidx.annotation.NonNull") if import_nullable: dependencies.append("androidx.annotation.Nullable") previous_dependency = None for dependency in sorted(dependencies): if previous_dependency is not None and previous_dependency.split( ".")[0] != dependency.split(".")[0]: writer.newline() writer.writeln(f"import {dependency};") previous_dependency = dependency writer.newline() writer.writeln(f"public interface {entity.name}Service {{") writer.newline() for method in entity.methods: indented_writer = writer.indented() for key_id in entity.key_ids: parameter_list = [] for key_property in entity.key_properties(key_id): variable_name = camelcase(key_property.name) variable_type = _java_type(key_property.type) nullable = '@NonNull' if key_property.nullable: nullable = '@Nullable' parameter_list.append( f'{nullable} @Query("{key_property.name}") {variable_type} {variable_name}' ) parameters = ', '.join(parameter_list) if entity.version != -1: indented_writer.writeln( f'@Headers("X-Navajo-Version: {entity.version}")') indented_writer.writeln( f'@{method}("{entity.path}?v={entity.version}")') else: indented_writer.writeln(f'@{method}("{entity.path}")') if method == "GET": indented_writer.writeln( f'Single<{entity.name}> get{entity.name}({parameters});') if method == "PUT": indented_writer.writeln( f'Single<{entity.name}> update{entity.name}({parameters}, @NonNull @Body {entity.name} {entity.name[0].lower() + entity.name[1:]});' ) if method == "DELETE": indented_writer.writeln( f'Single<{entity.name}> remove{entity.name}({parameters});' ) if method == "POST": indented_writer.writeln( f'Single<{entity.name}> insert{entity.name}({parameters}, @NonNull @Body {entity.name} {entity.name[0].lower() + entity.name[1:]});' ) indented_writer.newline() if not len(entity.key_ids): if entity.version != -1: indented_writer.writeln( f'@Headers("X-Navajo-Version: {entity.version}")') indented_writer.writeln( f'@{method}("{entity.path}?v={entity.version}")') else: indented_writer.writeln(f'@{method}("{entity.path}")') if method == "GET": indented_writer.writeln( f'Single<{entity.name}> get{entity.name}();') if method == "PUT": indented_writer.writeln( f'Single<{entity.name}> update{entity.name}(@NonNull @Body {entity.name} {entity.name[0].lower() + entity.name[1:]});' ) if method == "DELETE": indented_writer.writeln( f'Single<{entity.name}> remove{entity.name}();') if method == "POST": indented_writer.writeln( f'Single<{entity.name}> insert{entity.name}(@NonNull @Body {entity.name} {entity.name[0].lower() + entity.name[1:]});' ) indented_writer.newline() writer.writeln("}") writer.newline()
def _write_datamodel_class(writer: IndentedWriter, message: Message, import_list: Set, prefix: str = '') -> None: writer.write("public") if prefix != '': writer.append(" static") writer.append(f" class {message.name}Entity") if message.extends is not None: writer.append(f" extends {message.extends.name}") writer.appendln(" implements Serializable {") writer.newline() prefix += message.name + "." indented_writer = writer.indented() constructor_parameters = [] for property in message.properties: if property.method == "request": continue type = property.type name = property.name variable_name = camelcase(name) variable_type = _java_type(type) nullable = property.nullable if property.enum is not None and len(property.enum): indented_writer.writeln(f'public enum {name} {{') for enum_value in property.enum: enum_writer = indented_writer.indented() enum_writer.writeln(f'{enum_value},') indented_writer.writeln('}') indented_writer.newline() variable_type = name if nullable: indented_writer.writeln(f'@Nullable') import_list.add("androidx.annotation.Nullable") else: constructor_parameters.append((variable_name, variable_type)) indented_writer.writeln(f'@NonNull') import_list.add("androidx.annotation.NonNull") indented_writer.writeln(f'@SerializedName("{name}")') import_list.add("com.google.gson.annotations.SerializedName") indented_writer.writeln(f"public {variable_type} {variable_name};") indented_writer.newline() for submessage in message.messages: name = submessage.name nullable = submessage.nullable if submessage.is_array: if submessage.extends is None or submessage.is_non_empty: import_list.update( _write_datamodel_class(indented_writer, submessage, import_list, prefix)) variable_type = "List<" + prefix + name + ">" else: variable_type = "List<" + submessage.extends.name + ">" variable_name = camelcase(name) + "List" import_list.add("java.util.List") else: if submessage.extends is None or submessage.is_non_empty: import_list.update( _write_datamodel_class(indented_writer, submessage, import_list, prefix)) variable_type = prefix + name else: variable_type = submessage.extends.name variable_name = camelcase(name) if nullable: indented_writer.writeln('@Nullable') import_list.add("androidx.annotation.Nullable") else: constructor_parameters.append((variable_name, variable_type)) indented_writer.writeln('@NonNull') import_list.add("androidx.annotation.NonNull") indented_writer.writeln(f'@SerializedName("{name}")') import_list.add("com.google.gson.annotations.SerializedName") indented_writer.writeln(f'public {variable_type} {variable_name};') indented_writer.newline() super_constructor_parameters = [] constructor_parameters_string = [] if message.extends is not None: super_constructor_parameters, super_import_list = _get_super_constructor_parameters( message.extends.root) import_list.update(super_import_list) for constructor_parameter in super_constructor_parameters: name = constructor_parameter[0] type = constructor_parameter[1] constructor_parameters_string.append(f'@NonNull {type} {name}') import_list.add("androidx.annotation.NonNull") for constructor_parameter in constructor_parameters: name = constructor_parameter[0] type = constructor_parameter[1] constructor_parameters_string.append(f'@NonNull {type} {name}') import_list.add("androidx.annotation.NonNull") indented_writer.writeln( f'public {message.name}Entity({", ".join(constructor_parameters_string)}) {{' ) super_arguments_string = [] for constructor_parameter in super_constructor_parameters: name = constructor_parameter[0] super_arguments_string.append(name) body_writer = indented_writer.indented() body_writer.writeln(f'super({", ".join(super_arguments_string)});') for constructor_parameter in constructor_parameters: name = constructor_parameter[0] body_writer.writeln(f'this.{name} = {name};') indented_writer.writeln('}') indented_writer.newline() writer.writeln("}") writer.newline() return import_list
def _write_datamodel_class(writer: IndentedWriter, message: Message, prefix: str = '') -> None: writer.write(f"export interface {message.name}") if message.extends is not None: writer.append(f" extends {message.extends.name}") variables: Set[str] = set() for property in message.properties: if property.method == "request": continue name = property.name if property.enum is not None: type = name else: type = _type(property.type) variable = name variable += f": {type}" if property.nullable: variable += " | null" variable += ";" variables.add(variable) interfaces: List[Message] = [] for sub_message in message.messages: name = sub_message.name type = sub_message.name if sub_message.is_array: if sub_message.extends is None or len(sub_message.messages) or len( sub_message.properties): interfaces.append(sub_message) type = f"{name}[]" else: type = f"{sub_message.extends.name}[]" else: if sub_message.extends is None or len(sub_message.messages) or len( sub_message.properties): interfaces.append(sub_message) else: type = sub_message.extends.name variable = name variable += f": {type}" if sub_message.nullable: variable += " | null" variable += ";" variables.add(variable) # When there are no variables, then just render an empty interface, but with {} on 1 line if variables: writer.appendln(" {") for variable in sorted(variables, key=lambda x: x.split(":")[0]): writer.indented().writeln(variable) writer.appendln("}") else: writer.appendln(" {}") if interfaces: writer.newline() for interface in interfaces: _write_datamodel_class(writer, interface)
def _write_service(writer: IndentedWriter, entity: Entity, package: str) -> None: writer.writeln(f"package {package}.{_package(entity.package)}.service") writer.newline() dependencies = set() dependencies.update([ "retrofit2.http.Query", "com.google.gson.TypeAdapterFactory", f"com.sendrato.app.sdk.gson.RuntimeTypeAdapterFactory" ]) if "GET" in entity.methods or "PUT" in entity.methods or "POST" in entity.methods or "DELETE" in entity.methods: dependencies.add("io.reactivex.Single") if entity.version != -1: dependencies.add("retrofit2.http.Headers") if "PUT" in entity.methods or "POST" in entity.methods: dependencies.add("retrofit2.http.Body") for method in entity.methods: dependencies.add(f"retrofit2.http.{method}") if "GET" in entity.methods or "PUT" in entity.methods or "POST" in entity.methods or "DELETE" in entity.methods: dependencies.add( f"{package}.{_package(entity.package)}.logic.{entity.name}") for dependency in _get_dependencies(entity): dependencies.add(f"{package}.{_package(dependency.package)}.logic." + dependency.name) for dependency in sorted(dependencies): writer.writeln(f"import {dependency}") writer.newline() writer.writeln(f"interface {entity.name}Service {{") writer.newline() indented_writer = writer.indented() for method in entity.methods: for key_id in entity.key_ids: parameter_list = [] for key_property in entity.key_properties(key_id): variable_name = camelcase(key_property.name) variable_type = _kotlin_type(key_property.type) if key_property.nullable: variable_type += '?' parameter_list.append( f'@Query("{key_property.name}") {variable_name}: {variable_type}' ) parameters = ', '.join(parameter_list) if entity.version != -1: indented_writer.writeln( f'@Headers("X-Navajo-Version: {entity.version}")') indented_writer.writeln( f'@{method}("{entity.path}?v={entity.version}")') else: indented_writer.writeln(f'@{method}("{entity.path}")') if method == "GET": indented_writer.writeln( f'fun {entity.name[0].lower() + entity.name[1:]}({parameters}): Single<{entity.name}>' ) if method == "PUT": indented_writer.writeln( f'fun update{entity.name}({parameters}, @Body {entity.name[0].lower() + entity.name[1:]}: {entity.name}): Single<{entity.name}>' ) if method == "DELETE": indented_writer.writeln( f'fun remove{entity.name}({parameters}): Single<{entity.name}>' ) if method == "POST": indented_writer.writeln( f'fun insert{entity.name}({parameters}, @Body {entity.name[0].lower() + entity.name[1:]}: {entity.name}): Single<{entity.name}>' ) indented_writer.newline() if not entity.key_ids: if entity.version != -1: indented_writer.writeln( f'@Headers("X-Navajo-Version: {entity.version}")') indented_writer.writeln( f'@{method}("{entity.path}?v={entity.version}")') else: indented_writer.writeln(f'@{method}("{entity.path}")') if method == "GET": indented_writer.writeln( f'fun {entity.name[0].lower() + entity.name[1:]}(): Single<{entity.name}> ' ) if method == "PUT": indented_writer.writeln( f'fun update{entity.name}(@Body {entity.name[0].lower() + entity.name[1:]}: {entity.name}): Single<{entity.name}>' ) if method == "DELETE": indented_writer.writeln( f'fun remove{entity.name}(): Single<{entity.name}>') if method == "POST": indented_writer.writeln( f'fun insert{entity.name}(@Body {entity.name[0].lower() + entity.name[1:]}: {entity.name}): Single<{entity.name}>' ) indented_writer.newline() indented_writer.writeln("companion object {") companion_writer = indented_writer.indented() companion_writer.writeln( "var typeFactoryAdapterList = listOf<TypeAdapterFactory>(") _write_service_typeadapterfactories(companion_writer, entity.root, "") companion_writer.writeln(")") indented_writer.writeln("}") writer.writeln("}") writer.newline()
def _write_logic_class(writer: IndentedWriter, message: Message, shared_interface: SharedInterface = None) -> None: if shared_interface: writer.write(f"open class {shared_interface.name}{message.name}") else: writer.write(f"open class {message.name}") super_nonnull_variables = _get_variables(message, "", True)[0] super_nullable_variables = _get_variables(message, "", True)[1] shared_interface_super_nonnull_variables = [] shared_interface_super_nullable_variables = [] if shared_interface: for parent in shared_interface.parents: shared_interface_super_nonnull_variables += _get_variables( parent.root, "")[0] shared_interface_super_nullable_variables += _get_variables( parent.root, "")[1] indented_writer = writer.indented() writer.appendln("(") if (super_nonnull_variables or shared_interface_super_nonnull_variables or shared_interface_super_nullable_variables): for constructor_parameter in super_nonnull_variables: name = constructor_parameter.name type = constructor_parameter.type indented_writer.writeln(f'{name}: {type},') if shared_interface: for variable in shared_interface.variables: if variable not in super_nonnull_variables: indented_writer.writeln( f'{variable.name}: {variable.type},') if shared_interface_super_nonnull_variables: for variable in shared_interface_super_nonnull_variables: if variable not in super_nonnull_variables: indented_writer.writeln( f'{variable.name}: {variable.type},') # if shared_interface_super_nullable_variables: # for variable in shared_interface_super_nullable_variables: # if variable not in super_nullable_variables: # indented_writer.writeln(f'{variable.name}: {variable.type},') if shared_interface: writer.writeln(f") : {shared_interface.name}{message.name}Entity(") else: writer.writeln(f") : {message.name}Entity(") for constructor_parameter in super_nonnull_variables: name = constructor_parameter.name if debug: indented_writer.writeln('/* super variable */ ') indented_writer.writeln(f'{name},') if shared_interface: for variable in shared_interface.variables: if variable not in super_nonnull_variables: if debug: indented_writer.writeln( '/* shared interface variable */ ') indented_writer.writeln(f'{variable.name},') if shared_interface_super_nonnull_variables: for variable in shared_interface_super_nonnull_variables: if variable not in super_nonnull_variables: if debug: indented_writer.writeln( '/* shared interface super nonnull variable */ ') indented_writer.writeln(f'{variable.name},') # if shared_interface_super_nullable_variables: # for variable in shared_interface_super_nullable_variables: # if variable not in super_nullable_variables: # if debug: # indented_writer.writeln('/* shared interface super nullable variable */ ') # indented_writer.writeln(f'{variable.name},') writer.write(f")") else: if shared_interface: writer.writeln( f") : {shared_interface.name}{message.name}Entity()") else: writer.writeln(f") : {message.name}Entity()") hasId = False if not shared_interface: for variable in super_nonnull_variables: if variable.network_name == "Id" and variable.type == "String" and not variable.nullable: hasId = True if hasId or message.messages: hasSubClass = False for submessage in message.messages: name = submessage.name if submessage.is_array: if len(submessage.extends ) != 1 or submessage.properties or submessage.messages: if not hasSubClass: writer.appendln(" {") hasSubClass = True _write_logic_inner(indented_writer, submessage) else: if len(submessage.extends ) != 1 or submessage.properties or submessage.messages: if not hasSubClass: writer.appendln(" {") hasSubClass = True _write_logic_inner(indented_writer, submessage) if hasId: if not hasSubClass: writer.appendln(" {") hasSubClass = True indented_writer.newline() indented_writer.writeln("companion object {") indented_writer.indented().write("fun create(") for constructor_parameter in super_nonnull_variables: name = constructor_parameter.name type = constructor_parameter.type if name != 'id': indented_writer.append(f'{name}: {type}, ') indented_writer.append(") = " + message.name + "(INSERT_ID") for constructor_parameter in super_nonnull_variables: name = constructor_parameter.name type = constructor_parameter.type if name != 'id': indented_writer.append(f', {name}') indented_writer.appendln(")") indented_writer.writeln("}") if hasSubClass: writer.writeln("}") else: writer.newline() else: writer.newline() if (shared_interface and (super_nonnull_variables or shared_interface_super_nonnull_variables or shared_interface_super_nullable_variables)): constructor_writer = indented_writer.indented() writer.writeln("{") indented_writer.writeln("constructor(") constructor_writer.writeln( f"{camelcase(message.name)}: {message.name},") for constructor_parameter in shared_interface_super_nonnull_variables: if constructor_parameter not in super_nonnull_variables: constructor_writer.writeln( f'{constructor_parameter[1]}: {constructor_parameter[2]},' ) #last one without comma # for constructor_parameter in shared_interface_super_nullable_variables: # if constructor_parameter not in super_nullable_variables: # constructor_writer.writeln(f'{constructor_parameter[1]}: {constructor_parameter[2]},') #last one without comma for variable in shared_interface.variables: if variable not in super_nonnull_variables: constructor_writer.writeln( f"{variable.name}: {variable.type},") indented_writer.writeln(") : this(") for constructor_parameter in super_nonnull_variables: name = constructor_parameter.name constructor_writer.writeln( f'{camelcase(message.name)}.{name},') #last one without comma for constructor_parameter in shared_interface_super_nonnull_variables: if constructor_parameter not in super_nonnull_variables: name = constructor_parameter.name constructor_writer.writeln(f'{name},') #last one without comma # for constructor_parameter in shared_interface_super_nullable_variables: # name = constructor_parameter[1] # if constructor_parameter not in super_nullable_variables: # constructor_writer.writeln(f'{name},') #last one without comma for variable in shared_interface.variables: if variable not in super_nonnull_variables: constructor_writer.writeln(f'{variable.name},') indented_writer.writeln(") {") indented_writer.indented().writeln( f"copyNullableVariables({camelcase(message.name)})") indented_writer.writeln("}") writer.writeln("}")
def _write_datamodel_class(writer: IndentedWriter, message: Message, import_list: Set, prefix: str = '', shared_interface: SharedInterface = None) -> Set: if shared_interface is None: writer.write(f"open class {message.name}Entity") else: writer.write(f"open class {shared_interface.name}{message.name}Entity") if not shared_interface: prefix += message.name + "." variables = _get_variables(message, prefix) nonnull_variables = variables[0] nullable_variables = variables[1] enums = variables[2] inner_classes = variables[3] super_variables = [] super_interface_nonnull_variables = [] super_interface_nullable_variables = [] shared_interface_super_nonnull_variables = [] shared_interface_super_nullable_variables = [] constructor_vars = [] member_vars = [] if len(message.extends) == 1: super_variables = _get_variables(message.extends[0].root, message.extends[0].root.name + ".", True)[0] if shared_interface: for parent in shared_interface.parents: shared_interface_super_nonnull_variables += _get_variables( parent.root, prefix)[0] shared_interface_super_nullable_variables += _get_variables( parent.root, prefix)[1] indented_writer = writer.indented() if (super_variables or nonnull_variables or super_interface_nonnull_variables or shared_interface or shared_interface_super_nonnull_variables or shared_interface_super_nullable_variables): writer.appendln("(") if (super_variables): for variable in super_variables: if debug: indented_writer.writeln('/* super variable */ ') indented_writer.writeln(f'{variable.name}: {variable.type},') constructor_vars.append(variable) if (super_interface_nonnull_variables): for variable in super_interface_nonnull_variables: if variable in shared_interface_super_nonnull_variables + nonnull_variables: continue if shared_interface: if debug: indented_writer.writeln( '/* super interface non null shared variable */ ') indented_writer.writeln( f'override var {variable.name}: {variable.type},') else: import_list.add( "com.google.gson.annotations.SerializedName") if debug: indented_writer.writeln( '/* super interface non null variable */ ') indented_writer.writeln( f'@SerializedName("{variable.network_name}") override var {variable.name}: {variable.type},' ) constructor_vars.append(variable) if (nonnull_variables): for variable in nonnull_variables: import_list.add("com.google.gson.annotations.SerializedName") if shared_interface: if variable in super_interface_nonnull_variables: if debug: indented_writer.writeln( '/* non null shared override variable */ ') indented_writer.writeln( f'{variable.name}: {variable.type},') else: if debug: indented_writer.writeln( '/* non null shared variable */ ') indented_writer.writeln( f'{variable.name}: {variable.type},') else: if variable in super_interface_nonnull_variables: if debug: indented_writer.writeln( '/* non null override variable */ ') indented_writer.writeln( f'@SerializedName("{variable.network_name}") override var {variable.name}: {variable.type},' ) else: if debug: indented_writer.writeln('/* non null variable */ ') indented_writer.writeln( f'@SerializedName("{variable.network_name}") open var {variable.name}: {variable.type},' ) constructor_vars.append(variable) if (shared_interface): for variable in shared_interface.variables: import_list.add("com.google.gson.annotations.SerializedName") if debug: indented_writer.writeln('/* shared interface variable */ ') indented_writer.writeln( f'@SerializedName("{variable.network_name}") override var {variable.name}: {variable.type},' ) constructor_vars.append(variable) if (shared_interface_super_nonnull_variables): for variable in shared_interface_super_nonnull_variables: if variable in nonnull_variables: continue if debug: indented_writer.writeln( '/* shared interface super nonnull variable */ ') indented_writer.writeln( f'@SerializedName("{variable.network_name}") override var {variable.name}: {variable.type},' ) constructor_vars.append(variable) writer.write(")") if shared_interface: writer.append(f" : {message.name}") if super_variables or super_interface_nonnull_variables or nonnull_variables: vars = [] if super_variables: for variable in super_variables: vars.append(f'{variable.name}') if (super_interface_nonnull_variables): for variable in super_interface_nonnull_variables: if variable in nonnull_variables: continue vars.append(f'{variable.name} /* super interface */') if nonnull_variables: for variable in nonnull_variables: vars.append(f'{variable.name}') writer.append(f'({", ".join(vars)})') if shared_interface.is_inner: writer.append(f", {prefix + shared_interface.name}") else: writer.append(f", {shared_interface.name}") # if shared_interface.variables: # writer.append("(") # for variable in shared_interface.variables: # writer.append(f'{variable.name}, ') # writer.append(")") writer.append(", Serializable, Entity") elif not message.extends: writer.append(" : Serializable, Entity") else: writer.append(f" : {message.extends[0].name}") if super_variables: writer.appendln("(") for variable, has_more in lookahead(super_variables): indented_writer.write(f'{variable.name}') if has_more: writer.appendln(',') else: writer.appendln('') writer.write(")") writer.append(", Serializable, Entity") hasId = False if not shared_interface: for variable in nonnull_variables: if variable.network_name == "Id" and variable.type == "String" and not variable.nullable: hasId = True writer.appendln(" {") writer.newline() if (shared_interface_super_nullable_variables): for variable in shared_interface_super_nullable_variables: if variable in nullable_variables: continue else: if debug: indented_writer.writeln( '/* shared interface super nullable variable */ ') indented_writer.writeln( f'@SerializedName("{variable.network_name}") override var {variable.name}: {variable.type} = null' ) member_vars.append(variable) for inner_class in inner_classes: import_list.update( _write_datamodel_inner(indented_writer, inner_class[0], import_list, inner_class[1])) for enum in enums: indented_writer.writeln(f"enum class {enum[0]} {{") indented_writer.indented().writeln(f'{", ".join(enum[1])}') indented_writer.writeln(f"}}") writer.newline() if not shared_interface: for variable in nullable_variables: import_list.add("com.google.gson.annotations.SerializedName") indented_writer.writeln( f'@SerializedName("{variable.network_name}")') indented_writer.writeln( f"open var {variable.name}: {variable.type} = null") member_vars.append(variable) writer.newline() for variable in super_interface_nullable_variables: import_list.add("com.google.gson.annotations.SerializedName") indented_writer.writeln( f'@SerializedName("{variable.network_name}")') indented_writer.writeln( f"override var {variable.name}: {variable.type} = null") member_vars.append(variable) writer.newline() if hasId: indented_writer.writeln("override fun hashCode(): Int {") indented_writer.indented().writeln("return id.hashCode()") indented_writer.writeln("}") indented_writer.newline() indented_writer.writeln("override fun equals(other: Any?): Boolean {") indented_writer.indented().writeln( f"if (other is {message.name}Entity) {{") indented_writer.indented().indented().writeln( "return this === other || (id == other.id && id != INSERT_ID)") indented_writer.indented().writeln("}") indented_writer.indented().writeln("return super.equals(other)") indented_writer.writeln("}") indented_writer.newline() indented_writer.writeln("companion object {") indented_writer.indented().writeln('const val INSERT_ID = "insert"') indented_writer.writeln("}") indented_writer.newline() logic_type = f"{prefix}{shared_interface.name}{message.name}" if shared_interface else f"{prefix[:-1]}" indented_writer.writeln("@Transient") indented_writer.writeln(f"private lateinit var original: {logic_type}") indented_writer.newline() indented_writer.writeln("override fun saveOriginal() {") indented_writer.indented().writeln(f"original = copy()") indented_writer.writeln("}") indented_writer.newline() indented_writer.writeln(f"override fun copy(): {logic_type} {{") indented_writer.indented().write(f"val copy = {logic_type}(") for variable in constructor_vars: indented_writer.append( f"{variable.name}{'.map { it.copy() }.map { it as ' + variable.type[12:-1] + ' }.toMutableList()' if variable.name.endswith('List') else ''}{'' if variable.primitive or variable.name.endswith('List') else ('.copy() as ' + variable.type)}, " ) indented_writer.appendln(")") indented_writer.indented().writeln( f"copy.copyNullableVariables(this as {logic_type})") indented_writer.indented().writeln(f"return copy") indented_writer.writeln("}") indented_writer.newline() indented_writer.writeln( f"fun copyNullableVariables(from: {logic_type}) {{") if message.extends or shared_interface: indented_writer.indented().writeln( f"super.copyNullableVariables(from)") for variable in member_vars: if variable.primitive: indented_writer.indented().writeln( f"{variable.name} = from.{variable.name}") else: if variable.name.endswith("List"): if variable.nullable: indented_writer.indented().writeln( f"{variable.name} = from.{variable.name}?.map {{ it.copy() }}?.map {{ it as {variable.type[12:-2]} }}?.toMutableList()" ) else: indented_writer.indented().writeln( f"{variable.name} = from.{variable.name}.map {{ it.copy() }}.map {{ it as {variable.type[12:-1]} }}.toMutableList()" ) else: indented_writer.indented().writeln( f"{variable.name} = from.{variable.name}{'?' if variable.nullable else ''}.copy() as {variable.type}" ) indented_writer.writeln("}") indented_writer.newline() indented_writer.writeln( f"override fun deepEquals(other: Any?): Boolean {{") if message.extends: indented_writer.indented().writeln(f"if (!super.deepEquals(other)) {{") indented_writer.indented().indented().writeln("return false") indented_writer.indented().writeln("}") indented_writer.indented().writeln(f"return other is {logic_type}") for variable in (constructor_vars + member_vars): if variable.primitive: indented_writer.indented().indented().writeln( f"&& {variable.name} == other.{variable.name}") else: if variable.name.endswith("List"): indented_writer.indented().indented().writeln( f"&& {f'if ({variable.name} == null || other.{variable.name} == null) {variable.name} == other.{variable.name} else' if variable.nullable else ''} {variable.name}!!.size == other.{variable.name}!!.size && {variable.name}!!.zip(other.{variable.name}!!) {{ a, b -> a.deepEquals(b) }}.fold(true) {{ x, y -> x && y}}" ) else: indented_writer.indented().indented().writeln( f"&& {f'if ({variable.name} == null) other.{variable.name} == null else {variable.name}?' if variable.nullable else variable.name}.deepEquals(other.{variable.name}){' == true' if variable.nullable else ''}" ) indented_writer.writeln("}") indented_writer.newline() if message.extends or shared_interface: indented_writer.write("override ") else: indented_writer.write("open ") indented_writer.appendln(f"fun hasChanged(): Boolean {{") indented_writer.indented().writeln(f"return !deepEquals(original)") indented_writer.writeln("}") indented_writer.newline() indented_writer.writeln(f"override fun toOriginal() : {logic_type} {{") indented_writer.indented().writeln(f"val result = original") indented_writer.indented().writeln(f"original.saveOriginal()") indented_writer.indented().writeln(f"return result") indented_writer.writeln("}") writer.writeln("}") return import_list