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_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_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, 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