| package com.android.codegen |
| |
| import com.github.javaparser.JavaParser |
| import java.io.File |
| |
| |
| const val THIS_SCRIPT_LOCATION = "" |
| const val GENERATED_WARNING_PREFIX = "Code below generated by $CODEGEN_NAME" |
| const val GENERATED_END = "// End of generated code" |
| const val INDENT_SINGLE = " " |
| |
| val PRIMITIVE_TYPES = listOf("byte", "short", "int", "long", "char", "float", "double", "boolean") |
| val PRIMITIVE_ARRAY_TYPES = listOf("byte[]", "short[]", "int[]", "long[]", "char[]", "float[]", "double[]", "boolean[]") |
| val BOXED_PRIMITIVE_TYPES = PRIMITIVE_TYPES.map { it.capitalize() } - "Int" + "Integer" - "Char" + "Character" |
| |
| val BUILTIN_SPECIAL_PARCELLINGS = listOf("Pattern") |
| |
| const val FLAG_BUILDER_PROTECTED_SETTERS = "--builder-protected-setters" |
| const val FLAG_NO_FULL_QUALIFIERS = "--no-full-qualifiers" |
| |
| val JAVA_PARSER = JavaParser() |
| |
| /** @see [FeatureFlag] */ |
| val USAGE = """ |
| Usage: $CODEGEN_NAME [--[PREFIX-]FEATURE...] JAVAFILE |
| |
| Generates boilerplade parcelable/data class code at the bottom of JAVAFILE, based o fields' declaration in the given JAVAFILE's top-level class |
| |
| FEATURE represents some generatable code, and can be among: |
| ${FeatureFlag.values().map { feature -> |
| " ${feature.kebabCase}" to feature.desc |
| }.columnize(" - ")} |
| |
| And PREFIX can be: |
| <empty> - request to generate the feature |
| no - suppress generation of the feature |
| hidden - request to generate the feature with @hide |
| |
| Extra options: |
| --help - view this help |
| --update-only - auto-detect flags from the previously auto-generated comment within the file |
| $FLAG_NO_FULL_QUALIFIERS |
| - when referring to classes don't use package name prefix; handy with IDE auto-import |
| $FLAG_BUILDER_PROTECTED_SETTERS |
| - make builder's setters protected to expose them as public in a subclass on a whitelist basis |
| |
| |
| Special field modifiers and annotations: |
| transient - ignore the field completely |
| @Nullable - support null value when parcelling, and never throw on null input |
| @NonNull - throw on null input and don't parcel the nullness bit for the field |
| @DataClass.Enum - parcel field as an enum value by ordinal |
| @DataClass.PluralOf(..) - provide a singular version of a collection field name to be used in the builder's 'addFoo(..)' |
| @DataClass.ParcelWith(..) - provide a custom Parcelling class, specifying the custom (un)parcelling logic for this field |
| = <initializer>; - provide default value and never throw if this field was not provided e.g. when using builder |
| /** ... */ - copy given javadoc on field's getters/setters/constructor params/builder setters etc. |
| @hide (in javadoc) - force field's getters/setters/withers/builder setters to be @hide-den if generated |
| |
| |
| Special methods/etc. you can define: |
| |
| <any auto-generatable method> |
| For any method to be generated, if a method with same name and argument types is already |
| defined, than that method will not be generated. |
| This allows you to override certain details on granular basis. |
| |
| void onConstructed() |
| Will be called in constructor, after all the fields have been initialized. |
| This is a good place to put any custom validation logic that you may have |
| |
| static class $CANONICAL_BUILDER_CLASS extends $BASE_BUILDER_CLASS |
| If a class extending $BASE_BUILDER_CLASS is specified, generated builder's setters will |
| return the provided $CANONICAL_BUILDER_CLASS type. |
| $BASE_BUILDER_CLASS's constructor(s) will be package-private to encourage using $CANONICAL_BUILDER_CLASS instead |
| This allows you to extend the generated builder, adding or overriding any methods you may want |
| |
| |
| In addition, for any field mMyField(or myField) of type FieldType you can define the following methods: |
| |
| void parcelMyField(Parcel dest, int flags) |
| Allows you to provide custom logic for storing mMyField into a Parcel |
| |
| static FieldType unparcelMyField(Parcel in) |
| Allows you to provide custom logic to deserialize the value of mMyField from a Parcel |
| |
| String myFieldToString() |
| Allows you to provide a custom toString representation of mMyField's value |
| |
| FieldType lazyInitMyField() |
| Requests a lazy initialization in getMyField(), with the provided method being the constructor |
| You may additionally mark the fields as volatile to cause this to generate a thread-safe |
| double-check locking lazy initialization |
| |
| FieldType defaultMyField() |
| Allows you to provide a default value to initialize the field to, in case an explicit one |
| was not provided. |
| This is an alternative to providing a field initializer that, unlike the initializer, |
| you can use with final fields. |
| |
| Version: $CODEGEN_VERSION |
| |
| Questions? Feedback? |
| Contact: eugenesusla@ |
| Bug/feature request: http://go/codegen-bug |
| |
| Slides: http://go/android-codegen |
| In-depth example: http://go/SampleDataClass |
| """ |
| |
| fun main(args: Array<String>) { |
| if (args.contains("--help")) { |
| println(USAGE) |
| System.exit(0) |
| } |
| if (args.contains("--version")) { |
| println(CODEGEN_VERSION) |
| System.exit(0) |
| } |
| val file = File(args.last()).absoluteFile |
| val sourceLisnesOriginal = file.readLines() |
| val sourceLinesNoClosingBrace = sourceLisnesOriginal.dropLastWhile { |
| it.startsWith("}") || it.all(Char::isWhitespace) |
| } |
| val cliArgs = handleUpdateFlag(args, sourceLinesNoClosingBrace) |
| |
| val fileInfo = FileInfo(sourceLisnesOriginal, cliArgs, file) |
| fileInfo.main() |
| file.writeText(fileInfo.stringBuilder.toString().mapLines { trimEnd() }) |
| } |
| |
| private fun handleUpdateFlag(cliArgs: Array<String>, sourceLines: List<String>): Array<String> { |
| if ("--update-only" in cliArgs |
| && sourceLines.none { GENERATED_WARNING_PREFIX in it || it.startsWith("@DataClass") }) { |
| System.exit(0) |
| } |
| return cliArgs - "--update-only" |
| } |