├── .buildscript ├── deploy_snapshot.sh └── settings.xml ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE.txt ├── README.md ├── RELEASING.md ├── assets ├── DH3-structure.png ├── DH3-with-navigator.png └── logo │ ├── banner.png │ ├── logomark(blue).png │ ├── logomark(bluegradient).png │ ├── logomark(orangegradient).png │ ├── logomark(violet).png │ ├── logotype(blue).png │ ├── logotype(bluegradient).png │ ├── logotype(orangegradient).png │ └── logotype(violet).png ├── build.gradle ├── dart-annotations ├── build.gradle ├── gradle.properties └── src │ └── main │ └── java │ └── dart │ ├── BindExtra.java │ └── DartModel.java ├── dart-common ├── build.gradle ├── gradle.properties └── src │ └── main │ └── java │ └── dart │ └── common │ ├── BaseGenerator.java │ ├── Binding.java │ ├── ExtraBindingTarget.java │ ├── ExtraInjection.java │ ├── FieldBinding.java │ ├── NavigationModelBindingTarget.java │ └── util │ ├── BindExtraUtil.java │ ├── CompilerUtil.java │ ├── DartModelUtil.java │ ├── ExtraBindingTargetUtil.java │ ├── FileUtil.java │ ├── LoggingUtil.java │ ├── NavigationModelBindingTargetUtil.java │ ├── NavigationModelFieldUtil.java │ ├── ParcelerUtil.java │ └── StringUtil.java ├── dart-processor ├── build.gradle ├── gradle.properties └── src │ ├── main │ ├── java │ │ └── dart │ │ │ └── processor │ │ │ ├── ExtraBinderGenerator.java │ │ │ ├── ExtraBinderProcessor.java │ │ │ ├── NavigationModelBinderGenerator.java │ │ │ └── NavigationModelBinderProcessor.java │ └── resources │ │ └── META-INF │ │ ├── gradle │ │ └── incremental.annotation.processors │ │ └── services │ │ └── javax.annotation.processing.Processor │ └── test │ └── java │ └── dart │ └── processor │ ├── BindExtraTest.java │ ├── BindExtraWithParcelerTest.java │ ├── BindExtraWithoutParcelerTest.java │ ├── BindNavigationModelTest.java │ ├── ExtraBinderGeneratorTest.java │ ├── ProcessorTestUtilities.java │ └── data │ ├── ActivityWithNavigationModelField.java │ ├── ActivityWithNavigationModelFieldNavigationModel.java │ ├── SubActivityWithNavigationModelField.java │ ├── SubActivityWithNavigationModelFieldNavigationModel.java │ └── SubActivityWithNoNavigationModelField.java ├── dart-sample ├── app-navigation │ ├── build.gradle │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ └── f2prateek │ │ └── dart │ │ └── example │ │ └── SampleActivityNavigationModel.java ├── app │ ├── build.gradle │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── com │ │ │ └── f2prateek │ │ │ └── dart │ │ │ └── example │ │ │ ├── MainActivity.java │ │ │ ├── SampleActivity.java │ │ │ └── SampleApp.java │ │ └── res │ │ ├── layout │ │ ├── activity_main.xml │ │ └── activity_sample.xml │ │ └── values │ │ └── strings.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── module1-navigation │ ├── build.gradle │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ └── f2prateek │ │ └── dart │ │ ├── model │ │ ├── ComplexParcelable.java │ │ ├── SimpleParcelable.java │ │ └── StringParcel.java │ │ └── module1 │ │ ├── Module1ActivityNavigationModel.java │ │ └── Module1ServiceNavigationModel.java ├── module1 │ ├── build.gradle │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── com │ │ │ └── f2prateek │ │ │ └── dart │ │ │ └── module1 │ │ │ ├── Module1Activity.java │ │ │ └── Module1Service.java │ │ └── res │ │ ├── layout │ │ └── activity_navigation.xml │ │ └── values │ │ └── strings.xml └── settings.gradle ├── dart ├── build.gradle ├── gradle.properties └── src │ ├── main │ └── java │ │ └── dart │ │ └── Dart.java │ └── test │ └── java │ └── dart │ └── DartTest.java ├── gradle.properties ├── gradle ├── gradle-mvn-push.gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── henson-plugin ├── build.gradle ├── gradle.properties └── src │ ├── functTest │ └── groovy │ │ └── dart │ │ └── henson │ │ └── plugin │ │ └── HensonPluginFunctionalTest.groovy │ └── main │ ├── groovy │ └── dart │ │ └── henson │ │ └── plugin │ │ └── HensonPlugin.groovy │ ├── java │ └── dart │ │ └── henson │ │ └── plugin │ │ ├── HensonManager.java │ │ ├── HensonPluginExtension.java │ │ ├── generator │ │ └── HensonNavigatorGenerator.java │ │ ├── internal │ │ ├── DependencyManager.java │ │ ├── GenerateHensonNavigatorTask.java │ │ └── TaskManager.java │ │ └── util │ │ └── StringUtil.java │ └── resources │ └── build.properties ├── henson-processor ├── build.gradle ├── gradle.properties └── src │ ├── main │ ├── java │ │ └── dart │ │ │ └── henson │ │ │ └── processor │ │ │ ├── IntentBuilderGenerator.java │ │ │ └── IntentBuilderProcessor.java │ └── resources │ │ └── META-INF │ │ ├── gradle │ │ └── incremental.annotation.processors │ │ └── services │ │ └── javax.annotation.processing.Processor │ └── test │ └── java │ └── dart │ └── henson │ └── processor │ ├── IntentBuilderGeneratorTest.java │ ├── IntentBuilderGeneratorWithParcelerTest.java │ ├── IntentBuilderGeneratorWithoutParcelerTest.java │ ├── ProcessorTestUtilities.java │ └── data │ ├── ClassWithOptionalExtrasNavigationModel.java │ ├── ClassWithRequiredAndOptionalExtrasNavigationModel.java │ └── Nullable.java ├── henson ├── build.gradle ├── gradle.properties └── src │ └── main │ └── java │ └── dart │ └── henson │ ├── ActivityClassFinder.java │ ├── AllRequiredSetState.java │ ├── Bundler.java │ ├── RequiredStateSequence.java │ └── State.java ├── settings.gradle └── spotless.license.java.txt /.buildscript/deploy_snapshot.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Deploy a jar, source jar, and javadoc jar to Sonatype's snapshot repo. 4 | # 5 | # Adapted from https://coderwall.com/p/9b_lfq and 6 | # http://benlimmer.com/2013/12/26/automatically-publish-javadoc-to-gh-pages-with-travis-ci/ 7 | 8 | SLUG="f2prateek/dart" 9 | JDK="oraclejdk8" 10 | BRANCH="master" 11 | 12 | set -e 13 | 14 | if [ "$TRAVIS_REPO_SLUG" != "$SLUG" ]; then 15 | echo "Skipping snapshot deployment: wrong repository. Expected '$SLUG' but was '$TRAVIS_REPO_SLUG'." 16 | elif [ "$TRAVIS_JDK_VERSION" != "$JDK" ]; then 17 | echo "Skipping snapshot deployment: wrong JDK. Expected '$JDK' but was '$TRAVIS_JDK_VERSION'." 18 | elif [ "$TRAVIS_PULL_REQUEST" != "false" ]; then 19 | echo "Skipping snapshot deployment: was pull request." 20 | elif [ "$TRAVIS_BRANCH" != "$BRANCH" ]; then 21 | echo "Skipping snapshot deployment: wrong branch. Expected '$BRANCH' but was '$TRAVIS_BRANCH'." 22 | else 23 | echo "Deploying snapshot..." 24 | mvn clean source:jar javadoc:jar deploy --settings=".buildscript/settings.xml" -Dmaven.test.skip=true 25 | echo "Snapshot deployed!" 26 | fi 27 | -------------------------------------------------------------------------------- /.buildscript/settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | sonatype-nexus-snapshots 5 | ${env.CI_DEPLOY_USERNAME} 6 | ${env.CI_DEPLOY_PASSWORD} 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .classpath 2 | .project 3 | .settings 4 | .gradle 5 | eclipsebin 6 | 7 | bin 8 | gen 9 | build 10 | out 11 | lib 12 | 13 | local.properties 14 | 15 | .idea 16 | *.iml 17 | classes 18 | 19 | obj 20 | 21 | .DS_Store 22 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: android 2 | 3 | android: 4 | components: 5 | # Update tools and then platform-tools explicitly so lint gets an updated database. Can be removed once 3.0 is out. 6 | - tools 7 | - platform-tools 8 | 9 | jdk: 10 | - oraclejdk8 11 | 12 | env: 13 | global: 14 | - secure: "S2ANsF5glMuPrjilyE6+JqVp/t9bEQgkLXNHN1quLebTaJcveNFgyCPCvcevKJLiHCb4USY0cteZYj1U0QOvVR3zi/chr6Pxuo1kwgrfKpdBCWa1oxzLt0ipkVgH60VwxQNWjoUQCleOhu3F16X7IvCx32Wu7OqpmenJ6FJZYUw=" 15 | - secure: "ZetM/udS7DJMVdsFlSTCf88D6J4zQPS6hY3qc/f0BfYJP6qpOkHMBuxfIJMxkyQ9Rwi45RAX5kFFHJg/4wYiCQhlCSKy1gZaf4PORbhxTQR+rJCRtUi5dfHz2S2og/qWZm8KgaCalKW1s+f6/shFIBLcHvw8gnQmKvcIv7BHNaQ=" 16 | 17 | before_install: 18 | # Install SDK license so Android Gradle plugin can install deps. 19 | - mkdir "$ANDROID_HOME/licenses" || true 20 | - echo "d56f5187479451eabf01fb78af6dfcb131a6481e" > "$ANDROID_HOME/licenses/android-sdk-license" 21 | - echo "24333f8a63b6825ea9c5514f83c2829b004d1fee" >> "$ANDROID_HOME/licenses/android-sdk-license" 22 | # Install the rest of tools (e.g., avdmanager) 23 | #- sdkmanager tools 24 | # Install the system image 25 | #- sdkmanager "android-26" 26 | 27 | script: 28 | - ./gradlew install -x :henson-plugin:functionalTest -x :henson-plugin:spotlessJava 29 | - ./gradlew check -s 30 | - ./gradlew -b dart-sample/build.gradle check -s 31 | 32 | 33 | after_success: 34 | - .buildscript/deploy_snapshot.sh 35 | 36 | after_failure: 37 | - cat /home/travis/build/f2prateek/dart/henson-plugin/build/reports/tests/functionalTest/classes/dart.henson.plugin.HensonPluginFunctionalTest.html 38 | 39 | branches: 40 | except: 41 | - gh-pages 42 | 43 | notifications: 44 | email: false 45 | 46 | sudo: false 47 | 48 | cache: 49 | directories: 50 | - $HOME/.gradle/caches/ 51 | - $HOME/.gradle/wrapper/ 52 | - $HOME/.android/build-cache 53 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Change Log 2 | ========== 3 | 4 | Version 3.1.3 *(2019-07-02)* 5 | * Enable DH3 on dynamic feature modules: #240. 6 | Thanks to Yusuf Cahyo Nugroho for this contribution! 7 | 8 | Version 3.1.2 *(2019-01-31)* 9 | ---------------------------- 10 | * Use AGP 3.3 API for Task Configuration Avoidance 11 | 12 | Version 3.1.1 *(2019-01-17)* 13 | ---------------------------- 14 | * support android x projects #230 15 | 16 | Version 3.1.0 *(2019-01-11)* 17 | ---------------------------- 18 | * support incremental annotation processing #233 19 | 20 | Version 3.0.3 *(2018-09-26)* 21 | ---------------------------- 22 | * release version 3.0.2 henson plugin installed a SNAPSHOT version of DH dependency 23 | this is fixed in 3.0.3 24 | 25 | Version 3.0.2 *(2018-09-25)* 26 | ---------------------------- 27 | * fixed issue https://github.com/f2prateek/dart/pull/228 make builds more quiet 28 | 29 | Version 3.0.1 *(2018-06-22)* 30 | ---------------------------- 31 | * Fixed bug where parent activities using Dart outside the module couldn't be found all the time. 32 | * Issue #217 resolved. The Henson Navigator works with Kotlin! Thanks to WenChao Kong (@cooperkong) for helping us to support kotlin! 33 | 34 | Version 3.0.0 *(2018-05-22)* 35 | ---------------------------- 36 | * Version 3.X is not compatible with previous versions, please refer to the official documentation on Github (readme and wiki) to learn about the new API. 37 | 38 | Version 2.0.2 *(2017-02-15)* 39 | ---------------------------- 40 | * Issue #132 resolved. Models can now use inheritance. 41 | 42 | Version 2.0.1 *(2016-08-04)* 43 | ---------------------------- 44 | * Upgrade to JavaPoet. 45 | * Upgrade testing lib for annotation processors. We can now see errors properly displayed in Intelli J. 46 | * Add option to henson to use reflection when referencing target activity classes, see #128. 47 | 48 | Version 2.0.0 *(2016-02-29)* 49 | ---------------------------- 50 | * Switch to JavaPoet. 51 | * Use android.support.annotation.Nullable instead of com.f2prateek.dart.Optional. 52 | * Do not throw UnableToInjectException if there's no @InjectExtras annotation found. 53 | * Fix keys can be java identifiers. 54 | * Add support for injecting a service . 55 | * Add Henson helps to navigate between activities. 56 | 57 | Version 1.2.0 58 | ---------------------------- 59 | 60 | * Use variable name as key if one is not provided in annotation. 61 | * Fix `char` injection. 62 | 63 | 64 | Version 1.1.0 *(2014-01-17)* 65 | ---------------------------- 66 | 67 | * Support [Parceler](https://github.com/johncarl81/parceler) types. 68 | * Guard against null intents and null bundles. 69 | * Respect default values for optional extras. 70 | 71 | 72 | Version 1.0.0 *(2014-01-10)* 73 | ---------------------------- 74 | 75 | Initial release. 76 | -------------------------------------------------------------------------------- /RELEASING.md: -------------------------------------------------------------------------------- 1 | Releasing 2 | ======== 3 | 4 | 1. Change the version in `gradle.properties` to a non-SNAPSHOT version. 5 | 1. Update the `CHANGELOG.md` for the impending release. 6 | 1. `./gradlew clean build install --no-build-cache -x :henson-plugin:functionalTest` This step is not conventional, it installs the new version in your local maven repo, and skips the henson-plugin functional tests. It will update the version of DH that is installed by the plugin the next time it will run. 7 | 1. `git commit -am "Prepare for release X.Y.Z."` (where X.Y.Z is the new version) 8 | 1. `./gradlew clean build uploadArchives` (build is important here as we need the version number to be passed to a resource file) 9 | 1. Visit [Sonatype Nexus](https://oss.sonatype.org/) and promote the artifact. 10 | 1. `git tag -a X.Y.X -m "Version X.Y.Z"` (where X.Y.Z is the new version) 11 | 1. Update the `gradle.properties` to the next SNAPSHOT version. 12 | 1. `./gradlew clean build --no-build-cache -x :henson-plugin:functionalTest` to update the dependency versions installed by the plugin 13 | 1. `git commit -am "Prepare next development version."` 14 | 1. `git push && git push --tags` 15 | 16 | If step 5 or 6 fails, drop the Sonatype repo, fix the problem, commit, and start again at step 5. 17 | 18 | -------------------------------------------------------------------------------- /assets/DH3-structure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f2prateek/dart/ce582c1a217c436bb93924004dc1f5b1fe04f1e0/assets/DH3-structure.png -------------------------------------------------------------------------------- /assets/DH3-with-navigator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f2prateek/dart/ce582c1a217c436bb93924004dc1f5b1fe04f1e0/assets/DH3-with-navigator.png -------------------------------------------------------------------------------- /assets/logo/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f2prateek/dart/ce582c1a217c436bb93924004dc1f5b1fe04f1e0/assets/logo/banner.png -------------------------------------------------------------------------------- /assets/logo/logomark(blue).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f2prateek/dart/ce582c1a217c436bb93924004dc1f5b1fe04f1e0/assets/logo/logomark(blue).png -------------------------------------------------------------------------------- /assets/logo/logomark(bluegradient).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f2prateek/dart/ce582c1a217c436bb93924004dc1f5b1fe04f1e0/assets/logo/logomark(bluegradient).png -------------------------------------------------------------------------------- /assets/logo/logomark(orangegradient).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f2prateek/dart/ce582c1a217c436bb93924004dc1f5b1fe04f1e0/assets/logo/logomark(orangegradient).png -------------------------------------------------------------------------------- /assets/logo/logomark(violet).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f2prateek/dart/ce582c1a217c436bb93924004dc1f5b1fe04f1e0/assets/logo/logomark(violet).png -------------------------------------------------------------------------------- /assets/logo/logotype(blue).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f2prateek/dart/ce582c1a217c436bb93924004dc1f5b1fe04f1e0/assets/logo/logotype(blue).png -------------------------------------------------------------------------------- /assets/logo/logotype(bluegradient).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f2prateek/dart/ce582c1a217c436bb93924004dc1f5b1fe04f1e0/assets/logo/logotype(bluegradient).png -------------------------------------------------------------------------------- /assets/logo/logotype(orangegradient).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f2prateek/dart/ce582c1a217c436bb93924004dc1f5b1fe04f1e0/assets/logo/logotype(orangegradient).png -------------------------------------------------------------------------------- /assets/logo/logotype(violet).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f2prateek/dart/ce582c1a217c436bb93924004dc1f5b1fe04f1e0/assets/logo/logotype(violet).png -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.versions = [ 3 | 'minSdk': 14, 4 | 'compileSdk': 28, 5 | 6 | 'supportLibrary': '27.0.0', 7 | 'androidPlugin': '3.0.1', 8 | 'androidTools': '27.0.3', 9 | ] 10 | 11 | ext.deps = [ 12 | android: [ 13 | 'runtime': 'com.google.android:android:4.1.1.4', 14 | 'gradlePlugin': "com.android.tools.build:gradle:${versions.androidPlugin}", 15 | ], 16 | parceler: [ 17 | 'runtime': 'org.parceler:parceler-api:1.0.4', 18 | 'compiler': 'org.parceler:parceler:1.0.4' 19 | ], 20 | javapoet: 'com.squareup:javapoet:1.9.0', 21 | junit: 'junit:junit:4.12', 22 | fest: 'com.squareup:fest-android:1.0.7', 23 | truth: 'com.google.truth:truth:0.36', 24 | robolectric: 'org.robolectric:robolectric:2.4', 25 | compiletesting: 'com.google.testing.compile:compile-testing:0.12', 26 | spotless: 'com.diffplug.spotless:spotless-plugin-gradle:3.6.0', 27 | ] 28 | 29 | repositories { 30 | jcenter() 31 | google() 32 | maven { 33 | url "https://plugins.gradle.org/m2/" 34 | } 35 | } 36 | 37 | dependencies { 38 | classpath deps.android.gradlePlugin 39 | classpath deps.spotless 40 | } 41 | } 42 | 43 | subprojects { 44 | repositories { 45 | jcenter() 46 | google() 47 | } 48 | 49 | apply plugin: "com.diffplug.gradle.spotless" 50 | 51 | def checkSubTask = project.tasks.findByName('check') 52 | if(checkSubTask) { 53 | tasks['check'].dependsOn checkSubTask 54 | } 55 | def installSubTask = project.tasks.findByName('install') 56 | if(installSubTask) { 57 | tasks['install'].dependsOn installSubTask 58 | } 59 | 60 | spotless { 61 | java { 62 | licenseHeaderFile rootProject.file('spotless.license.java.txt') 63 | googleJavaFormat() // use a specific formatter for Java files 64 | } 65 | } 66 | tasks.withType(JavaCompile) { task -> 67 | task.options.compilerArgs << "-Xlint:deprecation" 68 | } 69 | } 70 | 71 | task check {} 72 | task install {} -------------------------------------------------------------------------------- /dart-annotations/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java-library' 2 | apply from: rootProject.file('gradle/gradle-mvn-push.gradle') 3 | 4 | sourceCompatibility = JavaVersion.VERSION_1_8 5 | targetCompatibility = JavaVersion.VERSION_1_8 6 | 7 | 8 | -------------------------------------------------------------------------------- /dart-annotations/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_ARTIFACT_ID=dart-annotations 2 | POM_NAME=Dart Annotations 3 | POM_PACKAGING=jar -------------------------------------------------------------------------------- /dart-annotations/src/main/java/dart/BindExtra.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Jake Wharton 3 | * Copyright 2014 Prateek Srivastava (@f2prateek) 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package dart; 19 | 20 | import static java.lang.annotation.ElementType.FIELD; 21 | import static java.lang.annotation.RetentionPolicy.CLASS; 22 | 23 | import java.lang.annotation.Retention; 24 | import java.lang.annotation.Target; 25 | 26 | /** 27 | * Annotation for fields which indicate that it should be looked up in the activity intent's extras 28 | * or fragment arguments. The extra will automatically be cast to the field type. If no key is 29 | * provided, the variable name will be used. 30 | * 31 | *

32 |  * {@literal @}BindExtra("key") String title;
33 |  * {@literal @}BindExtra String content; // "content" is the key for the extra
34 |  * 
35 | */ 36 | @Retention(CLASS) 37 | @Target(FIELD) 38 | public @interface BindExtra { 39 | String value() default ""; 40 | } 41 | -------------------------------------------------------------------------------- /dart-annotations/src/main/java/dart/DartModel.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Jake Wharton 3 | * Copyright 2014 Prateek Srivastava (@f2prateek) 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package dart; 19 | 20 | import static java.lang.annotation.ElementType.FIELD; 21 | import static java.lang.annotation.ElementType.TYPE; 22 | import static java.lang.annotation.RetentionPolicy.CLASS; 23 | 24 | import java.lang.annotation.Retention; 25 | import java.lang.annotation.Target; 26 | 27 | @Retention(CLASS) 28 | @Target({TYPE, FIELD}) 29 | public @interface DartModel {} 30 | -------------------------------------------------------------------------------- /dart-common/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java-library' 2 | apply from: rootProject.file('gradle/gradle-mvn-push.gradle') 3 | 4 | sourceCompatibility = JavaVersion.VERSION_1_8 5 | targetCompatibility = JavaVersion.VERSION_1_8 6 | 7 | 8 | dependencies { 9 | implementation project(':dart-annotations') 10 | } 11 | -------------------------------------------------------------------------------- /dart-common/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_ARTIFACT_ID=dart-common 2 | POM_NAME=Dart Common Lib 3 | POM_PACKAGING=jar -------------------------------------------------------------------------------- /dart-common/src/main/java/dart/common/BaseGenerator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Jake Wharton 3 | * Copyright 2014 Prateek Srivastava (@f2prateek) 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package dart.common; 19 | 20 | /** Base class of code generators. They generate java code. */ 21 | public abstract class BaseGenerator { 22 | 23 | /** 24 | * Create all Java code 25 | * 26 | * @return the javacode as string. 27 | */ 28 | public abstract String brewJava(); 29 | 30 | /** @return the Fully Qualified Class Name of the generated code. */ 31 | public abstract String getFqcn(); 32 | } 33 | -------------------------------------------------------------------------------- /dart-common/src/main/java/dart/common/Binding.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Jake Wharton 3 | * Copyright 2014 Prateek Srivastava (@f2prateek) 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package dart.common; 19 | 20 | /** A field or method extra binding. */ 21 | public interface Binding { 22 | /** A description of the binding in human readable form (e.g., "field 'foo'"). */ 23 | String getDescription(); 24 | 25 | /** 26 | * False if any annotation named {@code Optional} or {@code Nullable} is present on the binding. 27 | */ 28 | boolean isRequired(); 29 | } 30 | -------------------------------------------------------------------------------- /dart-common/src/main/java/dart/common/ExtraBindingTarget.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Jake Wharton 3 | * Copyright 2014 Prateek Srivastava (@f2prateek) 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package dart.common; 19 | 20 | import static dart.common.util.DartModelUtil.DART_MODEL_SUFFIX; 21 | 22 | import java.util.ArrayList; 23 | import java.util.LinkedHashMap; 24 | import java.util.List; 25 | import java.util.Map; 26 | import javax.lang.model.element.TypeElement; 27 | import javax.lang.model.type.TypeMirror; 28 | 29 | public class ExtraBindingTarget { 30 | public final Map bindingMap = new LinkedHashMap<>(); 31 | public final String classPackage; 32 | public final String className; 33 | public String parentPackage; 34 | public String parentClass; 35 | // Closest ancestor with required fields 36 | // we could have made a simpler model and just remember 37 | // the name of the required state but we decided to make a richer model 38 | // and to remember the name of the full ancestor class that contains required fields. 39 | // Closest here means first one in the hierarchy, we discover it without scanning the hierarchy, 40 | // just having a look at the parent class is enough to retrieve this information. 41 | public String closestRequiredAncestorPackage; 42 | public String closestRequiredAncestorClass; 43 | 44 | public boolean hasRequiredFields; 45 | public boolean topLevel; 46 | public List childClasses; 47 | 48 | public ExtraBindingTarget(String classPackage, String className) { 49 | this.classPackage = classPackage; 50 | this.className = className.substring(0, className.lastIndexOf(DART_MODEL_SUFFIX)); 51 | this.childClasses = new ArrayList<>(); 52 | this.topLevel = false; 53 | } 54 | 55 | public String getFQN() { 56 | return classPackage + "." + className; 57 | } 58 | 59 | public String getParentFQN() { 60 | return parentPackage + "." + parentClass; 61 | } 62 | 63 | public void addField(String key, String name, TypeMirror type, boolean required, boolean parcel) { 64 | ExtraInjection extraInjection = bindingMap.get(key); 65 | if (extraInjection == null) { 66 | extraInjection = new ExtraInjection(key); 67 | bindingMap.put(key, extraInjection); 68 | } 69 | extraInjection.addFieldBinding(new FieldBinding(name, type, required, parcel)); 70 | hasRequiredFields = hasRequiredFields || required; 71 | } 72 | 73 | public void addChild(TypeElement typeElement) { 74 | childClasses.add(typeElement); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /dart-common/src/main/java/dart/common/ExtraInjection.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Jake Wharton 3 | * Copyright 2014 Prateek Srivastava (@f2prateek) 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package dart.common; 19 | 20 | import java.util.ArrayList; 21 | import java.util.Collection; 22 | import java.util.LinkedHashSet; 23 | import java.util.List; 24 | import java.util.Set; 25 | 26 | public final class ExtraInjection { 27 | private final String key; 28 | private final Set fieldBindings = new LinkedHashSet(); 29 | 30 | ExtraInjection(String key) { 31 | this.key = key; 32 | } 33 | 34 | public String getKey() { 35 | return key; 36 | } 37 | 38 | public Collection getFieldBindings() { 39 | return fieldBindings; 40 | } 41 | 42 | public List getRequiredBindings() { 43 | List requiredBindings = new ArrayList(); 44 | for (FieldBinding fieldBinding : fieldBindings) { 45 | if (fieldBinding.isRequired()) { 46 | requiredBindings.add(fieldBinding); 47 | } 48 | } 49 | return requiredBindings; 50 | } 51 | 52 | public void addFieldBinding(FieldBinding fieldBinding) { 53 | fieldBindings.add(fieldBinding); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /dart-common/src/main/java/dart/common/FieldBinding.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Jake Wharton 3 | * Copyright 2014 Prateek Srivastava (@f2prateek) 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package dart.common; 19 | 20 | import javax.lang.model.type.TypeMirror; 21 | 22 | public final class FieldBinding implements Binding { 23 | private final String name; 24 | private final TypeMirror type; 25 | private final boolean required; 26 | private final boolean parcel; 27 | 28 | FieldBinding(String name, TypeMirror type, boolean required, boolean parcel) { 29 | this.name = name; 30 | this.type = type; 31 | this.required = required; 32 | this.parcel = parcel; 33 | } 34 | 35 | public String getName() { 36 | return name; 37 | } 38 | 39 | public TypeMirror getType() { 40 | return type; 41 | } 42 | 43 | @Override 44 | public String getDescription() { 45 | return "field '" + name + "'"; 46 | } 47 | 48 | @Override 49 | public boolean isRequired() { 50 | return required; 51 | } 52 | 53 | public boolean isParcel() { 54 | return parcel; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /dart-common/src/main/java/dart/common/NavigationModelBindingTarget.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Jake Wharton 3 | * Copyright 2014 Prateek Srivastava (@f2prateek) 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package dart.common; 19 | 20 | public class NavigationModelBindingTarget { 21 | public final String classPackage; 22 | public final String className; 23 | public final String navigationModelPackage; 24 | public final String navigationModelClass; 25 | public String navigationModelFieldName; 26 | public String parentPackage; 27 | public String parentClass; 28 | 29 | public NavigationModelBindingTarget( 30 | String classPackage, 31 | String className, 32 | String navigationModelPackage, 33 | String navigationModelClass, 34 | String navigationModelFieldName) { 35 | this.classPackage = classPackage; 36 | this.className = className; 37 | this.navigationModelPackage = navigationModelPackage; 38 | this.navigationModelClass = navigationModelClass; 39 | this.navigationModelFieldName = navigationModelFieldName; 40 | } 41 | 42 | public String getFQN() { 43 | return classPackage + "." + className; 44 | } 45 | 46 | public String getParentFQN() { 47 | return parentPackage + "." + parentClass; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /dart-common/src/main/java/dart/common/util/BindExtraUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Jake Wharton 3 | * Copyright 2014 Prateek Srivastava (@f2prateek) 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package dart.common.util; 19 | 20 | import static javax.lang.model.element.Modifier.PRIVATE; 21 | import static javax.lang.model.element.Modifier.STATIC; 22 | 23 | import dart.BindExtra; 24 | import dart.common.ExtraBindingTarget; 25 | import java.io.PrintWriter; 26 | import java.io.StringWriter; 27 | import java.util.Map; 28 | import java.util.Set; 29 | import javax.annotation.processing.RoundEnvironment; 30 | import javax.lang.model.element.Element; 31 | import javax.lang.model.element.Modifier; 32 | import javax.lang.model.element.TypeElement; 33 | import javax.lang.model.type.TypeMirror; 34 | 35 | public class BindExtraUtil { 36 | 37 | private final CompilerUtil compilerUtil; 38 | private final ParcelerUtil parcelerUtil; 39 | private final LoggingUtil loggingUtil; 40 | private final ExtraBindingTargetUtil extraBindingTargetUtil; 41 | private final DartModelUtil dartModelUtil; 42 | 43 | private RoundEnvironment roundEnv; 44 | 45 | public BindExtraUtil( 46 | CompilerUtil compilerUtil, 47 | ParcelerUtil parcelerUtil, 48 | LoggingUtil loggingUtil, 49 | ExtraBindingTargetUtil extraBindingTargetUtil, 50 | DartModelUtil dartModelUtil) { 51 | this.compilerUtil = compilerUtil; 52 | this.parcelerUtil = parcelerUtil; 53 | this.loggingUtil = loggingUtil; 54 | this.extraBindingTargetUtil = extraBindingTargetUtil; 55 | this.dartModelUtil = dartModelUtil; 56 | } 57 | 58 | public void setRoundEnvironment(RoundEnvironment roundEnv) { 59 | this.roundEnv = roundEnv; 60 | } 61 | 62 | public void parseBindExtraAnnotatedElements(Map targetClassMap) { 63 | for (Element element : roundEnv.getElementsAnnotatedWith(BindExtra.class)) { 64 | try { 65 | parseInjectExtra(element, targetClassMap); 66 | } catch (Exception e) { 67 | StringWriter stackTrace = new StringWriter(); 68 | e.printStackTrace(new PrintWriter(stackTrace)); 69 | loggingUtil.error( 70 | element, 71 | "Unable to generate extra binder when parsing @BindExtra.\n\n%s", 72 | stackTrace.toString()); 73 | } 74 | } 75 | } 76 | 77 | public void parseInjectExtra( 78 | Element element, Map targetClassMap) { 79 | // Verify common generated code restrictions. 80 | if (!isValidUsageOfBindExtra(element)) { 81 | return; 82 | } 83 | 84 | final TypeElement enclosingElement = (TypeElement) element.getEnclosingElement(); 85 | ExtraBindingTarget extraBindingTarget = targetClassMap.get(enclosingElement); 86 | if (extraBindingTarget == null) { 87 | // The ExtraBindingTarget was already created, @DartModel processed first 88 | if (!dartModelUtil.isValidUsageOfDartModel(enclosingElement)) { 89 | return; 90 | } 91 | extraBindingTarget = extraBindingTargetUtil.createTargetClass(enclosingElement); 92 | targetClassMap.put(enclosingElement, extraBindingTarget); 93 | } 94 | 95 | final String annotationValue = element.getAnnotation(BindExtra.class).value(); 96 | 97 | final String name = element.getSimpleName().toString(); 98 | final String key = StringUtil.isNullOrEmpty(annotationValue) ? name : annotationValue; 99 | final TypeMirror type = element.asType(); 100 | final boolean required = isRequiredInjection(element); 101 | final boolean parcel = 102 | parcelerUtil.isParcelerAvailable() && parcelerUtil.isValidExtraTypeForParceler(type); 103 | extraBindingTarget.addField(key, name, type, required, parcel); 104 | } 105 | 106 | private boolean isValidUsageOfBindExtra(Element element) { 107 | final TypeElement enclosingElement = (TypeElement) element.getEnclosingElement(); 108 | boolean valid = true; 109 | 110 | // Verify modifiers. 111 | Set modifiers = element.getModifiers(); 112 | if (modifiers.contains(PRIVATE) || modifiers.contains(STATIC)) { 113 | loggingUtil.error( 114 | element, 115 | "@BindExtra field must not be private or static. (%s.%s)", 116 | enclosingElement.getQualifiedName(), 117 | element.getSimpleName()); 118 | valid = false; 119 | } 120 | 121 | // Verify that the type is primitive, serializable or parcelable. 122 | TypeMirror typeElement = element.asType(); 123 | if (!isValidExtraType(typeElement) 124 | && !(parcelerUtil.isParcelerAvailable() 125 | && parcelerUtil.isValidExtraTypeForParceler(typeElement))) { 126 | loggingUtil.error( 127 | element, 128 | "The fields of class annotated with @DartModel must be primitive, Serializable or " 129 | + "Parcelable (%s.%s).\n" 130 | + "If you use Parceler, all types supported by Parceler are allowed.", 131 | enclosingElement.getQualifiedName(), 132 | element.getSimpleName()); 133 | valid = false; 134 | } 135 | 136 | // Verify @BindExtra value. 137 | try { 138 | final String annotationValue = element.getAnnotation(BindExtra.class).value(); 139 | if (!StringUtil.isNullOrEmpty(annotationValue) 140 | && !StringUtil.isValidJavaIdentifier(annotationValue)) { 141 | loggingUtil.error( 142 | element, 143 | "@BindExtra key has to be a valid java variable identifier (%s#%s).\n" 144 | + "See https://docs.oracle.com/cd/E19798-01/821-1841/bnbuk/index.html", 145 | enclosingElement.getQualifiedName(), 146 | element.getSimpleName()); 147 | valid = false; 148 | } 149 | } catch (Exception e) { 150 | loggingUtil.error( 151 | element, 152 | "@BindExtra has an invalid value (%s#%s).", 153 | enclosingElement.getQualifiedName(), 154 | element.getSimpleName()); 155 | valid = false; 156 | } 157 | 158 | return valid; 159 | } 160 | 161 | private boolean isValidExtraType(TypeMirror type) { 162 | return compilerUtil.isSerializable(type) 163 | || compilerUtil.isParcelable(type) 164 | || compilerUtil.isCharSequence(type); 165 | } 166 | 167 | /** 168 | * Returns {@code true} if an binding is deemed to be required. Returns false when a field is 169 | * annotated with any annotation named {@code Optional} or {@code Nullable}. 170 | */ 171 | private boolean isRequiredInjection(Element element) { 172 | return !compilerUtil.hasAnnotationWithName(element, "Nullable"); 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /dart-common/src/main/java/dart/common/util/CompilerUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Jake Wharton 3 | * Copyright 2014 Prateek Srivastava (@f2prateek) 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package dart.common.util; 19 | 20 | import java.util.ArrayList; 21 | import java.util.Collection; 22 | import java.util.List; 23 | import java.util.Set; 24 | import javax.annotation.processing.ProcessingEnvironment; 25 | import javax.lang.model.element.AnnotationMirror; 26 | import javax.lang.model.element.Element; 27 | import javax.lang.model.element.TypeElement; 28 | import javax.lang.model.type.DeclaredType; 29 | import javax.lang.model.type.TypeKind; 30 | import javax.lang.model.type.TypeMirror; 31 | import javax.lang.model.util.Elements; 32 | import javax.lang.model.util.Types; 33 | 34 | /** Utility class for type and element related methods. */ 35 | public class CompilerUtil { 36 | 37 | private final Elements elementUtils; 38 | private final Types typeUtils; 39 | 40 | public CompilerUtil(ProcessingEnvironment processingEnv) { 41 | elementUtils = processingEnv.getElementUtils(); 42 | typeUtils = processingEnv.getTypeUtils(); 43 | } 44 | 45 | /** Finds the parent binder type in the supplied set, if any. */ 46 | public TypeElement findParent(TypeElement typeElement, Set parents) { 47 | TypeMirror type; 48 | while (true) { 49 | type = typeElement.getSuperclass(); 50 | if (type.getKind() == TypeKind.NONE) { 51 | return null; 52 | } 53 | typeElement = (TypeElement) ((DeclaredType) type).asElement(); 54 | if (containsTypeMirror(parents, type)) { 55 | return typeElement; 56 | } 57 | } 58 | } 59 | 60 | public boolean hasAnnotationWithFqcn(Element element, String annotationClassNameName) { 61 | if (element != null) { 62 | for (AnnotationMirror annotationMirror : element.getAnnotationMirrors()) { 63 | if (annotationMirror 64 | .getAnnotationType() 65 | .asElement() 66 | .toString() 67 | .equals(annotationClassNameName)) { 68 | return true; 69 | } 70 | } 71 | } 72 | return false; 73 | } 74 | 75 | /** 76 | * Returns {@code true} if the an annotation is found on the given element with the given class 77 | * name (not fully qualified). 78 | */ 79 | public boolean hasAnnotationWithName(Element element, String simpleName) { 80 | for (AnnotationMirror mirror : element.getAnnotationMirrors()) { 81 | final Element annnotationElement = mirror.getAnnotationType().asElement(); 82 | String annotationName = annnotationElement.getSimpleName().toString(); 83 | if (simpleName.equals(annotationName)) { 84 | return true; 85 | } 86 | } 87 | return false; 88 | } 89 | 90 | public boolean isSerializable(TypeMirror type) { 91 | return isAssignable(type, "java.io.Serializable"); 92 | } 93 | 94 | public boolean isParcelable(TypeMirror type) { 95 | return isAssignable(type, "android.os.Parcelable"); 96 | } 97 | 98 | public boolean isCharSequence(TypeMirror type) { 99 | return isAssignable(type, "java.lang.CharSequence"); 100 | } 101 | 102 | public boolean isAssignable(TypeMirror type, String assignableType) { 103 | return typeUtils.isAssignable(type, elementUtils.getTypeElement(assignableType).asType()); 104 | } 105 | 106 | public List getTypeElements(String[] classNames) { 107 | List elements = new ArrayList<>(); 108 | for (String className : classNames) { 109 | elements.add(this.elementUtils.getTypeElement(className)); 110 | } 111 | return elements; 112 | } 113 | 114 | public String getPackageName(TypeElement type) { 115 | return elementUtils.getPackageOf(type).getQualifiedName().toString(); 116 | } 117 | 118 | public String getClassName(TypeElement type, String packageName) { 119 | int packageLen = packageName.length() + 1; 120 | return type.getQualifiedName().toString().substring(packageLen); 121 | } 122 | 123 | public boolean existsWithin(TypeMirror type, List supportedTypes) { 124 | for (Element supportedType : supportedTypes) { 125 | if (typeUtils.erasure(type).equals(typeUtils.erasure(supportedType.asType()))) { 126 | return true; 127 | } 128 | } 129 | return false; 130 | } 131 | 132 | private boolean containsTypeMirror(Collection typeElements, TypeMirror query) { 133 | // Ensure we are checking against a type-erased version for normalization purposes. 134 | query = typeUtils.erasure(query); 135 | for (TypeElement element : typeElements) { 136 | final TypeMirror typeMirror = typeUtils.erasure(element.asType()); 137 | if (typeUtils.isSameType(typeMirror, query)) { 138 | return true; 139 | } 140 | } 141 | return false; 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /dart-common/src/main/java/dart/common/util/DartModelUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Jake Wharton 3 | * Copyright 2014 Prateek Srivastava (@f2prateek) 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package dart.common.util; 19 | 20 | import static javax.lang.model.element.ElementKind.CLASS; 21 | import static javax.lang.model.element.ElementKind.PACKAGE; 22 | import static javax.lang.model.element.Modifier.ABSTRACT; 23 | import static javax.lang.model.element.Modifier.PRIVATE; 24 | import static javax.lang.model.element.Modifier.STATIC; 25 | 26 | import dart.DartModel; 27 | import dart.common.ExtraBindingTarget; 28 | import java.io.PrintWriter; 29 | import java.io.StringWriter; 30 | import java.util.List; 31 | import java.util.Map; 32 | import java.util.Set; 33 | import javax.annotation.processing.RoundEnvironment; 34 | import javax.lang.model.element.ExecutableElement; 35 | import javax.lang.model.element.Modifier; 36 | import javax.lang.model.element.TypeElement; 37 | import javax.lang.model.util.ElementFilter; 38 | 39 | public class DartModelUtil { 40 | 41 | public static final String DART_MODEL_SUFFIX = "NavigationModel"; 42 | 43 | private final LoggingUtil loggingUtil; 44 | private final ExtraBindingTargetUtil extraBindingTargetUtil; 45 | private final CompilerUtil compilerUtil; 46 | 47 | private RoundEnvironment roundEnv; 48 | 49 | public DartModelUtil( 50 | LoggingUtil loggingUtil, 51 | ExtraBindingTargetUtil extraBindingTargetUtil, 52 | CompilerUtil compilerUtil) { 53 | this.loggingUtil = loggingUtil; 54 | this.extraBindingTargetUtil = extraBindingTargetUtil; 55 | this.compilerUtil = compilerUtil; 56 | } 57 | 58 | public void setRoundEnvironment(RoundEnvironment roundEnv) { 59 | this.roundEnv = roundEnv; 60 | } 61 | 62 | public void parseDartModelAnnotatedTypes(Map targetClassMap) { 63 | for (TypeElement element : 64 | ElementFilter.typesIn(roundEnv.getElementsAnnotatedWith(DartModel.class))) { 65 | try { 66 | parseDartModel(element, targetClassMap); 67 | } catch (Exception e) { 68 | StringWriter stackTrace = new StringWriter(); 69 | e.printStackTrace(new PrintWriter(stackTrace)); 70 | loggingUtil.error( 71 | element, 72 | "Unable to generate extra binder when parsing @DartModel.\n\n%s", 73 | stackTrace.toString()); 74 | } 75 | } 76 | } 77 | 78 | boolean isValidUsageOfDartModel(TypeElement element) { 79 | boolean valid = true; 80 | 81 | // Verify modifiers. 82 | Set modifiers = element.getModifiers(); 83 | if (modifiers.contains(PRIVATE) || modifiers.contains(STATIC) || modifiers.contains(ABSTRACT)) { 84 | loggingUtil.error( 85 | element, 86 | "DartModel class %s must not be private, static or abstract.", 87 | element.getSimpleName()); 88 | valid = false; 89 | } 90 | 91 | // Verify type. 92 | if (element.getKind() != CLASS) { 93 | loggingUtil.error(element, "DartModel element %s must be a class.", element.getSimpleName()); 94 | valid = false; 95 | } 96 | 97 | // Verify containing type. 98 | if (element.getEnclosingElement() == null 99 | || element.getEnclosingElement().getKind() != PACKAGE) { 100 | loggingUtil.error( 101 | element, "DartModel class %s must be a top level class.", element.getSimpleName()); 102 | valid = false; 103 | } 104 | 105 | // Verify default constructor. 106 | final ExecutableElement defaultConstructor = findDefaultConstructor(element); 107 | if (defaultConstructor == null) { 108 | loggingUtil.error( 109 | element, "DartModel class %s must have a default constructor.", element.getSimpleName()); 110 | valid = false; 111 | } 112 | 113 | // Verify default constructor visibility. 114 | if (defaultConstructor.getModifiers().contains(Modifier.PRIVATE)) { 115 | loggingUtil.error( 116 | element, 117 | "DartModel class %s default constructor must not be private.", 118 | element.getSimpleName()); 119 | valid = false; 120 | } 121 | 122 | // Verify Dart Model suffix. 123 | final String classPackage = compilerUtil.getPackageName(element); 124 | final String className = compilerUtil.getClassName(element, classPackage); 125 | if (!className.endsWith(DART_MODEL_SUFFIX)) { 126 | loggingUtil.error( 127 | element, 128 | "DartModel class %s does not follow the naming convention: my.package.TargetComponentNavigationModel.", 129 | element.getSimpleName()); 130 | valid = false; 131 | } 132 | 133 | return valid; 134 | } 135 | 136 | private void parseDartModel( 137 | TypeElement element, Map targetClassMap) { 138 | // The ExtraBindingTarget was already created, @BindExtra processed first 139 | if (targetClassMap.containsKey(element)) { 140 | return; 141 | } 142 | 143 | // Verify common generated code restrictions. 144 | if (!isValidUsageOfDartModel(element)) { 145 | return; 146 | } 147 | 148 | // Assemble information on the binding point. 149 | final ExtraBindingTarget navigationModelTarget = 150 | extraBindingTargetUtil.createTargetClass(element); 151 | targetClassMap.put(element, navigationModelTarget); 152 | } 153 | 154 | private ExecutableElement findDefaultConstructor(TypeElement element) { 155 | final List constructors = 156 | ElementFilter.constructorsIn(element.getEnclosedElements()); 157 | for (ExecutableElement constructor : constructors) { 158 | if (constructor.getParameters().isEmpty()) { 159 | return constructor; 160 | } 161 | } 162 | return null; 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /dart-common/src/main/java/dart/common/util/FileUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Jake Wharton 3 | * Copyright 2014 Prateek Srivastava (@f2prateek) 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package dart.common.util; 19 | 20 | import dart.common.BaseGenerator; 21 | import java.io.IOException; 22 | import java.io.Writer; 23 | import javax.annotation.processing.Filer; 24 | import javax.annotation.processing.ProcessingEnvironment; 25 | import javax.lang.model.element.Element; 26 | import javax.tools.JavaFileObject; 27 | 28 | public class FileUtil { 29 | 30 | private final Filer filer; 31 | 32 | private boolean isDebugEnabled = false; 33 | 34 | public FileUtil(ProcessingEnvironment processingEnv) { 35 | filer = processingEnv.getFiler(); 36 | } 37 | 38 | public void writeFile(BaseGenerator generator, Element... originatingElements) 39 | throws IOException { 40 | Writer writer = null; 41 | try { 42 | JavaFileObject jfo = filer.createSourceFile(generator.getFqcn(), originatingElements); 43 | writer = jfo.openWriter(); 44 | 45 | if (isDebugEnabled) { 46 | System.out.println("File generated:\n" + generator.brewJava() + "---"); 47 | } 48 | 49 | writer.write(generator.brewJava()); 50 | } finally { 51 | if (writer != null) { 52 | writer.close(); 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /dart-common/src/main/java/dart/common/util/LoggingUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Jake Wharton 3 | * Copyright 2014 Prateek Srivastava (@f2prateek) 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package dart.common.util; 19 | 20 | import static javax.tools.Diagnostic.Kind.ERROR; 21 | import static javax.tools.Diagnostic.Kind.WARNING; 22 | 23 | import javax.annotation.processing.Messager; 24 | import javax.annotation.processing.ProcessingEnvironment; 25 | import javax.lang.model.element.Element; 26 | 27 | /** Utility class for logging related methods. */ 28 | public class LoggingUtil { 29 | 30 | private final Messager messager; 31 | 32 | public LoggingUtil(ProcessingEnvironment processingEnv) { 33 | messager = processingEnv.getMessager(); 34 | } 35 | 36 | public void error(Element element, String message, Object... args) { 37 | messager.printMessage(ERROR, String.format(message, args), element); 38 | } 39 | 40 | public void warning(Element element, String message, Object... args) { 41 | messager.printMessage(WARNING, String.format(message, args), element); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /dart-common/src/main/java/dart/common/util/NavigationModelBindingTargetUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Jake Wharton 3 | * Copyright 2014 Prateek Srivastava (@f2prateek) 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package dart.common.util; 19 | 20 | import dart.common.NavigationModelBindingTarget; 21 | import java.util.Map; 22 | import java.util.Set; 23 | import javax.annotation.processing.ProcessingEnvironment; 24 | import javax.lang.model.element.TypeElement; 25 | import javax.lang.model.element.VariableElement; 26 | import javax.lang.model.type.DeclaredType; 27 | import javax.lang.model.type.TypeKind; 28 | import javax.lang.model.type.TypeMirror; 29 | import javax.lang.model.util.Elements; 30 | 31 | public class NavigationModelBindingTargetUtil { 32 | 33 | public static final String NAVIGATION_MODEL_BINDER_SUFFIX = "__NavigationModelBinder"; 34 | 35 | private final CompilerUtil compilerUtil; 36 | private final Elements elementUtils; 37 | 38 | public NavigationModelBindingTargetUtil( 39 | CompilerUtil compilerUtil, ProcessingEnvironment processingEnv) { 40 | this.compilerUtil = compilerUtil; 41 | elementUtils = processingEnv.getElementUtils(); 42 | } 43 | 44 | public NavigationModelBindingTarget createTargetClass( 45 | TypeElement classElement, VariableElement navigationModelVariableElement) { 46 | final String classPackage = compilerUtil.getPackageName(classElement); 47 | final String className = compilerUtil.getClassName(classElement, classPackage); 48 | final TypeElement navigationModelElement = 49 | (TypeElement) ((DeclaredType) navigationModelVariableElement.asType()).asElement(); 50 | final String navigationModelPackage = compilerUtil.getPackageName(navigationModelElement); 51 | final String navigationModelClass = 52 | compilerUtil.getClassName(navigationModelElement, navigationModelPackage); 53 | final String navigationModelFieldName = 54 | navigationModelVariableElement.getSimpleName().toString(); 55 | return new NavigationModelBindingTarget( 56 | classPackage, 57 | className, 58 | navigationModelPackage, 59 | navigationModelClass, 60 | navigationModelFieldName); 61 | } 62 | 63 | public void createBindingTargetTrees( 64 | Map targetClassMap) { 65 | final Set targetTypeElements = targetClassMap.keySet(); 66 | for (TypeElement typeElement : targetTypeElements) { 67 | TypeElement parentTypeElement = compilerUtil.findParent(typeElement, targetTypeElements); 68 | if (parentTypeElement != null) { 69 | final NavigationModelBindingTarget target = targetClassMap.get(typeElement); 70 | final NavigationModelBindingTarget parentTarget = targetClassMap.get(parentTypeElement); 71 | target.parentPackage = parentTarget.classPackage; 72 | target.parentClass = parentTarget.className; 73 | } 74 | } 75 | checkForParentsOutside(targetClassMap); 76 | } 77 | 78 | private void checkForParentsOutside( 79 | Map targetClassMap) { 80 | for (Map.Entry target : targetClassMap.entrySet()) { 81 | final TypeElement element = target.getKey(); 82 | final NavigationModelBindingTarget navigationModelBindingTarget = target.getValue(); 83 | // if it does not have a parent already, inside the module, look outside 84 | if (navigationModelBindingTarget.parentPackage == null) { 85 | TypeElement ancestorElement = findClosestAncestorWithNavigationModelBinder(element); 86 | if (ancestorElement != null) { 87 | navigationModelBindingTarget.parentPackage = compilerUtil.getPackageName(ancestorElement); 88 | navigationModelBindingTarget.parentClass = 89 | compilerUtil.getClassName( 90 | ancestorElement, navigationModelBindingTarget.parentPackage); 91 | } 92 | } 93 | } 94 | } 95 | 96 | private TypeElement findClosestAncestorWithNavigationModelBinder(TypeElement element) { 97 | while (true) { 98 | final TypeMirror superType = element.getSuperclass(); 99 | if (superType.getKind() == TypeKind.NONE) { 100 | // Got to the oldest ancestor and none contains NavigationModelModelBinder 101 | return null; 102 | } 103 | element = (TypeElement) ((DeclaredType) superType).asElement(); 104 | // ancestor contains a NavigationModel field 105 | if (getNavigationModelBinder(element) != null) { 106 | return element; 107 | } 108 | } 109 | } 110 | 111 | private TypeElement getNavigationModelBinder(TypeElement element) { 112 | final String modelFQN = element.getQualifiedName().toString(); 113 | return elementUtils.getTypeElement(modelFQN + NAVIGATION_MODEL_BINDER_SUFFIX); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /dart-common/src/main/java/dart/common/util/NavigationModelFieldUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Jake Wharton 3 | * Copyright 2014 Prateek Srivastava (@f2prateek) 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package dart.common.util; 19 | 20 | import static javax.lang.model.element.Modifier.PRIVATE; 21 | import static javax.lang.model.element.Modifier.STATIC; 22 | 23 | import dart.DartModel; 24 | import dart.common.NavigationModelBindingTarget; 25 | import java.io.PrintWriter; 26 | import java.io.StringWriter; 27 | import java.util.Map; 28 | import java.util.Set; 29 | import javax.annotation.processing.RoundEnvironment; 30 | import javax.lang.model.element.Modifier; 31 | import javax.lang.model.element.TypeElement; 32 | import javax.lang.model.element.VariableElement; 33 | import javax.lang.model.util.ElementFilter; 34 | 35 | public class NavigationModelFieldUtil { 36 | 37 | private final LoggingUtil loggingUtil; 38 | private final NavigationModelBindingTargetUtil navigationModelBindingTargetUtil; 39 | 40 | private RoundEnvironment roundEnv; 41 | 42 | public NavigationModelFieldUtil( 43 | LoggingUtil loggingUtil, NavigationModelBindingTargetUtil navigationModelBindingTargetUtil) { 44 | this.loggingUtil = loggingUtil; 45 | this.navigationModelBindingTargetUtil = navigationModelBindingTargetUtil; 46 | } 47 | 48 | public void setRoundEnvironment(RoundEnvironment roundEnv) { 49 | this.roundEnv = roundEnv; 50 | } 51 | 52 | public void parseDartModelAnnotatedFields( 53 | Map targetClassMap) { 54 | for (VariableElement element : 55 | ElementFilter.fieldsIn(roundEnv.getElementsAnnotatedWith(DartModel.class))) { 56 | try { 57 | parseNavigationModelField(element, targetClassMap); 58 | } catch (Exception e) { 59 | StringWriter stackTrace = new StringWriter(); 60 | e.printStackTrace(new PrintWriter(stackTrace)); 61 | loggingUtil.error( 62 | element, 63 | "Unable to generate extra binder when parsing @DartModel.\n\n%s", 64 | stackTrace.toString()); 65 | } 66 | } 67 | } 68 | 69 | private void parseNavigationModelField( 70 | VariableElement element, Map targetClassMap) { 71 | final TypeElement enclosingElement = (TypeElement) element.getEnclosingElement(); 72 | if (targetClassMap.containsKey(enclosingElement)) { 73 | loggingUtil.error( 74 | enclosingElement, 75 | "Component %s cannot bind more than one NavigationModel.", 76 | enclosingElement.getSimpleName()); 77 | return; 78 | } 79 | 80 | // Verify common generated code restrictions. 81 | if (!isValidUsageOfNavigationModelField(element)) { 82 | return; 83 | } 84 | 85 | // Assemble information on the binding point. 86 | final NavigationModelBindingTarget navigationModelBindingTarget = 87 | navigationModelBindingTargetUtil.createTargetClass(enclosingElement, element); 88 | targetClassMap.put(enclosingElement, navigationModelBindingTarget); 89 | } 90 | 91 | private boolean isValidUsageOfNavigationModelField(VariableElement element) { 92 | final TypeElement enclosingElement = (TypeElement) element.getEnclosingElement(); 93 | boolean valid = true; 94 | 95 | // Verify modifiers. 96 | Set modifiers = element.getModifiers(); 97 | if (modifiers.contains(PRIVATE) || modifiers.contains(STATIC)) { 98 | loggingUtil.error( 99 | element, 100 | "@DartModel field must not be private or static. (%s.%s)", 101 | enclosingElement.getQualifiedName(), 102 | element.getSimpleName()); 103 | valid = false; 104 | } 105 | 106 | return valid; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /dart-common/src/main/java/dart/common/util/ParcelerUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Jake Wharton 3 | * Copyright 2014 Prateek Srivastava (@f2prateek) 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package dart.common.util; 19 | 20 | import java.util.List; 21 | import javax.annotation.processing.ProcessingEnvironment; 22 | import javax.lang.model.element.Element; 23 | import javax.lang.model.type.DeclaredType; 24 | import javax.lang.model.type.TypeMirror; 25 | import javax.lang.model.util.Elements; 26 | import javax.lang.model.util.Types; 27 | 28 | /** Utility class for Parceler library related methods. */ 29 | public class ParcelerUtil { 30 | 31 | private final CompilerUtil compilerUtil; 32 | private final Elements elementUtils; 33 | private final Types typeUtils; 34 | 35 | private final List singleCollections; 36 | private final List doubleCollections; 37 | 38 | // Flag to force enabling/disabling Parceler. 39 | // Used for testing. 40 | private final boolean isEnabled; 41 | 42 | public ParcelerUtil( 43 | CompilerUtil compilerUtil, ProcessingEnvironment processingEnv, boolean enable) { 44 | this.compilerUtil = compilerUtil; 45 | elementUtils = processingEnv.getElementUtils(); 46 | typeUtils = processingEnv.getTypeUtils(); 47 | isEnabled = enable; 48 | 49 | singleCollections = 50 | compilerUtil.getTypeElements( 51 | new String[] { 52 | "java.util.List", "java.util.ArrayList", "java.util.LinkedList", "java.util.Set", 53 | "java.util.HashSet", "java.util.SortedSet", "java.util.TreeSet", 54 | "java.util.LinkedHashSet", 55 | "android.util.SparseArray" 56 | }); 57 | 58 | doubleCollections = 59 | compilerUtil.getTypeElements( 60 | new String[] { 61 | "java.util.Map", 62 | "java.util.HashMap", 63 | "java.util.LinkedHashMap", 64 | "java.util.SortedMap", 65 | "java.util.TreeMap" 66 | }); 67 | } 68 | 69 | public boolean isParcelerAvailable() { 70 | return isEnabled && elementUtils.getTypeElement("org.parceler.Parcel") != null; 71 | } 72 | 73 | public boolean isValidExtraTypeForParceler(TypeMirror type) { 74 | return isValidForParceler(type, false); 75 | } 76 | 77 | private boolean isValidForParceler(TypeMirror type, boolean subCollection) { 78 | if (subCollection && (compilerUtil.isSerializable(type) || compilerUtil.isParcelable(type))) { 79 | return true; 80 | } 81 | if (isAnnotatedWithParcel(type)) { 82 | return true; 83 | } 84 | if (type instanceof DeclaredType) { 85 | DeclaredType declaredType = (DeclaredType) type; 86 | if (compilerUtil.existsWithin(type, singleCollections)) { 87 | return isValidForParceler(declaredType.getTypeArguments().get(0), true); 88 | } 89 | if (compilerUtil.existsWithin(type, doubleCollections)) { 90 | return isValidForParceler(declaredType.getTypeArguments().get(0), true) 91 | && isValidForParceler(declaredType.getTypeArguments().get(1), true); 92 | } 93 | } 94 | return false; 95 | } 96 | 97 | private boolean isAnnotatedWithParcel(TypeMirror type) { 98 | return compilerUtil.hasAnnotationWithFqcn(typeUtils.asElement(type), "org.parceler.Parcel"); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /dart-common/src/main/java/dart/common/util/StringUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Jake Wharton 3 | * Copyright 2014 Prateek Srivastava (@f2prateek) 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package dart.common.util; 19 | 20 | import java.util.Arrays; 21 | import java.util.HashSet; 22 | import java.util.Set; 23 | 24 | /** Utility class for String related methods. */ 25 | public class StringUtil { 26 | 27 | // @formatter:off 28 | //You must go to Preferences->Code Style->General->Formatter Control 29 | // and check Enable formatter markers in comments for this to work. 30 | private static final Set JAVA_KEYWORDS = 31 | new HashSet<>( 32 | Arrays.asList( 33 | "abstract", 34 | "assert", 35 | "boolean", 36 | "break", 37 | "byte", 38 | "case", 39 | "catch", 40 | "char", 41 | "class", 42 | "const", 43 | "continue", 44 | "enum", 45 | "default", 46 | "do", 47 | "double", 48 | "else", 49 | "extends", 50 | "while", 51 | "false", 52 | "final", 53 | "finally", 54 | "float", 55 | "for", 56 | "goto", 57 | "if", 58 | "implements", 59 | "import", 60 | "instanceof", 61 | "int", 62 | "interface", 63 | "long", 64 | "native", 65 | "new", 66 | "null", 67 | "package", 68 | "private", 69 | "protected", 70 | "public", 71 | "return", 72 | "short", 73 | "static", 74 | "strictfp", 75 | "super", 76 | "switch", 77 | "synchronized", 78 | "this", 79 | "throw", 80 | "throws", 81 | "transient", 82 | "true", 83 | "try", 84 | "void", 85 | "volatile")); 86 | // @formatter:on 87 | 88 | /** 89 | * Returns true if the string is null or 0-length. 90 | * 91 | * @param str the string to be examined 92 | * @return true if str is null or zero length 93 | */ 94 | public static boolean isNullOrEmpty(String str) { 95 | return str == null || str.trim().length() == 0; 96 | } 97 | 98 | /** 99 | * Returns true if the string is a valid Java identifier. See Identifiers 101 | * 102 | * @param str the string to be examined 103 | * @return true if str is a valid Java identifier 104 | */ 105 | public static boolean isValidJavaIdentifier(String str) { 106 | if (isNullOrEmpty(str)) { 107 | return false; 108 | } 109 | if (JAVA_KEYWORDS.contains(str)) { 110 | return false; 111 | } 112 | if (!Character.isJavaIdentifierStart(str.charAt(0))) { 113 | return false; 114 | } 115 | for (int i = 1; i < str.length(); i++) { 116 | if (!Character.isJavaIdentifierPart(str.charAt(i))) { 117 | return false; 118 | } 119 | } 120 | return true; 121 | } 122 | 123 | /** 124 | * Returns true if the string is a valid Java full qualified class name. 125 | * 126 | * @param str the string to be examined 127 | * @return true if str is a valid Java Fqcn 128 | */ 129 | public static boolean isValidFqcn(String str) { 130 | if (isNullOrEmpty(str)) { 131 | return false; 132 | } 133 | final String[] parts = str.split("\\."); 134 | if (parts.length < 2) { 135 | return false; 136 | } 137 | for (String part : parts) { 138 | if (!isValidJavaIdentifier(part)) { 139 | return false; 140 | } 141 | } 142 | return true; 143 | } 144 | 145 | private StringUtil() {} 146 | } 147 | -------------------------------------------------------------------------------- /dart-processor/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java-library' 2 | apply from: rootProject.file('gradle/gradle-mvn-push.gradle') 3 | 4 | sourceCompatibility = JavaVersion.VERSION_1_8 5 | targetCompatibility = JavaVersion.VERSION_1_8 6 | 7 | 8 | dependencies { 9 | implementation project(':dart-annotations') 10 | implementation project(':dart-common') 11 | implementation project(':dart') 12 | implementation deps.javapoet 13 | implementation deps.parceler.runtime 14 | compileOnly deps.android.runtime 15 | 16 | testImplementation files(org.gradle.internal.jvm.Jvm.current().getToolsJar()) 17 | testImplementation deps.junit 18 | testImplementation deps.compiletesting 19 | testImplementation deps.truth 20 | testImplementation deps.fest 21 | testImplementation deps.android.runtime 22 | } 23 | -------------------------------------------------------------------------------- /dart-processor/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_ARTIFACT_ID=dart-processor 2 | POM_NAME=Dart Annotation Processor 3 | POM_PACKAGING=jar -------------------------------------------------------------------------------- /dart-processor/src/main/java/dart/processor/ExtraBinderGenerator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Jake Wharton 3 | * Copyright 2014 Prateek Srivastava (@f2prateek) 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package dart.processor; 19 | 20 | import static dart.common.util.DartModelUtil.DART_MODEL_SUFFIX; 21 | 22 | import com.squareup.javapoet.ClassName; 23 | import com.squareup.javapoet.JavaFile; 24 | import com.squareup.javapoet.MethodSpec; 25 | import com.squareup.javapoet.TypeName; 26 | import com.squareup.javapoet.TypeSpec; 27 | import dart.Dart; 28 | import dart.common.BaseGenerator; 29 | import dart.common.Binding; 30 | import dart.common.ExtraBindingTarget; 31 | import dart.common.ExtraInjection; 32 | import dart.common.FieldBinding; 33 | import java.util.Collection; 34 | import java.util.List; 35 | import javax.lang.model.element.Modifier; 36 | import javax.lang.model.type.TypeMirror; 37 | 38 | /** 39 | * Creates Java code to bind extras into an activity or a {@link android.os.Bundle}. 40 | * 41 | *

{@link Dart} to use this code at runtime. 42 | */ 43 | public class ExtraBinderGenerator extends BaseGenerator { 44 | 45 | private final ExtraBindingTarget target; 46 | 47 | public ExtraBinderGenerator(ExtraBindingTarget target) { 48 | this.target = target; 49 | } 50 | 51 | @Override 52 | public String brewJava() { 53 | TypeSpec.Builder binderTypeSpec = 54 | TypeSpec.classBuilder(binderClassName()).addModifiers(Modifier.PUBLIC); 55 | emitBind(binderTypeSpec); 56 | JavaFile javaFile = 57 | JavaFile.builder(target.classPackage, binderTypeSpec.build()) 58 | .addFileComment("Generated code from Dart. Do not modify!") 59 | .build(); 60 | return javaFile.toString(); 61 | } 62 | 63 | @Override 64 | public String getFqcn() { 65 | return target.classPackage + "." + binderClassName(); 66 | } 67 | 68 | private String binderClassName() { 69 | return target.className + DART_MODEL_SUFFIX + Dart.EXTRA_BINDER_SUFFIX; 70 | } 71 | 72 | private void emitBind(TypeSpec.Builder builder) { 73 | MethodSpec.Builder bindBuilder = 74 | MethodSpec.methodBuilder("bind") 75 | .addModifiers(Modifier.PUBLIC, Modifier.STATIC) 76 | .addParameter(ClassName.get(Dart.Finder.class), "finder") 77 | .addParameter(ClassName.bestGuess(target.getFQN() + DART_MODEL_SUFFIX), "target") 78 | .addParameter(ClassName.get(Object.class), "source"); 79 | 80 | if (target.parentPackage != null) { 81 | // Emit a call to the superclass binder, if any. 82 | bindBuilder.addStatement( 83 | "$T.bind(finder, target, source)", 84 | ClassName.bestGuess( 85 | target.getParentFQN() + DART_MODEL_SUFFIX + Dart.EXTRA_BINDER_SUFFIX)); 86 | } 87 | 88 | // Local variable in which all extras will be temporarily stored. 89 | bindBuilder.addStatement("Object object"); 90 | 91 | // Loop over each extras binding and emit it. 92 | for (ExtraInjection binding : target.bindingMap.values()) { 93 | emitExtraInjection(bindBuilder, binding); 94 | } 95 | 96 | builder.addMethod(bindBuilder.build()); 97 | } 98 | 99 | private void emitExtraInjection(MethodSpec.Builder builder, ExtraInjection binding) { 100 | builder.addStatement("object = finder.getExtra(source, $S)", binding.getKey()); 101 | 102 | List requiredBindings = binding.getRequiredBindings(); 103 | if (!requiredBindings.isEmpty()) { 104 | builder 105 | .beginControlFlow("if (object == null)") 106 | .addStatement( 107 | "throw new IllegalStateException(\"Required extra with key '$L' for $L " 108 | + "was not found. If this extra is optional add '@Nullable' annotation.\")", 109 | binding.getKey(), 110 | emitHumanDescription(requiredBindings)) 111 | .endControlFlow(); 112 | emitFieldBindings(builder, binding); 113 | } else { 114 | // an optional extra, wrap it in a check to keep original value, if any 115 | builder.beginControlFlow("if (object != null)"); 116 | emitFieldBindings(builder, binding); 117 | builder.endControlFlow(); 118 | } 119 | } 120 | 121 | private void emitFieldBindings(MethodSpec.Builder builder, ExtraInjection binding) { 122 | Collection fieldBindings = binding.getFieldBindings(); 123 | if (fieldBindings.isEmpty()) { 124 | return; 125 | } 126 | 127 | for (FieldBinding fieldBinding : fieldBindings) { 128 | builder.addCode("target.$L = ", fieldBinding.getName()); 129 | 130 | if (fieldBinding.isParcel()) { 131 | builder.addCode("org.parceler.Parcels.unwrap((android.os.Parcelable) object);\n"); 132 | } else { 133 | emitCast(builder, fieldBinding.getType()); 134 | builder.addCode("object;\n"); 135 | } 136 | } 137 | } 138 | 139 | private void emitCast(MethodSpec.Builder builder, TypeMirror fieldType) { 140 | builder.addCode("($T) ", TypeName.get(fieldType)); 141 | } 142 | 143 | //TODO add android annotations dependency to get that annotation plus others. 144 | 145 | /** Visible for testing */ 146 | String emitHumanDescription(List bindings) { 147 | StringBuilder builder = new StringBuilder(); 148 | switch (bindings.size()) { 149 | case 1: 150 | builder.append(bindings.get(0).getDescription()); 151 | break; 152 | case 2: 153 | builder 154 | .append(bindings.get(0).getDescription()) 155 | .append(" and ") 156 | .append(bindings.get(1).getDescription()); 157 | break; 158 | default: 159 | for (int i = 0, count = bindings.size(); i < count; i++) { 160 | Binding requiredField = bindings.get(i); 161 | if (i != 0) { 162 | builder.append(", "); 163 | } 164 | if (i == count - 1) { 165 | builder.append("and "); 166 | } 167 | builder.append(requiredField.getDescription()); 168 | } 169 | break; 170 | } 171 | return builder.toString(); 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /dart-processor/src/main/java/dart/processor/ExtraBinderProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Jake Wharton 3 | * Copyright 2014 Prateek Srivastava (@f2prateek) 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package dart.processor; 19 | 20 | import dart.common.ExtraBindingTarget; 21 | import dart.common.util.BindExtraUtil; 22 | import dart.common.util.CompilerUtil; 23 | import dart.common.util.DartModelUtil; 24 | import dart.common.util.ExtraBindingTargetUtil; 25 | import dart.common.util.FileUtil; 26 | import dart.common.util.LoggingUtil; 27 | import dart.common.util.ParcelerUtil; 28 | import java.io.IOException; 29 | import java.util.HashMap; 30 | import java.util.LinkedHashMap; 31 | import java.util.Map; 32 | import java.util.Set; 33 | import javax.annotation.processing.AbstractProcessor; 34 | import javax.annotation.processing.ProcessingEnvironment; 35 | import javax.annotation.processing.RoundEnvironment; 36 | import javax.annotation.processing.SupportedAnnotationTypes; 37 | import javax.lang.model.SourceVersion; 38 | import javax.lang.model.element.TypeElement; 39 | 40 | @SupportedAnnotationTypes({ 41 | ExtraBinderProcessor.NAVIGATION_MODEL_ANNOTATION_CLASS_NAME, 42 | ExtraBinderProcessor.EXTRA_ANNOTATION_CLASS_NAME 43 | }) 44 | public final class ExtraBinderProcessor extends AbstractProcessor { 45 | 46 | static final String NAVIGATION_MODEL_ANNOTATION_CLASS_NAME = "dart.DartModel"; 47 | static final String EXTRA_ANNOTATION_CLASS_NAME = "dart.BindExtra"; 48 | 49 | private LoggingUtil loggingUtil; 50 | private FileUtil fileUtil; 51 | private ExtraBindingTargetUtil extraBindingTargetUtil; 52 | private DartModelUtil dartModelUtil; 53 | private BindExtraUtil bindExtraUtil; 54 | private Map allRoundsGeneratedToTypeElement = new HashMap<>(); 55 | 56 | private boolean usesParcelerOption = true; 57 | 58 | @Override 59 | public synchronized void init(ProcessingEnvironment processingEnv) { 60 | super.init(processingEnv); 61 | 62 | final CompilerUtil compilerUtil = new CompilerUtil(processingEnv); 63 | final ParcelerUtil parcelerUtil = 64 | new ParcelerUtil(compilerUtil, processingEnv, usesParcelerOption); 65 | loggingUtil = new LoggingUtil(processingEnv); 66 | fileUtil = new FileUtil(processingEnv); 67 | extraBindingTargetUtil = new ExtraBindingTargetUtil(compilerUtil, processingEnv, loggingUtil); 68 | dartModelUtil = new DartModelUtil(loggingUtil, extraBindingTargetUtil, compilerUtil); 69 | bindExtraUtil = 70 | new BindExtraUtil( 71 | compilerUtil, parcelerUtil, loggingUtil, extraBindingTargetUtil, dartModelUtil); 72 | } 73 | 74 | @Override 75 | public boolean process(Set annotations, RoundEnvironment roundEnv) { 76 | dartModelUtil.setRoundEnvironment(roundEnv); 77 | bindExtraUtil.setRoundEnvironment(roundEnv); 78 | 79 | Map targetClassMap = findAndParseTargets(); 80 | generateExtraBinders(targetClassMap); 81 | 82 | //return false here to let henson process the annotations too 83 | return false; 84 | } 85 | 86 | @Override 87 | public SourceVersion getSupportedSourceVersion() { 88 | return SourceVersion.latestSupported(); 89 | } 90 | 91 | /** 92 | * Flag to force enabling/disabling Parceler. Used for testing. 93 | * 94 | * @param enable whether Parceler should be enable 95 | */ 96 | public void enableParceler(boolean enable) { 97 | usesParcelerOption = enable; 98 | } 99 | 100 | private Map findAndParseTargets() { 101 | Map targetClassMap = new LinkedHashMap<>(); 102 | 103 | dartModelUtil.parseDartModelAnnotatedTypes(targetClassMap); 104 | bindExtraUtil.parseBindExtraAnnotatedElements(targetClassMap); 105 | extraBindingTargetUtil.createBindingTargetTrees(targetClassMap); 106 | 107 | return targetClassMap; 108 | } 109 | 110 | private void generateExtraBinders(Map targetClassMap) { 111 | for (Map.Entry entry : targetClassMap.entrySet()) { 112 | TypeElement typeElement = entry.getKey(); 113 | ExtraBindingTarget extraBindingTarget = entry.getValue(); 114 | 115 | //we unfortunately can't test that nothing is generated in a TRUTH based test 116 | try { 117 | ExtraBinderGenerator generator = new ExtraBinderGenerator(extraBindingTarget); 118 | fileUtil.writeFile(generator, typeElement); 119 | allRoundsGeneratedToTypeElement.put(generator.getFqcn(), typeElement); 120 | } catch (IOException e) { 121 | loggingUtil.error( 122 | typeElement, 123 | "Unable to write extra binder for type %s: %s", 124 | typeElement, 125 | e.getMessage()); 126 | } 127 | } 128 | } 129 | 130 | /*visible for testing*/ 131 | TypeElement getOriginatingElement(String generatedQualifiedName) { 132 | return allRoundsGeneratedToTypeElement.get(generatedQualifiedName); 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /dart-processor/src/main/java/dart/processor/NavigationModelBinderGenerator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Jake Wharton 3 | * Copyright 2014 Prateek Srivastava (@f2prateek) 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package dart.processor; 19 | 20 | import static com.squareup.javapoet.ClassName.bestGuess; 21 | import static com.squareup.javapoet.ClassName.get; 22 | import static dart.common.util.NavigationModelBindingTargetUtil.NAVIGATION_MODEL_BINDER_SUFFIX; 23 | 24 | import com.squareup.javapoet.JavaFile; 25 | import com.squareup.javapoet.MethodSpec; 26 | import com.squareup.javapoet.TypeSpec; 27 | import dart.Dart; 28 | import dart.common.BaseGenerator; 29 | import dart.common.NavigationModelBindingTarget; 30 | import javax.lang.model.element.Modifier; 31 | 32 | /** 33 | * Creates Java code to bind NavigationModel into an activity/services/fragment. 34 | * 35 | *

{@link Dart} to use this code at runtime. 36 | */ 37 | public class NavigationModelBinderGenerator extends BaseGenerator { 38 | 39 | private final NavigationModelBindingTarget target; 40 | 41 | public NavigationModelBinderGenerator(NavigationModelBindingTarget target) { 42 | this.target = target; 43 | } 44 | 45 | @Override 46 | public String brewJava() { 47 | TypeSpec.Builder binderTypeSpec = 48 | TypeSpec.classBuilder(binderClassName()).addModifiers(Modifier.PUBLIC); 49 | 50 | emitBind(binderTypeSpec); 51 | emitAssign(binderTypeSpec); 52 | 53 | JavaFile javaFile = 54 | JavaFile.builder(target.classPackage, binderTypeSpec.build()) 55 | .addFileComment("Generated code from Dart. Do not modify!") 56 | .build(); 57 | return javaFile.toString(); 58 | } 59 | 60 | @Override 61 | public String getFqcn() { 62 | return target.classPackage + "." + binderClassName(); 63 | } 64 | 65 | private String binderClassName() { 66 | return target.className + NAVIGATION_MODEL_BINDER_SUFFIX; 67 | } 68 | 69 | private void emitBind(TypeSpec.Builder builder) { 70 | MethodSpec.Builder bindBuilder = 71 | MethodSpec.methodBuilder("bind") 72 | .addModifiers(Modifier.PUBLIC, Modifier.STATIC) 73 | .addParameter(get(Dart.Finder.class), "finder") 74 | .addParameter(bestGuess(target.getFQN()), "target"); 75 | 76 | bindBuilder.addStatement( 77 | "target.$L = new $T()", 78 | target.navigationModelFieldName, 79 | get(target.navigationModelPackage, target.navigationModelClass)); 80 | 81 | bindBuilder.addStatement( 82 | "$T.bind(finder, target.$L, target)", 83 | get(target.navigationModelPackage, target.navigationModelClass + Dart.EXTRA_BINDER_SUFFIX), 84 | target.navigationModelFieldName); 85 | 86 | if (target.parentPackage != null) { 87 | // Emit a call to the superclass binder, if any. 88 | bindBuilder.addStatement( 89 | "$T.assign(target, target.$L)", 90 | bestGuess(target.getParentFQN() + NAVIGATION_MODEL_BINDER_SUFFIX), 91 | target.navigationModelFieldName); 92 | } 93 | 94 | builder.addMethod(bindBuilder.build()); 95 | } 96 | 97 | private void emitAssign(TypeSpec.Builder builder) { 98 | MethodSpec.Builder bindBuilder = 99 | MethodSpec.methodBuilder("assign") 100 | .addModifiers(Modifier.PUBLIC, Modifier.STATIC) 101 | .addParameter(bestGuess(target.getFQN()), "target") 102 | .addParameter( 103 | get(target.navigationModelPackage, target.navigationModelClass), "navigationModel"); 104 | 105 | bindBuilder.addStatement("target.$L = navigationModel", target.navigationModelFieldName); 106 | 107 | if (target.parentPackage != null) { 108 | // Emit a call to the superclass binder, if any. 109 | bindBuilder.addStatement( 110 | "$T.assign(target, navigationModel)", 111 | bestGuess(target.getParentFQN() + NAVIGATION_MODEL_BINDER_SUFFIX)); 112 | } 113 | 114 | builder.addMethod(bindBuilder.build()); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /dart-processor/src/main/java/dart/processor/NavigationModelBinderProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Jake Wharton 3 | * Copyright 2014 Prateek Srivastava (@f2prateek) 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package dart.processor; 19 | 20 | import dart.common.NavigationModelBindingTarget; 21 | import dart.common.util.CompilerUtil; 22 | import dart.common.util.FileUtil; 23 | import dart.common.util.LoggingUtil; 24 | import dart.common.util.NavigationModelBindingTargetUtil; 25 | import dart.common.util.NavigationModelFieldUtil; 26 | import java.io.IOException; 27 | import java.util.HashMap; 28 | import java.util.LinkedHashMap; 29 | import java.util.Map; 30 | import java.util.Set; 31 | import javax.annotation.processing.AbstractProcessor; 32 | import javax.annotation.processing.ProcessingEnvironment; 33 | import javax.annotation.processing.RoundEnvironment; 34 | import javax.annotation.processing.SupportedAnnotationTypes; 35 | import javax.lang.model.SourceVersion; 36 | import javax.lang.model.element.TypeElement; 37 | 38 | @SupportedAnnotationTypes({ 39 | NavigationModelBinderProcessor.NAVIGATION_MODEL_ANNOTATION_CLASS_NAME, 40 | }) 41 | public final class NavigationModelBinderProcessor extends AbstractProcessor { 42 | 43 | static final String NAVIGATION_MODEL_ANNOTATION_CLASS_NAME = "dart.DartModel"; 44 | 45 | private LoggingUtil loggingUtil; 46 | private FileUtil fileUtil; 47 | private NavigationModelBindingTargetUtil navigationModelBindingTargetUtil; 48 | private NavigationModelFieldUtil navigationModelFieldUtil; 49 | private Map allRoundsGeneratedToTypeElement = new HashMap<>(); 50 | 51 | @Override 52 | public synchronized void init(ProcessingEnvironment processingEnv) { 53 | super.init(processingEnv); 54 | 55 | final CompilerUtil compilerUtil = new CompilerUtil(processingEnv); 56 | loggingUtil = new LoggingUtil(processingEnv); 57 | fileUtil = new FileUtil(processingEnv); 58 | navigationModelBindingTargetUtil = 59 | new NavigationModelBindingTargetUtil(compilerUtil, processingEnv); 60 | navigationModelFieldUtil = 61 | new NavigationModelFieldUtil(loggingUtil, navigationModelBindingTargetUtil); 62 | } 63 | 64 | @Override 65 | public boolean process(Set annotations, RoundEnvironment roundEnv) { 66 | navigationModelFieldUtil.setRoundEnvironment(roundEnv); 67 | 68 | Map targetClassMap = findAndParseTargets(); 69 | generateNavigationModelBinder(targetClassMap); 70 | 71 | //return false here to let henson process the annotations too 72 | return false; 73 | } 74 | 75 | @Override 76 | public SourceVersion getSupportedSourceVersion() { 77 | return SourceVersion.latestSupported(); 78 | } 79 | 80 | private Map findAndParseTargets() { 81 | Map targetClassMap = new LinkedHashMap<>(); 82 | 83 | navigationModelFieldUtil.parseDartModelAnnotatedFields(targetClassMap); 84 | navigationModelBindingTargetUtil.createBindingTargetTrees(targetClassMap); 85 | 86 | return targetClassMap; 87 | } 88 | 89 | private void generateNavigationModelBinder( 90 | Map targetClassMap) { 91 | for (Map.Entry entry : targetClassMap.entrySet()) { 92 | TypeElement typeElement = entry.getKey(); 93 | NavigationModelBindingTarget navigationModelBindingTarget = entry.getValue(); 94 | 95 | //we unfortunately can't test that nothing is generated in a TRUTH based test 96 | try { 97 | NavigationModelBinderGenerator generator = 98 | new NavigationModelBinderGenerator(navigationModelBindingTarget); 99 | fileUtil.writeFile(generator, typeElement); 100 | allRoundsGeneratedToTypeElement.put(generator.getFqcn(), typeElement); 101 | } catch (IOException e) { 102 | loggingUtil.error( 103 | typeElement, 104 | "Unable to write extra binder for type %s: %s", 105 | typeElement, 106 | e.getMessage()); 107 | } 108 | } 109 | } 110 | 111 | /*visible for testing*/ 112 | TypeElement getOriginatingElement(String generatedQualifiedName) { 113 | return allRoundsGeneratedToTypeElement.get(generatedQualifiedName); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /dart-processor/src/main/resources/META-INF/gradle/incremental.annotation.processors: -------------------------------------------------------------------------------- 1 | dart.processor.ExtraBinderProcessor,isolating 2 | dart.processor.NavigationModelBinderProcessor,isolating 3 | -------------------------------------------------------------------------------- /dart-processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2013 Jake Wharton 3 | # Copyright 2014 Prateek Srivastava (@f2prateek) 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | dart.processor.ExtraBinderProcessor 19 | dart.processor.NavigationModelBinderProcessor 20 | -------------------------------------------------------------------------------- /dart-processor/src/test/java/dart/processor/ExtraBinderGeneratorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Jake Wharton 3 | * Copyright 2014 Prateek Srivastava (@f2prateek) 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package dart.processor; 19 | 20 | import static java.util.Arrays.asList; 21 | import static org.fest.assertions.api.Assertions.assertThat; 22 | 23 | import dart.common.Binding; 24 | import dart.common.ExtraBindingTarget; 25 | import org.junit.Before; 26 | import org.junit.Test; 27 | 28 | public class ExtraBinderGeneratorTest { 29 | 30 | ExtraBinderGenerator extraBinderGenerator; 31 | 32 | @Before 33 | public void setup() { 34 | final ExtraBindingTarget extraBindingTarget = 35 | new ExtraBindingTarget("foo", "barNavigationModel"); 36 | extraBinderGenerator = new ExtraBinderGenerator(extraBindingTarget); 37 | } 38 | 39 | @Test 40 | public void humanDescriptionJoinWorks() { 41 | Binding one = new TestBinding("one"); 42 | Binding two = new TestBinding("two"); 43 | Binding three = new TestBinding("three"); 44 | 45 | String actual1 = extraBinderGenerator.emitHumanDescription(asList(one)); 46 | assertThat(actual1).isEqualTo("one"); 47 | 48 | String actual2 = extraBinderGenerator.emitHumanDescription(asList(one, two)); 49 | assertThat(actual2).isEqualTo("one and two"); 50 | 51 | String actual3 = extraBinderGenerator.emitHumanDescription(asList(one, two, three)); 52 | assertThat(actual3).isEqualTo("one, two, and three"); 53 | } 54 | 55 | private static class TestBinding implements Binding { 56 | private final String description; 57 | 58 | private TestBinding(String description) { 59 | this.description = description; 60 | } 61 | 62 | @Override 63 | public String getDescription() { 64 | return description; 65 | } 66 | 67 | @Override 68 | public boolean isRequired() { 69 | throw new AssertionError(); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /dart-processor/src/test/java/dart/processor/ProcessorTestUtilities.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Jake Wharton 3 | * Copyright 2014 Prateek Srivastava (@f2prateek) 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package dart.processor; 19 | 20 | import javax.lang.model.element.Element; 21 | import javax.lang.model.element.TypeElement; 22 | 23 | final class ProcessorTestUtilities { 24 | static ExtraBinderProcessor extraBinderProcessors() { 25 | return new ExtraBinderProcessor(); 26 | } 27 | 28 | static ExtraBinderProcessor extraBinderProcessorsWithoutParceler() { 29 | ExtraBinderProcessor bindExtraProcessor = new ExtraBinderProcessor(); 30 | bindExtraProcessor.enableParceler(false); 31 | return bindExtraProcessor; 32 | } 33 | 34 | static NavigationModelBinderProcessor navigationModelBinderProcessors() { 35 | return new NavigationModelBinderProcessor(); 36 | } 37 | 38 | static TypeElement getMostEnclosingElement(Element element) { 39 | if (element == null) { 40 | return null; 41 | } 42 | 43 | while (element.getEnclosingElement() != null 44 | && element.getEnclosingElement().getKind().isClass() 45 | || element.getEnclosingElement().getKind().isInterface()) { 46 | element = element.getEnclosingElement(); 47 | } 48 | return (TypeElement) element; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /dart-processor/src/test/java/dart/processor/data/ActivityWithNavigationModelField.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Jake Wharton 3 | * Copyright 2014 Prateek Srivastava (@f2prateek) 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package dart.processor.data; 19 | 20 | import dart.DartModel; 21 | 22 | public class ActivityWithNavigationModelField { 23 | @DartModel ActivityWithNavigationModelFieldNavigationModel navigationModel; 24 | } 25 | -------------------------------------------------------------------------------- /dart-processor/src/test/java/dart/processor/data/ActivityWithNavigationModelFieldNavigationModel.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Jake Wharton 3 | * Copyright 2014 Prateek Srivastava (@f2prateek) 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package dart.processor.data; 19 | 20 | import dart.DartModel; 21 | 22 | @DartModel 23 | public class ActivityWithNavigationModelFieldNavigationModel {} 24 | -------------------------------------------------------------------------------- /dart-processor/src/test/java/dart/processor/data/SubActivityWithNavigationModelField.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Jake Wharton 3 | * Copyright 2014 Prateek Srivastava (@f2prateek) 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package dart.processor.data; 19 | 20 | import dart.DartModel; 21 | 22 | public class SubActivityWithNavigationModelField extends ActivityWithNavigationModelField { 23 | @DartModel SubActivityWithNavigationModelFieldNavigationModel subNavigationModel; 24 | } 25 | -------------------------------------------------------------------------------- /dart-processor/src/test/java/dart/processor/data/SubActivityWithNavigationModelFieldNavigationModel.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Jake Wharton 3 | * Copyright 2014 Prateek Srivastava (@f2prateek) 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package dart.processor.data; 19 | 20 | import dart.DartModel; 21 | 22 | @DartModel 23 | public class SubActivityWithNavigationModelFieldNavigationModel 24 | extends ActivityWithNavigationModelFieldNavigationModel {} 25 | -------------------------------------------------------------------------------- /dart-processor/src/test/java/dart/processor/data/SubActivityWithNoNavigationModelField.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Jake Wharton 3 | * Copyright 2014 Prateek Srivastava (@f2prateek) 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package dart.processor.data; 19 | 20 | public class SubActivityWithNoNavigationModelField extends ActivityWithNavigationModelField {} 21 | -------------------------------------------------------------------------------- /dart-sample/app-navigation/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenLocal() 4 | jcenter() 5 | google() 6 | } 7 | 8 | dependencies { 9 | classpath deps.dart.gradlePlugin 10 | } 11 | } 12 | 13 | apply plugin: 'com.android.library' 14 | 15 | android { 16 | compileSdkVersion versions.compileSdk 17 | 18 | compileOptions { 19 | sourceCompatibility = JavaVersion.VERSION_1_8 20 | targetCompatibility = JavaVersion.VERSION_1_8 21 | } 22 | 23 | defaultConfig { 24 | minSdkVersion versions.minSdk 25 | targetSdkVersion versions.compileSdk 26 | versionCode 1 27 | versionName '1.0.0' 28 | } 29 | 30 | lintOptions { 31 | textReport true 32 | textOutput 'stdout' 33 | abortOnError false 34 | } 35 | 36 | buildTypes { 37 | debug { 38 | minifyEnabled false 39 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 40 | } 41 | } 42 | } 43 | 44 | dependencies { 45 | implementation deps.android.annotations 46 | implementation deps.dart.annotations 47 | implementation deps.dart.runtime 48 | implementation deps.henson.runtime 49 | implementation deps.parceler.runtime 50 | implementation project(':module1-navigation') 51 | 52 | annotationProcessor deps.henson.compiler 53 | annotationProcessor deps.dart.compiler 54 | } 55 | -------------------------------------------------------------------------------- /dart-sample/app-navigation/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | -------------------------------------------------------------------------------- /dart-sample/app-navigation/src/main/java/com/f2prateek/dart/example/SampleActivityNavigationModel.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Jake Wharton 3 | * Copyright 2014 Prateek Srivastava (@f2prateek) 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package com.f2prateek.dart.example; 19 | 20 | import android.support.annotation.Nullable; 21 | import android.util.SparseArray; 22 | import com.f2prateek.dart.model.ComplexParcelable; 23 | import com.f2prateek.dart.model.StringParcel; 24 | import dart.BindExtra; 25 | import java.util.List; 26 | 27 | public class SampleActivityNavigationModel { 28 | 29 | public static final String DEFAULT_EXTRA_VALUE = "a default value"; 30 | 31 | private static final String EXTRA_STRING = "extraString"; 32 | private static final String EXTRA_INT = "extraInt"; 33 | private static final String EXTRA_PARCELABLE = "extraParcelable"; 34 | private static final String EXTRA_PARCEL = "extraParcel"; 35 | private static final String EXTRA_LIST_PARCELABLE = "extraListParcelable"; 36 | private static final String EXTRA_SPARSE_ARRAY_PARCELABLE = "extraSparseArrayParcelable"; 37 | private static final String EXTRA_OPTIONAL = "extraOptional"; 38 | private static final String EXTRA_WITH_DEFAULT = "extraWithDefault"; 39 | 40 | public @BindExtra(EXTRA_STRING) String stringExtra; 41 | public @BindExtra(EXTRA_INT) int intExtra; 42 | public @BindExtra(EXTRA_PARCELABLE) ComplexParcelable parcelableExtra; 43 | public @BindExtra(EXTRA_PARCEL) StringParcel parcelExtra; 44 | public @BindExtra(EXTRA_LIST_PARCELABLE) List listParcelExtra; 45 | public @BindExtra(EXTRA_SPARSE_ARRAY_PARCELABLE) SparseArray sparseArrayParcelExtra; 46 | public @BindExtra(EXTRA_OPTIONAL) @Nullable String optionalExtra; 47 | public @BindExtra(EXTRA_WITH_DEFAULT) @Nullable String defaultExtra = DEFAULT_EXTRA_VALUE; 48 | public @BindExtra String defaultKeyExtra; 49 | } 50 | -------------------------------------------------------------------------------- /dart-sample/app/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | //this is used for development of the plugin 4 | mavenLocal() 5 | jcenter() 6 | google() 7 | } 8 | 9 | dependencies { 10 | classpath deps.dart.gradlePlugin 11 | } 12 | 13 | //this is used for development of the plugin 14 | configurations.classpath { 15 | resolutionStrategy.cacheChangingModulesFor 0, 'seconds' 16 | } 17 | } 18 | 19 | apply plugin: 'com.android.application' 20 | apply plugin: 'dart.henson-plugin' 21 | 22 | 23 | android { 24 | compileSdkVersion versions.compileSdk 25 | 26 | compileOptions { 27 | sourceCompatibility = JavaVersion.VERSION_1_8 28 | targetCompatibility = JavaVersion.VERSION_1_8 29 | } 30 | 31 | defaultConfig { 32 | applicationId 'com.f2prateek.dart.example' 33 | minSdkVersion versions.minSdk 34 | targetSdkVersion versions.compileSdk 35 | versionCode 1 36 | versionName '1.0.0' 37 | } 38 | 39 | lintOptions { 40 | textReport true 41 | textOutput 'stdout' 42 | abortOnError false 43 | } 44 | 45 | buildTypes { 46 | debug { 47 | minifyEnabled false 48 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 49 | } 50 | } 51 | } 52 | 53 | dependencies { 54 | implementation deps.butterknife.runtime 55 | implementation deps.dart.annotations 56 | implementation deps.dart.runtime 57 | implementation deps.henson.runtime 58 | implementation project(':app-navigation') 59 | implementation project(':module1') 60 | implementation project(':module1-navigation') 61 | 62 | annotationProcessor deps.butterknife.compiler 63 | annotationProcessor deps.dart.compiler 64 | } 65 | 66 | henson.navigatorPackageName = 'com.f2prateek.dart.example' 67 | -------------------------------------------------------------------------------- /dart-sample/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /dart-sample/app/src/main/java/com/f2prateek/dart/example/MainActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Jake Wharton 3 | * Copyright 2014 Prateek Srivastava (@f2prateek) 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package com.f2prateek.dart.example; 19 | 20 | import android.app.Activity; 21 | import android.content.Intent; 22 | import android.os.Bundle; 23 | import android.util.SparseArray; 24 | import butterknife.ButterKnife; 25 | import butterknife.OnClick; 26 | 27 | import com.f2prateek.dart.model.ComplexParcelable; 28 | import com.f2prateek.dart.model.StringParcel; 29 | import java.util.ArrayList; 30 | import java.util.List; 31 | 32 | public class MainActivity extends Activity { 33 | 34 | @Override protected void onCreate(Bundle savedInstanceState) { 35 | super.onCreate(savedInstanceState); 36 | setContentView(R.layout.activity_main); 37 | 38 | ButterKnife.bind(this); 39 | } 40 | 41 | // Launch Sample Activity residing in the same module 42 | @OnClick(R.id.navigateToSampleActivity) 43 | public void onSampleActivityCTAClick() { 44 | StringParcel parcel1 = new StringParcel("Andy"); 45 | StringParcel parcel2 = new StringParcel("Tony"); 46 | 47 | List parcelList = new ArrayList<>(); 48 | parcelList.add(parcel1); 49 | parcelList.add(parcel2); 50 | 51 | SparseArray parcelSparseArray = new SparseArray<>(); 52 | parcelSparseArray.put(0, parcel1); 53 | parcelSparseArray.put(2, parcel2); 54 | 55 | Intent intent = HensonNavigator.gotoSampleActivity(this) 56 | .defaultKeyExtra("defaultKeyExtra") 57 | .extraInt(4) 58 | .extraListParcelable(parcelList) 59 | .extraParcel(parcel1) 60 | .extraParcelable(ComplexParcelable.random()) 61 | .extraSparseArrayParcelable(parcelSparseArray) 62 | .extraString("a string") 63 | .build(); 64 | 65 | startActivity(intent); 66 | } 67 | 68 | // Launch Navigation Activity residing in the navigation module 69 | @OnClick(R.id.navigateToModule1Activity) 70 | public void onNavigationActivityCTAClick() { 71 | StringParcel parcel1 = new StringParcel("Andy"); 72 | StringParcel parcel2 = new StringParcel("Tony"); 73 | 74 | List parcelList = new ArrayList<>(); 75 | parcelList.add(parcel1); 76 | parcelList.add(parcel2); 77 | 78 | SparseArray parcelSparseArray = new SparseArray<>(); 79 | parcelSparseArray.put(0, parcel1); 80 | parcelSparseArray.put(2, parcel2); 81 | 82 | Intent intent = HensonNavigator.gotoModule1Activity(this) 83 | .defaultKeyExtra("defaultKeyExtra") 84 | .extraInt(4) 85 | .extraListParcelable(parcelList) 86 | .extraParcel(parcel1) 87 | .extraParcelable(ComplexParcelable.random()) 88 | .extraSparseArrayParcelable(parcelSparseArray) 89 | .extraString("a string") 90 | .build(); 91 | 92 | startActivity(intent); 93 | } 94 | 95 | // Launch Navigation Service residing in the navigation module 96 | @OnClick(R.id.navigateToModule1Service) 97 | public void onNavigationServiceCTAClick() { 98 | Intent intentService = HensonNavigator.gotoModule1Service(this) 99 | .stringExtra("foo") 100 | .build(); 101 | 102 | startService(intentService); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /dart-sample/app/src/main/java/com/f2prateek/dart/example/SampleActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Jake Wharton 3 | * Copyright 2014 Prateek Srivastava (@f2prateek) 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package com.f2prateek.dart.example; 19 | 20 | import android.app.Activity; 21 | import android.os.Bundle; 22 | import android.widget.TextView; 23 | import butterknife.BindView; 24 | import butterknife.ButterKnife; 25 | import dart.Dart; 26 | import dart.DartModel; 27 | 28 | public class SampleActivity extends Activity { 29 | 30 | @BindView(R.id.default_key_extra) TextView defaultKeyExtraTextView; 31 | @BindView(R.id.string_extra) TextView stringExtraTextView; 32 | @BindView(R.id.int_extra) TextView intExtraTextView; 33 | @BindView(R.id.parcelable_extra) TextView parcelableExtraTextView; 34 | @BindView(R.id.optional_extra) TextView optionalExtraTextView; 35 | @BindView(R.id.parcel_extra) TextView parcelExtraTextView; 36 | @BindView(R.id.list_parcel_extra) TextView listParcelExtraTextView; 37 | @BindView(R.id.sparse_array_parcel_extra) TextView sparseArrayParcelExtraTextView; 38 | @BindView(R.id.default_extra) TextView defaultExtraTextView; 39 | 40 | @DartModel SampleActivityNavigationModel navigationModel; 41 | 42 | @Override protected void onCreate(Bundle savedInstanceState) { 43 | super.onCreate(savedInstanceState); 44 | setContentView(R.layout.activity_sample); 45 | 46 | ButterKnife.bind(this); 47 | Dart.bind(this); 48 | 49 | // Contrived code to use the "bound" extras. 50 | stringExtraTextView.setText(navigationModel.stringExtra); 51 | intExtraTextView.setText(String.valueOf(navigationModel.intExtra)); 52 | parcelableExtraTextView.setText(String.valueOf(navigationModel.parcelableExtra)); 53 | optionalExtraTextView.setText(String.valueOf(navigationModel.optionalExtra)); 54 | parcelExtraTextView.setText(String.valueOf(navigationModel.parcelExtra.getName())); 55 | listParcelExtraTextView.setText(String.valueOf(navigationModel.listParcelExtra.size())); 56 | sparseArrayParcelExtraTextView.setText( 57 | String.valueOf(navigationModel.sparseArrayParcelExtra.size())); 58 | defaultExtraTextView.setText(String.valueOf(navigationModel.defaultExtra)); 59 | defaultKeyExtraTextView.setText(navigationModel.defaultKeyExtra); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /dart-sample/app/src/main/java/com/f2prateek/dart/example/SampleApp.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Jake Wharton 3 | * Copyright 2014 Prateek Srivastava (@f2prateek) 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package com.f2prateek.dart.example; 19 | 20 | import android.app.Application; 21 | import butterknife.ButterKnife; 22 | import dart.Dart; 23 | 24 | public class SampleApp extends Application { 25 | @Override public void onCreate() { 26 | super.onCreate(); 27 | ButterKnife.setDebug(BuildConfig.DEBUG); 28 | Dart.setDebug(BuildConfig.DEBUG); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /dart-sample/app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 19 | 20 | 24 | 25 |