From 056229f60f22ae790b5a464e7eac82662ebe3b69 Mon Sep 17 00:00:00 2001 From: Daniel Molinero Reguera Date: Fri, 1 Feb 2019 14:38:45 -0800 Subject: [PATCH] Toothpick 2: See Changelog for details. --- .travis.yml | 8 +- CHANGELOG.md | 15 +- README.md | 28 +- build.gradle | 31 +- deps.gradle | 42 ++ gradle.properties | 2 +- gradle/gradle-mvn-push.gradle | 1 - gradle/wrapper/gradle-wrapper.properties | 2 +- settings.gradle | 7 +- smoothie-androidx/build.gradle | 52 ++ smoothie-androidx/gradle.properties | 4 + .../src/main/AndroidManifest.xml | 2 + .../SmoothieAndroidXActivityModule.java | 20 + .../AndroidXFragmentManagerProvider.java | 19 + .../AndroidXLoaderManagerProvider.java | 19 + .../SmoothieSupportAndroidXModuleTest.java | 49 ++ smoothie-sample/build.gradle | 29 +- smoothie-sample/gradle.properties | 3 - .../gradle/wrapper/gradle-wrapper.properties | 2 +- smoothie-sample/gradlew | 0 smoothie-sample/settings.gradle | 1 + .../com/example/smoothie/SimpleActivity.java | 8 +- .../java/com/example/smoothie/SimpleApp.java | 13 +- smoothie-support/build.gradle | 52 ++ smoothie-support/gradle.properties | 4 + smoothie-support/src/main/AndroidManifest.xml | 2 + .../module/SmoothieSupportActivityModule.java | 0 .../SupportFragmentManagerProvider.java | 0 .../SupportLoaderManagerProvider.java | 0 .../SmoothieSupportActivityModuleTest.java | 0 smoothie/build.gradle | 22 +- smoothie/proguard-rules.txt | 19 + .../annotations/ContextSingleton.java | 28 -- .../module/SmoothieApplicationModule.java | 3 + toothpick-compiler/build.gradle | 4 +- toothpick-compiler/gradle.properties | 2 +- .../compiler/common/ToothpickProcessor.java | 64 +-- .../compiler/factory/FactoryProcessor.java | 80 +-- .../factory/generators/FactoryGenerator.java | 4 +- .../MemberInjectorProcessor.java | 80 ++- .../generators/MemberInjectorGenerator.java | 4 +- .../generators/RegistryGenerator.java | 221 --------- .../targets/RegistryInjectionTarget.java | 57 --- .../gradle/incremental.annotation.processors | 2 + .../compiler/factory/BaseFactoryTest.java | 4 +- .../FactoryOriginatingElementTest.java | 38 ++ .../compiler/factory/FactoryRegistryTest.java | 460 ------------------ .../compiler/factory/FactoryTest.java | 88 ++-- .../factory/ProcessorTestUtilities.java | 14 - ...edFactoryForClassContainingFieldsTest.java | 6 +- ...dFactoryForClassContainingMethodsTest.java | 6 +- .../RelaxedFactoryForScopeInstancesTest.java | 2 +- .../RelaxedFactoryForSingletonsTest.java | 4 +- .../FieldMemberInjectorTest.java | 56 +-- .../MemberInjectorOriginatingElementTest.java | 40 ++ .../MemberInjectorRegistryTest.java | 203 -------- .../MethodMemberInjectorTest.java | 22 +- .../ProcessorTestUtilities.java | 17 +- .../RegistryGeneratorGroupSizeRule.java | 32 -- toothpick-generated-core/build.gradle | 12 - toothpick-generated-core/gradle.properties | 3 - .../factory/AbstractFactoryRegistry.java | 42 -- .../AbstractMemberInjectorRegistry.java | 42 -- toothpick-javax-annotations/gradle.properties | 2 +- toothpick-runtime/build.gradle | 19 +- .../src/main/java/toothpick/InjectorImpl.java | 10 +- .../java/toothpick/InternalProviderImpl.java | 6 +- .../src/main/java/toothpick/ScopeImpl.java | 4 +- .../configuration/Configuration.java | 42 +- .../ReflectionConfiguration.java | 9 - .../ReflectionOffConfiguration.java | 18 - .../ReflectionOnConfiguration.java | 18 - .../toothpick/locators/FactoryLocator.java | 24 + .../locators/MemberInjectorLocator.java | 25 + .../NoFactoryFoundException.java | 7 +- .../registries/FactoryRegistryLocator.java | 60 --- .../MemberInjectorRegistryLocator.java | 49 -- ...lBindingsTestWithDefaultConfiguration.java | 7 +- .../java/toothpick/ScopeImplDumpTest.java | 2 +- .../test/java/toothpick/ScopeImplTest.java | 4 +- .../java/toothpick/ToothpickBaseTest.java | 24 - .../test/java/toothpick/ToothpickTest.java | 2 +- .../concurrency/BindingsMultiThreadTest.java | 59 ++- .../src/test/java/toothpick/data/Qurtz.java | 7 + .../toothpick/getInstance/CycleCheckTest.java | 26 +- .../getInstance/NamedInstanceCreation.java | 3 +- .../inject/InjectionWithoutModuleTest.java | 3 +- .../lazy/InjectionOfLazyProviderTest.java | 3 +- .../locators/FactoryLocatorTest.java | 38 ++ .../locators/MemberInjectorLocatorTest.java | 41 ++ .../NoFactoryFoundExceptionTest.java | 2 +- .../FactoryRegistryLocatorTest.java | 140 ------ .../MemberInjectorRegistryLocatorTest.java | 120 ----- .../java/toothpick/scoping/ScopingTest.java | 11 +- toothpick-sample/build.gradle | 35 +- .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 54329 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + toothpick-sample/gradlew | 172 +++++++ toothpick-sample/gradlew.bat | 84 ++++ toothpick-sample/settings.gradle | 1 + .../toothpick/sample/SecondEntryPoint.java | 18 - .../toothpick/sample/SimpleEntryPoint.java | 10 +- .../java/toothpick/sample/Computer2Test.java | 11 +- .../java/toothpick/sample/ComputerTest.java | 36 +- .../sample/ComputerTestWithRules.java | 26 - .../toothpick/sample/EasyMockExtension.java | 19 + .../sample/SimpleEntryPointTest.java | 47 +- .../sample/SimpleEntryPointTestWithRules.java | 49 -- toothpick-testing-junit4/build.gradle | 14 + toothpick-testing-junit4/gradle.properties | 4 + .../java/toothpick/testing/ToothPickRule.java | 16 - .../toothpick/testing/ToothPickStatement.java | 0 .../java/toothpick/testing/SimpleTest.java | 0 .../TestCustomScopeWithNamedBinding.java | 2 +- .../testing/TestInjectionAndGetInstance.java | 8 +- .../java/toothpick/testing/TestMocking.java | 2 +- .../java/toothpick/testing/TestScopeName.java | 0 .../toothpick/testing/ToothpickRuleTest.java | 5 - toothpick-testing-junit5/build.gradle | 20 + toothpick-testing-junit5/gradle.properties | 4 + .../toothpick/testing/ToothPickExtension.java | 56 +++ .../toothpick/testing/EasyMockExtension.java | 19 + .../java/toothpick/testing/SimpleTest.java | 34 ++ .../TestCustomScopeWithNamedBinding.java | 41 ++ .../testing/TestInjectionAndGetInstance.java | 49 ++ .../java/toothpick/testing/TestMocking.java | 51 ++ .../java/toothpick/testing/TestScopeName.java | 51 ++ toothpick-testing/build.gradle | 15 +- toothpick-testing/gradle.properties | 2 +- .../toothpick/testing/TestBadRegistry.java | 20 - toothpick/build.gradle | 2 +- toothpick/gradle.properties | 2 +- .../src/main/java/toothpick/Factory.java | 2 +- .../main/java/toothpick/MemberInjector.java | 2 +- .../toothpick/registries/FactoryRegistry.java | 15 - .../registries/MemberInjectorRegistry.java | 15 - 136 files changed, 1512 insertions(+), 2334 deletions(-) create mode 100644 deps.gradle create mode 100644 smoothie-androidx/build.gradle create mode 100644 smoothie-androidx/gradle.properties create mode 100644 smoothie-androidx/src/main/AndroidManifest.xml create mode 100644 smoothie-androidx/src/main/java/toothpick/smoothie/module/SmoothieAndroidXActivityModule.java create mode 100644 smoothie-androidx/src/main/java/toothpick/smoothie/provider/AndroidXFragmentManagerProvider.java create mode 100644 smoothie-androidx/src/main/java/toothpick/smoothie/provider/AndroidXLoaderManagerProvider.java create mode 100644 smoothie-androidx/src/test/java/toothpick/smoothie/module/SmoothieSupportAndroidXModuleTest.java delete mode 100644 smoothie-sample/gradle.properties mode change 100644 => 100755 smoothie-sample/gradlew create mode 100644 smoothie-sample/settings.gradle create mode 100644 smoothie-support/build.gradle create mode 100644 smoothie-support/gradle.properties create mode 100644 smoothie-support/src/main/AndroidManifest.xml rename {smoothie => smoothie-support}/src/main/java/toothpick/smoothie/module/SmoothieSupportActivityModule.java (100%) rename {smoothie => smoothie-support}/src/main/java/toothpick/smoothie/provider/SupportFragmentManagerProvider.java (100%) rename {smoothie => smoothie-support}/src/main/java/toothpick/smoothie/provider/SupportLoaderManagerProvider.java (100%) rename {smoothie => smoothie-support}/src/test/java/toothpick/smoothie/module/SmoothieSupportActivityModuleTest.java (100%) create mode 100644 smoothie/proguard-rules.txt delete mode 100644 smoothie/src/main/java/toothpick/smoothie/annotations/ContextSingleton.java delete mode 100644 toothpick-compiler/src/main/java/toothpick/compiler/registry/generators/RegistryGenerator.java delete mode 100644 toothpick-compiler/src/main/java/toothpick/compiler/registry/targets/RegistryInjectionTarget.java create mode 100644 toothpick-compiler/src/main/resources/META-INF/gradle/incremental.annotation.processors create mode 100644 toothpick-compiler/src/test/java/toothpick/compiler/factory/FactoryOriginatingElementTest.java delete mode 100644 toothpick-compiler/src/test/java/toothpick/compiler/factory/FactoryRegistryTest.java create mode 100644 toothpick-compiler/src/test/java/toothpick/compiler/memberinjector/MemberInjectorOriginatingElementTest.java delete mode 100644 toothpick-compiler/src/test/java/toothpick/compiler/memberinjector/MemberInjectorRegistryTest.java delete mode 100644 toothpick-compiler/src/test/java/toothpick/compiler/registry/generators/RegistryGeneratorGroupSizeRule.java delete mode 100644 toothpick-generated-core/build.gradle delete mode 100644 toothpick-generated-core/gradle.properties delete mode 100644 toothpick-generated-core/src/main/java/toothpick/registries/factory/AbstractFactoryRegistry.java delete mode 100644 toothpick-generated-core/src/main/java/toothpick/registries/memberinjector/AbstractMemberInjectorRegistry.java delete mode 100644 toothpick-runtime/src/main/java/toothpick/configuration/ReflectionConfiguration.java delete mode 100644 toothpick-runtime/src/main/java/toothpick/configuration/ReflectionOffConfiguration.java delete mode 100644 toothpick-runtime/src/main/java/toothpick/configuration/ReflectionOnConfiguration.java create mode 100644 toothpick-runtime/src/main/java/toothpick/locators/FactoryLocator.java create mode 100644 toothpick-runtime/src/main/java/toothpick/locators/MemberInjectorLocator.java rename toothpick-runtime/src/main/java/toothpick/{registries => locators}/NoFactoryFoundException.java (63%) delete mode 100644 toothpick-runtime/src/main/java/toothpick/registries/FactoryRegistryLocator.java delete mode 100644 toothpick-runtime/src/main/java/toothpick/registries/MemberInjectorRegistryLocator.java delete mode 100644 toothpick-runtime/src/test/java/toothpick/ToothpickBaseTest.java create mode 100644 toothpick-runtime/src/test/java/toothpick/data/Qurtz.java create mode 100644 toothpick-runtime/src/test/java/toothpick/locators/FactoryLocatorTest.java create mode 100644 toothpick-runtime/src/test/java/toothpick/locators/MemberInjectorLocatorTest.java rename toothpick-runtime/src/test/java/toothpick/{registries => locators}/NoFactoryFoundExceptionTest.java (96%) delete mode 100644 toothpick-runtime/src/test/java/toothpick/registries/FactoryRegistryLocatorTest.java delete mode 100644 toothpick-runtime/src/test/java/toothpick/registries/MemberInjectorRegistryLocatorTest.java create mode 100644 toothpick-sample/gradle/wrapper/gradle-wrapper.jar create mode 100644 toothpick-sample/gradle/wrapper/gradle-wrapper.properties create mode 100755 toothpick-sample/gradlew create mode 100644 toothpick-sample/gradlew.bat create mode 100644 toothpick-sample/settings.gradle delete mode 100644 toothpick-sample/src/main/java/toothpick/sample/SecondEntryPoint.java delete mode 100644 toothpick-sample/src/test/java/toothpick/sample/ComputerTestWithRules.java create mode 100644 toothpick-sample/src/test/java/toothpick/sample/EasyMockExtension.java delete mode 100644 toothpick-sample/src/test/java/toothpick/sample/SimpleEntryPointTestWithRules.java create mode 100644 toothpick-testing-junit4/build.gradle create mode 100644 toothpick-testing-junit4/gradle.properties rename {toothpick-testing => toothpick-testing-junit4}/src/main/java/toothpick/testing/ToothPickRule.java (60%) rename {toothpick-testing => toothpick-testing-junit4}/src/main/java/toothpick/testing/ToothPickStatement.java (100%) rename {toothpick-testing => toothpick-testing-junit4}/src/test/java/toothpick/testing/SimpleTest.java (100%) rename {toothpick-testing => toothpick-testing-junit4}/src/test/java/toothpick/testing/TestCustomScopeWithNamedBinding.java (96%) rename {toothpick-testing => toothpick-testing-junit4}/src/test/java/toothpick/testing/TestInjectionAndGetInstance.java (87%) rename {toothpick-testing => toothpick-testing-junit4}/src/test/java/toothpick/testing/TestMocking.java (96%) rename {toothpick-testing => toothpick-testing-junit4}/src/test/java/toothpick/testing/TestScopeName.java (100%) rename {toothpick-testing => toothpick-testing-junit4}/src/test/java/toothpick/testing/ToothpickRuleTest.java (85%) create mode 100644 toothpick-testing-junit5/build.gradle create mode 100644 toothpick-testing-junit5/gradle.properties create mode 100644 toothpick-testing-junit5/src/main/java/toothpick/testing/ToothPickExtension.java create mode 100644 toothpick-testing-junit5/src/test/java/toothpick/testing/EasyMockExtension.java create mode 100644 toothpick-testing-junit5/src/test/java/toothpick/testing/SimpleTest.java create mode 100644 toothpick-testing-junit5/src/test/java/toothpick/testing/TestCustomScopeWithNamedBinding.java create mode 100644 toothpick-testing-junit5/src/test/java/toothpick/testing/TestInjectionAndGetInstance.java create mode 100644 toothpick-testing-junit5/src/test/java/toothpick/testing/TestMocking.java create mode 100644 toothpick-testing-junit5/src/test/java/toothpick/testing/TestScopeName.java delete mode 100644 toothpick-testing/src/test/java/toothpick/testing/TestBadRegistry.java delete mode 100644 toothpick/src/main/java/toothpick/registries/FactoryRegistry.java delete mode 100644 toothpick/src/main/java/toothpick/registries/MemberInjectorRegistry.java diff --git a/.travis.yml b/.travis.yml index 9f0493c1..e28657d3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,8 +4,8 @@ android: components: # https://github.com/travis-ci/travis-ci/issues/5036 - tools - - build-tools-26.0.2 - - android-26 + - build-tools-28.0.3 + - android-28 - extra-android-m2repository jdk: @@ -37,7 +37,9 @@ cache: - $HOME/.android/build-cache script: - - ./gradlew clean check -x :smoothie-sample:lint + - ./gradlew clean check + - ./gradlew -b toothpick-sample/build.gradle clean check + - ./gradlew -b smoothie-sample/build.gradle clean check -x lint after_success: - ./gradlew jacocoTestReport coveralls diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b70d3e8..f56412e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,19 @@ -## Release version 1.1.4 (To be released) +## Release version 2.0.0 (To be released) + +* support incremental annotation processing. All processors are now incremental and isolating. +* remove all registries, TP 2.x doesn't use registries any more. They were actually slower than not using them after +we reworked on registries to enable obfuscation. Reflection is now used to load the factories and member injectors, +this is normal (and all other annotation processor based libs do that too) and there is no impact on performance. +* support multiple rounds of annotation processing. +* generated classes now use `__` instead of `$$` to make TP more compliant with some tools. +* removed the generate ContextSingleton annotation +* smoothie now binds the ClipClipboardManager service. Thx to Cody Henthrone for this. Sorry we were late merging this ! +* smoothie now contains non support and non android x bindings. We have introduced 2 new artifacts: +smoothie-support and smoothie-androidx that respectively support the old legacy support library and the new android X libs). +* toothpick-testing now only contains core testing classes. New artifacts have been introduced to support junit 4 nd junit 5 (resp. : toothpick-testing-junit4, toothpick-testing-junit5) +* added a consumer proguard file ## Release version 1.1.3 (March 10th, 2018) diff --git a/README.md b/README.md index 585d81c9..ac6105e6 100644 --- a/README.md +++ b/README.md @@ -78,28 +78,32 @@ Currently Toothpick has 2 sets of examples : * one [for Android](https://github.com/stephanenicolas/toothpick/tree/master/smoothie-sample) ## Setup + +The latest version of TP is provided by a badge at the top of this page. + For Android : ```groovy -#android setup using gradle 2.2.3 +#android setup using gradle 3.3.0 buildscript { repositories { + google() jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.2.3' + classpath 'com.android.tools.build:gradle:3.3.0' } } ... dependencies { - compile 'com.github.stephanenicolas.toothpick:toothpick-runtime:1.1.3' - // and for android -> compile 'com.github.stephanenicolas.toothpick:smoothie:1.1.3' - annotationProcessor 'com.github.stephanenicolas.toothpick:toothpick-compiler:1.1.3' + implementation 'com.github.stephanenicolas.toothpick:toothpick-runtime:2.x' + // and for android -> implementation 'com.github.stephanenicolas.toothpick:smoothie-androidx:2.x' + annotationProcessor 'com.github.stephanenicolas.toothpick:toothpick-compiler:2.x' //highly recommended - testCompile 'com.github.stephanenicolas.toothpick:toothpick-testing:1.1.3' - testCompile 'mockito or easymock' + testImplementation 'com.github.stephanenicolas.toothpick:toothpick-testing-junit5:2.x' + testImplementation 'mockito or easymock' } ``` @@ -110,13 +114,13 @@ For java: com.github.stephanenicolas.toothpick toothpick-compiler - 1.1.3 + 2.x compile com.github.stephanenicolas.toothpick toothpick-runtime - 1.1.3 + 2.x compile @@ -124,7 +128,7 @@ For java: com.github.stephanenicolas.toothpick toothpick-testing - 1.1.3 + 2.x test @@ -173,3 +177,7 @@ Visit [Toothpick's wiki](https://github.com/stephanenicolas/toothpick/wiki) ! * [Okuki](https://github.com/wongcain/okuki) is a simple, hierarchical navigation bus and back stack for Android, with optional Rx bindings, and Toothpick DI integration. * [KotlinWeather](https://github.com/ekamp/KotlinWeather) is a simple example of using ToothPick with Kotlin and gradle integration using kapt. + +# Credits + +Most of the effort on version 2 has been actively supported by Groupon. Thanks for this awesome OSS commitment ! diff --git a/build.gradle b/build.gradle index d383d042..81eea163 100644 --- a/build.gradle +++ b/build.gradle @@ -2,11 +2,13 @@ apply plugin: 'jacoco' apply plugin: 'com.github.kt3k.coveralls' buildscript { + apply from: 'deps.gradle' repositories { + google() jcenter() } dependencies { - classpath 'org.kt3k.gradle.plugin:coveralls-gradle-plugin:2.6.3' + classpath deps.coverallPlugin } } @@ -113,30 +115,3 @@ subprojects { project -> } } } - -ext.deps = [// Common - inject : 'javax.inject:javax.inject:1', - - // Compiler - javapoet : 'com.squareup:javapoet:1.4.0', - - // Android - android : 'com.google.android:android:4.1.1.4', - supportv4 : 'com.google.android:support-v4:r7', - supportAnnotations : 'com.android.support:support-annotations:23.3.0', - butterknife : 'com.jakewharton:butterknife:8.0.0', - butterknife_compiler: 'com.jakewharton:butterknife-compiler:8.0.0', - rxandroid : 'io.reactivex:rxandroid:0.23.0', - - // Test dependencies - junit : 'junit:junit:4.12', - hamcrest : 'org.hamcrest:java-hamcrest:2.0.0.0', - truth : 'com.google.truth:truth:0.34', - compiletesting : 'com.google.testing.compile:compile-testing:0.11', - easymock : 'org.easymock:easymock:3.4', - powermock : 'org.powermock:powermock-easymock-release-full:1.6.4', - robolectric : 'org.robolectric:robolectric:3.4.2', - - // Android Test Dependencies - espresso : 'com.android.support.test.espresso:espresso-core:2.2.2', - dexmaker : 'com.google.dexmaker:dexmaker:1.2',] diff --git a/deps.gradle b/deps.gradle new file mode 100644 index 00000000..8c53fad0 --- /dev/null +++ b/deps.gradle @@ -0,0 +1,42 @@ +ext.deps = [// Common + inject : 'javax.inject:javax.inject:1', + + // Compiler + javapoet : 'com.squareup:javapoet:1.11.1', + + // Android + android : 'com.google.android:android:4.1.1.4', + androidPlugin : 'com.android.tools.build:gradle:3.3.0', + coverallPlugin : 'org.kt3k.gradle.plugin:coveralls-gradle-plugin:2.6.3', + supportv4 : 'com.android.support:support-v4:28.0.0', + androidxv4 : 'androidx.legacy:legacy-support-v4:1.0.0', + butterknife : 'com.jakewharton:butterknife:10.0.0', + butterknife_compiler: 'com.jakewharton:butterknife-compiler:10.0.0', + rxandroid : 'io.reactivex:rxandroid:1.2.1', + + // TP artifacts for composite builds + tp_smoothie : 'com.github.stephanenicolas.toothpick:smoothie:2.0.0', + tp_smoothie_androidx: 'com.github.stephanenicolas.toothpick:smoothie-androidx:2.0.0', + tp_smoothie_support : 'com.github.stephanenicolas.toothpick:smoothie-support:2.0.0', + tp : 'com.github.stephanenicolas.toothpick:toothpick:2.0.0', + tp_runtime : 'com.github.stephanenicolas.toothpick:toothpick-runtime:2.0.0', + tp_compiler : 'com.github.stephanenicolas.toothpick:toothpick-compiler:2.0.0', + tp_testing : 'com.github.stephanenicolas.toothpick:toothpick-testing:2.0.0', + tp_testing_junit4 : 'com.github.stephanenicolas.toothpick:toothpick-testing-junit4:2.0.0', + tp_testing_junit5 : 'com.github.stephanenicolas.toothpick:toothpick-testing-junit5:2.0.0', + + // Test dependencies + junit4 : 'junit:junit:4.12', + junit5_api : 'org.junit.jupiter:junit-jupiter-api:5.3.2', + junit5_engine : 'org.junit.jupiter:junit-jupiter-engine:5.3.2', + hamcrest : 'org.hamcrest:java-hamcrest:2.0.0.0', + truth : 'com.google.truth:truth:0.42', + compiletesting : 'com.google.testing.compile:compile-testing:0.15', + easymock : 'org.easymock:easymock:3.4', + powermock : 'org.powermock:powermock-easymock-release-full:1.6.4', + powermock_rule : 'org.powermock:powermock-module-junit4-rule-agent:1.6.4', + robolectric : 'org.robolectric:robolectric:3.4.2', + + // Android Test Dependencies + espresso : 'com.android.support.test.espresso:espresso-core:2.2.2', + dexmaker : 'com.google.dexmaker:dexmaker:1.2',] \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 243a1411..eac05ff6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ GROUP=com.github.stephanenicolas.toothpick -VERSION_NAME=1.1.4-SNAPSHOT +VERSION_NAME=2.0.0-SNAPSHOT POM_PACKAGING=JAR POM_DESCRIPTION=DI. diff --git a/gradle/gradle-mvn-push.gradle b/gradle/gradle-mvn-push.gradle index 75fdc5c1..ea3f6bbb 100644 --- a/gradle/gradle-mvn-push.gradle +++ b/gradle/gradle-mvn-push.gradle @@ -138,7 +138,6 @@ afterEvaluate { project -> task androidJavadocs(type: Javadoc) { source = android.sourceSets.main.java.source classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) - classpath += configurations.debugCompileClasspath } task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 39a5a5fe..6ef30fc9 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,5 +3,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.2.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-all.zip diff --git a/settings.gradle b/settings.gradle index fe67cd03..68d7e3fe 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,11 +1,12 @@ include ':toothpick' include ':toothpick-javax-annotations' -include ':toothpick-generated-core' include ':toothpick-compiler' include ':toothpick-runtime' include ':toothpick-testing' -include ':toothpick-sample' +include ':toothpick-testing-junit4' +include ':toothpick-testing-junit5' include ':smoothie' -include ':smoothie-sample' +include ':smoothie-support' +include ':smoothie-androidx' rootProject.name = 'toothpick-parent' diff --git a/smoothie-androidx/build.gradle b/smoothie-androidx/build.gradle new file mode 100644 index 00000000..a076a1de --- /dev/null +++ b/smoothie-androidx/build.gradle @@ -0,0 +1,52 @@ +buildscript { + repositories { + google() + jcenter() + } + dependencies { + classpath deps.androidPlugin + } + +} + +apply plugin: 'com.android.library' + +repositories { + google() +} + +android { + compileSdkVersion 28 + buildToolsVersion '28.0.3' + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_7 + targetCompatibility JavaVersion.VERSION_1_7 + } + + defaultConfig { + minSdkVersion 15 + } + + lintOptions { + textReport true + textOutput 'stdout' + // We run a full lint analysis as build part in CI, so skip vital checks for assemble tasks. + checkReleaseBuilds false + } +} + +dependencies { + compileOnly project(':toothpick') + api project(':smoothie') + compileOnly deps.inject + compileOnly deps.androidxv4 + + testImplementation deps.androidxv4 + testImplementation project(':toothpick-testing') + testImplementation deps.junit4 + testImplementation deps.easymock + testImplementation deps.robolectric +} + +apply from: rootProject.file('gradle/gradle-mvn-push.gradle') diff --git a/smoothie-androidx/gradle.properties b/smoothie-androidx/gradle.properties new file mode 100644 index 00000000..bac2f5af --- /dev/null +++ b/smoothie-androidx/gradle.properties @@ -0,0 +1,4 @@ +POM_ARTIFACT_ID=smoothie-androidx +POM_NAME=smoothie android X +POM_DESCRIPTION='Toothpick package providing Android providers for the android X library' +POM_PACKAGING='aar' diff --git a/smoothie-androidx/src/main/AndroidManifest.xml b/smoothie-androidx/src/main/AndroidManifest.xml new file mode 100644 index 00000000..ddfbb545 --- /dev/null +++ b/smoothie-androidx/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/smoothie-androidx/src/main/java/toothpick/smoothie/module/SmoothieAndroidXActivityModule.java b/smoothie-androidx/src/main/java/toothpick/smoothie/module/SmoothieAndroidXActivityModule.java new file mode 100644 index 00000000..5bd2b586 --- /dev/null +++ b/smoothie-androidx/src/main/java/toothpick/smoothie/module/SmoothieAndroidXActivityModule.java @@ -0,0 +1,20 @@ +package toothpick.smoothie.module; + +import android.app.Activity; +import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; +import androidx.loader.app.LoaderManager; +import android.view.LayoutInflater; +import toothpick.config.Module; +import toothpick.smoothie.provider.AndroidXFragmentManagerProvider; +import toothpick.smoothie.provider.AndroidXLoaderManagerProvider; +import toothpick.smoothie.provider.LayoutInflaterProvider; + +public class SmoothieAndroidXActivityModule extends Module { + public SmoothieAndroidXActivityModule(FragmentActivity activity) { + bind(Activity.class).toInstance(activity); + bind(FragmentManager.class).toProviderInstance(new AndroidXFragmentManagerProvider(activity)); + bind(LoaderManager.class).toProviderInstance(new AndroidXLoaderManagerProvider(activity)); + bind(LayoutInflater.class).toProviderInstance(new LayoutInflaterProvider(activity)); + } +} diff --git a/smoothie-androidx/src/main/java/toothpick/smoothie/provider/AndroidXFragmentManagerProvider.java b/smoothie-androidx/src/main/java/toothpick/smoothie/provider/AndroidXFragmentManagerProvider.java new file mode 100644 index 00000000..5bb1bdec --- /dev/null +++ b/smoothie-androidx/src/main/java/toothpick/smoothie/provider/AndroidXFragmentManagerProvider.java @@ -0,0 +1,19 @@ +package toothpick.smoothie.provider; + +import android.app.Activity; +import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; +import javax.inject.Provider; + +public class AndroidXFragmentManagerProvider implements Provider { + Activity activity; + + public AndroidXFragmentManagerProvider(Activity activity) { + this.activity = activity; + } + + @Override + public FragmentManager get() { + return ((FragmentActivity) activity).getSupportFragmentManager(); + } +} diff --git a/smoothie-androidx/src/main/java/toothpick/smoothie/provider/AndroidXLoaderManagerProvider.java b/smoothie-androidx/src/main/java/toothpick/smoothie/provider/AndroidXLoaderManagerProvider.java new file mode 100644 index 00000000..cb7a4a39 --- /dev/null +++ b/smoothie-androidx/src/main/java/toothpick/smoothie/provider/AndroidXLoaderManagerProvider.java @@ -0,0 +1,19 @@ +package toothpick.smoothie.provider; + +import android.app.Activity; +import androidx.fragment.app.FragmentActivity; +import androidx.loader.app.LoaderManager; +import javax.inject.Provider; + +public class AndroidXLoaderManagerProvider implements Provider { + Activity activity; + + public AndroidXLoaderManagerProvider(Activity activity) { + this.activity = activity; + } + + @Override + public LoaderManager get() { + return ((FragmentActivity) activity).getSupportLoaderManager(); + } +} diff --git a/smoothie-androidx/src/test/java/toothpick/smoothie/module/SmoothieSupportAndroidXModuleTest.java b/smoothie-androidx/src/test/java/toothpick/smoothie/module/SmoothieSupportAndroidXModuleTest.java new file mode 100644 index 00000000..397b5c5d --- /dev/null +++ b/smoothie-androidx/src/test/java/toothpick/smoothie/module/SmoothieSupportAndroidXModuleTest.java @@ -0,0 +1,49 @@ +package toothpick.smoothie.module; + +import android.app.Activity; +import android.app.Application; +import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; +import androidx.loader.app.LoaderManager; +import android.view.LayoutInflater; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; +import toothpick.Scope; +import toothpick.Toothpick; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.sameInstance; +import static org.hamcrest.MatcherAssert.assertThat; + +@RunWith(RobolectricTestRunner.class) +public class SmoothieSupportAndroidXModuleTest { + + @Test + public void testGet() throws Exception { + //GIVEN + FragmentActivity activity = Robolectric.buildActivity(FragmentActivity.class).create().get(); + Application application = RuntimeEnvironment.application; + Scope appScope = Toothpick.openScope(application); + appScope.installModules(new SmoothieApplicationModule(application)); + + Scope activityScope = Toothpick.openScopes(application, activity); + activityScope.installModules(new SmoothieAndroidXActivityModule(activity)); + + //WHEN + Activity injectedActivity = activityScope.getInstance(Activity.class); + FragmentManager fragmentManager = activityScope.getInstance(FragmentManager.class); + LoaderManager loaderManager = activityScope.getInstance(LoaderManager.class); + LayoutInflater layoutInflater = activityScope.getInstance(LayoutInflater.class); + + //THEN + assertThat(injectedActivity, instanceOf(FragmentActivity.class)); + assertThat((FragmentActivity) injectedActivity, sameInstance(activity)); + assertThat(fragmentManager, notNullValue()); + assertThat(loaderManager, notNullValue()); + assertThat(layoutInflater, notNullValue()); + } +} diff --git a/smoothie-sample/build.gradle b/smoothie-sample/build.gradle index f4c6d706..714c7de2 100644 --- a/smoothie-sample/build.gradle +++ b/smoothie-sample/build.gradle @@ -1,18 +1,19 @@ buildscript { + apply from: '../deps.gradle' repositories { - jcenter() google() + jcenter() } dependencies { - classpath ('com.android.tools.build:gradle:3.0.0-beta7') + classpath deps.androidPlugin } } apply plugin: 'com.android.application' android { - compileSdkVersion 26 - buildToolsVersion '26.0.2' + compileSdkVersion 28 + buildToolsVersion '28.0.3' compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 @@ -26,13 +27,6 @@ android { versionCode 1 versionName '1.0.0' testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner' - javaCompileOptions { - annotationProcessorOptions { - arguments = [ - 'toothpick_registry_package_name': 'com.example.smoothie', - ] - } - } } lintOptions { @@ -51,20 +45,23 @@ android { } repositories { + google() + jcenter() maven { url "https://oss.sonatype.org/content/repositories/snapshots" } } dependencies { - implementation project(path: ':smoothie', configuration: 'default') - implementation project(':toothpick-runtime') + implementation deps.tp_smoothie_androidx + implementation deps.tp_runtime implementation deps.butterknife implementation deps.rxandroid + implementation deps.androidxv4 - annotationProcessor project(':toothpick-compiler') + annotationProcessor deps.tp_compiler annotationProcessor deps.butterknife_compiler - testImplementation project(':toothpick-testing') - testImplementation deps.junit + testImplementation deps.tp_testing_junit4 + testImplementation deps.junit4 testImplementation deps.easymock testImplementation deps.truth testImplementation deps.robolectric diff --git a/smoothie-sample/gradle.properties b/smoothie-sample/gradle.properties deleted file mode 100644 index 322a0448..00000000 --- a/smoothie-sample/gradle.properties +++ /dev/null @@ -1,3 +0,0 @@ -POM_ARTIFACT_ID=smoothie-sample -POM_NAME=smoothie -POM_DESCRIPTION='Sample Android app using Smoothie' \ No newline at end of file diff --git a/smoothie-sample/gradle/wrapper/gradle-wrapper.properties b/smoothie-sample/gradle/wrapper/gradle-wrapper.properties index f23df6e4..1e014f45 100644 --- a/smoothie-sample/gradle/wrapper/gradle-wrapper.properties +++ b/smoothie-sample/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-all.zip diff --git a/smoothie-sample/gradlew b/smoothie-sample/gradlew old mode 100644 new mode 100755 diff --git a/smoothie-sample/settings.gradle b/smoothie-sample/settings.gradle new file mode 100644 index 00000000..53785818 --- /dev/null +++ b/smoothie-sample/settings.gradle @@ -0,0 +1 @@ +includeBuild '..' diff --git a/smoothie-sample/src/main/java/com/example/smoothie/SimpleActivity.java b/smoothie-sample/src/main/java/com/example/smoothie/SimpleActivity.java index 940ddceb..44371eb9 100644 --- a/smoothie-sample/src/main/java/com/example/smoothie/SimpleActivity.java +++ b/smoothie-sample/src/main/java/com/example/smoothie/SimpleActivity.java @@ -1,10 +1,10 @@ package com.example.smoothie; -import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.widget.Button; import android.widget.TextView; +import androidx.fragment.app.FragmentActivity; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; @@ -12,9 +12,9 @@ import javax.inject.Inject; import toothpick.Scope; import toothpick.Toothpick; -import toothpick.smoothie.module.SmoothieActivityModule; +import toothpick.smoothie.module.SmoothieAndroidXActivityModule; -public class SimpleActivity extends Activity { +public class SimpleActivity extends FragmentActivity { private Scope scope; @@ -26,7 +26,7 @@ public class SimpleActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { scope = Toothpick.openScopes(getApplication(), this); - scope.installModules(new SmoothieActivityModule(this)); + scope.installModules(new SmoothieAndroidXActivityModule(this)); super.onCreate(savedInstanceState); Toothpick.inject(this, scope); setContentView(R.layout.simple_activity); diff --git a/smoothie-sample/src/main/java/com/example/smoothie/SimpleApp.java b/smoothie-sample/src/main/java/com/example/smoothie/SimpleApp.java index 5ff36d4f..1617f084 100644 --- a/smoothie-sample/src/main/java/com/example/smoothie/SimpleApp.java +++ b/smoothie-sample/src/main/java/com/example/smoothie/SimpleApp.java @@ -1,11 +1,9 @@ package com.example.smoothie; import android.app.Application; -import toothpick.configuration.Configuration; import toothpick.Scope; import toothpick.Toothpick; -import toothpick.registries.FactoryRegistryLocator; -import toothpick.registries.MemberInjectorRegistryLocator; +import toothpick.configuration.Configuration; import toothpick.smoothie.module.SmoothieApplicationModule; public class SimpleApp extends Application { @@ -13,14 +11,7 @@ public class SimpleApp extends Application { public void onCreate() { super.onCreate(); - // com.example.smoothie.MemberInjectorRegistry and com.example.smoothie.FactoryRegistry are classes generated by this project - // Your project will have these classes in your package (or the one you specify). - // Please note that the fully qualified name should be used instead of an import. - // (see https://github.com/stephanenicolas/toothpick/wiki/Factory-and-Member-Injector-registries) - // If you're not using the reflection free configuration, the next 3 lines can be omitted - Toothpick.setConfiguration(Configuration.forProduction().disableReflection()); - MemberInjectorRegistryLocator.setRootRegistry(new com.example.smoothie.MemberInjectorRegistry()); - FactoryRegistryLocator.setRootRegistry(new com.example.smoothie.FactoryRegistry()); + Toothpick.setConfiguration(Configuration.forProduction()); Scope appScope = Toothpick.openScope(this); initToothpick(appScope); diff --git a/smoothie-support/build.gradle b/smoothie-support/build.gradle new file mode 100644 index 00000000..ccee0638 --- /dev/null +++ b/smoothie-support/build.gradle @@ -0,0 +1,52 @@ +buildscript { + repositories { + google() + jcenter() + } + dependencies { + classpath deps.androidPlugin + } + +} + +apply plugin: 'com.android.library' + +repositories { + google() +} + +dependencies { + compileOnly project(':toothpick') + api project(':smoothie') + compileOnly deps.inject + compileOnly deps.supportv4 + + testImplementation deps.supportv4 + testImplementation project(':toothpick-testing') + testImplementation deps.junit4 + testImplementation deps.easymock + testImplementation deps.robolectric +} + +android { + compileSdkVersion 28 + buildToolsVersion '28.0.3' + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_7 + targetCompatibility JavaVersion.VERSION_1_7 + } + + defaultConfig { + minSdkVersion 15 + } + + lintOptions { + textReport true + textOutput 'stdout' + // We run a full lint analysis as build part in CI, so skip vital checks for assemble tasks. + checkReleaseBuilds false + } +} + +apply from: rootProject.file('gradle/gradle-mvn-push.gradle') diff --git a/smoothie-support/gradle.properties b/smoothie-support/gradle.properties new file mode 100644 index 00000000..ba9d4849 --- /dev/null +++ b/smoothie-support/gradle.properties @@ -0,0 +1,4 @@ +POM_ARTIFACT_ID=smoothie-support +POM_NAME=smoothie support +POM_DESCRIPTION='Toothpick package providing Android providers for the support library' +POM_PACKAGING='aar' diff --git a/smoothie-support/src/main/AndroidManifest.xml b/smoothie-support/src/main/AndroidManifest.xml new file mode 100644 index 00000000..acd8f35d --- /dev/null +++ b/smoothie-support/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/smoothie/src/main/java/toothpick/smoothie/module/SmoothieSupportActivityModule.java b/smoothie-support/src/main/java/toothpick/smoothie/module/SmoothieSupportActivityModule.java similarity index 100% rename from smoothie/src/main/java/toothpick/smoothie/module/SmoothieSupportActivityModule.java rename to smoothie-support/src/main/java/toothpick/smoothie/module/SmoothieSupportActivityModule.java diff --git a/smoothie/src/main/java/toothpick/smoothie/provider/SupportFragmentManagerProvider.java b/smoothie-support/src/main/java/toothpick/smoothie/provider/SupportFragmentManagerProvider.java similarity index 100% rename from smoothie/src/main/java/toothpick/smoothie/provider/SupportFragmentManagerProvider.java rename to smoothie-support/src/main/java/toothpick/smoothie/provider/SupportFragmentManagerProvider.java diff --git a/smoothie/src/main/java/toothpick/smoothie/provider/SupportLoaderManagerProvider.java b/smoothie-support/src/main/java/toothpick/smoothie/provider/SupportLoaderManagerProvider.java similarity index 100% rename from smoothie/src/main/java/toothpick/smoothie/provider/SupportLoaderManagerProvider.java rename to smoothie-support/src/main/java/toothpick/smoothie/provider/SupportLoaderManagerProvider.java diff --git a/smoothie/src/test/java/toothpick/smoothie/module/SmoothieSupportActivityModuleTest.java b/smoothie-support/src/test/java/toothpick/smoothie/module/SmoothieSupportActivityModuleTest.java similarity index 100% rename from smoothie/src/test/java/toothpick/smoothie/module/SmoothieSupportActivityModuleTest.java rename to smoothie-support/src/test/java/toothpick/smoothie/module/SmoothieSupportActivityModuleTest.java diff --git a/smoothie/build.gradle b/smoothie/build.gradle index ade984d0..a1dea76a 100644 --- a/smoothie/build.gradle +++ b/smoothie/build.gradle @@ -1,31 +1,33 @@ buildscript { repositories { - jcenter() google() + jcenter() } dependencies { - classpath ('com.android.tools.build:gradle:3.0.0-beta7') + classpath deps.androidPlugin } } apply plugin: 'com.android.library' +repositories { + google() +} + dependencies { compileOnly project(':toothpick') compileOnly deps.inject - compileOnly deps.supportv4 - testImplementation deps.supportv4 testImplementation project(':toothpick-testing') - testImplementation deps.junit + testImplementation deps.junit4 testImplementation deps.easymock testImplementation deps.robolectric } android { - compileSdkVersion 26 - buildToolsVersion '26.0.2' + compileSdkVersion 28 + buildToolsVersion '28.0.3' compileOptions { sourceCompatibility JavaVersion.VERSION_1_7 @@ -35,11 +37,7 @@ android { defaultConfig { minSdkVersion 15 - javaCompileOptions { - annotationProcessorOptions { - includeCompileClasspath = true - } - } + consumerProguardFiles 'proguard-rules.txt' } lintOptions { diff --git a/smoothie/proguard-rules.txt b/smoothie/proguard-rules.txt new file mode 100644 index 00000000..ee32225e --- /dev/null +++ b/smoothie/proguard-rules.txt @@ -0,0 +1,19 @@ +# Note that if we could use kapt to generate registries, possible to get rid of this +-keepattributes *Annotation* +# Do not obfuscate classes with Injected Constructors +-keepclasseswithmembernames class * { @javax.inject.Inject (...); } +# Do not obfuscate classes with Injected Fields +-keepclasseswithmembernames class * { @javax.inject.Inject ; } +# Do not obfuscate classes with Injected Methods +-keepclasseswithmembernames class * { @javax.inject.Inject ; } +-keep @android.support.annotation.Keep class * +-dontwarn javax.inject.** +-dontwarn javax.annotation.** +-keep class **__Factory { *; } +-keep class **__MemberInjector { *; } + +-adaptclassstrings +-keep class toothpick.** { *; } + +-keep @javax.inject.Singleton class * +#You need to keep your custom scopes too diff --git a/smoothie/src/main/java/toothpick/smoothie/annotations/ContextSingleton.java b/smoothie/src/main/java/toothpick/smoothie/annotations/ContextSingleton.java deleted file mode 100644 index 3a1302a6..00000000 --- a/smoothie/src/main/java/toothpick/smoothie/annotations/ContextSingleton.java +++ /dev/null @@ -1,28 +0,0 @@ -package toothpick.smoothie.annotations; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import javax.inject.Scope; - -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * Identifies a type that the injector only instantiates once - * per context. This scope annotation has to be bound to - * service & activity scopes. Not inherited. - * - * Note that this annotation is just provided to ease the migration - * from RG to TP. We highly recommend not keeping it after the migration - * is complete and to clearly identify what you inject: either the application context - * or an activity (or a service). Using this scope annotation and injection contexts blindly - * is a perfect recipe for memory leaks. - * - * @see javax.inject.Scope @Scope - * Deprecated, do not inject contexts blindly, this is a bad practice. Read above. - */ -@Scope -@Documented -@Retention(RUNTIME) -@Deprecated -public @interface ContextSingleton { -} diff --git a/smoothie/src/main/java/toothpick/smoothie/module/SmoothieApplicationModule.java b/smoothie/src/main/java/toothpick/smoothie/module/SmoothieApplicationModule.java index 95835cb6..6cea40f0 100644 --- a/smoothie/src/main/java/toothpick/smoothie/module/SmoothieApplicationModule.java +++ b/smoothie/src/main/java/toothpick/smoothie/module/SmoothieApplicationModule.java @@ -20,6 +20,7 @@ import android.media.AudioManager; import android.net.ConnectivityManager; import android.net.wifi.WifiManager; +import android.content.ClipboardManager; import android.os.Build; import android.os.Handler; import android.os.PowerManager; @@ -53,6 +54,7 @@ import static android.content.Context.VIBRATOR_SERVICE; import static android.content.Context.WINDOW_SERVICE; import static android.content.Context.WIFI_SERVICE; +import static android.content.Context.CLIPBOARD_SERVICE; public class SmoothieApplicationModule extends Module { public SmoothieApplicationModule(Application application) { @@ -99,6 +101,7 @@ private void bindSystemServices(Application application) { bindSystemService(application, TelephonyManager.class, TELEPHONY_SERVICE); bindSystemService(application, AudioManager.class, AUDIO_SERVICE); bindSystemService(application, DownloadManager.class, DOWNLOAD_SERVICE); + bindSystemService(application, ClipboardManager.class, CLIPBOARD_SERVICE); } private void bindSystemService(Application application, Class serviceClass, String serviceName) { diff --git a/toothpick-compiler/build.gradle b/toothpick-compiler/build.gradle index 0a084992..a958c628 100644 --- a/toothpick-compiler/build.gradle +++ b/toothpick-compiler/build.gradle @@ -6,11 +6,11 @@ sourceCompatibility = 1.7 targetCompatibility = 1.7 dependencies { - api project(':toothpick-generated-core') + api project(':toothpick') api deps.inject api deps.javapoet - testImplementation deps.junit + testImplementation deps.junit4 testImplementation deps.truth testImplementation deps.compiletesting testImplementation files(Jvm.current().getToolsJar()) diff --git a/toothpick-compiler/gradle.properties b/toothpick-compiler/gradle.properties index 784438ee..2434df29 100644 --- a/toothpick-compiler/gradle.properties +++ b/toothpick-compiler/gradle.properties @@ -1,4 +1,4 @@ POM_ARTIFACT_ID=toothpick-compiler POM_NAME=Toothpick Compiler POM_DESCRIPTION='Annotation Processors of toothpick' -POM_PACKAGING='jar' \ No newline at end of file +POM_PACKAGING='jar' diff --git a/toothpick-compiler/src/main/java/toothpick/compiler/common/ToothpickProcessor.java b/toothpick-compiler/src/main/java/toothpick/compiler/common/ToothpickProcessor.java index 33647c7f..338c4303 100644 --- a/toothpick-compiler/src/main/java/toothpick/compiler/common/ToothpickProcessor.java +++ b/toothpick-compiler/src/main/java/toothpick/compiler/common/ToothpickProcessor.java @@ -49,12 +49,6 @@ public abstract class ToothpickProcessor extends AbstractProcessor { public static final String SINGLETON_ANNOTATION_CLASS_NAME = "javax.inject.Singleton"; public static final String PRODUCES_SINGLETON_ANNOTATION_CLASS_NAME = "toothpick.ProvidesSingletonInScope"; - /** - * The name of the annotation processor option to declare in which package a registry should be generated. - * If this parameter is not passed, no registry is generated. - */ - public static final String PARAMETER_REGISTRY_PACKAGE_NAME = "toothpick_registry_package_name"; - /** * The name of the annotation processor option to exclude classes from the creation of member scopes & factories. * Exclude filters are java regex, multiple entries are comma separated. @@ -71,14 +65,6 @@ public abstract class ToothpickProcessor extends AbstractProcessor { */ public static final String PARAMETER_ANNOTATION_TYPES = "toothpick_annotations"; - /** - * The name annotation processor option to declare in which packages reside the sub-registries used by the generated registry, - * if it is created. Multiple entries are comma separated. - * - * @see #PARAMETER_REGISTRY_PACKAGE_NAME - */ - public static final String PARAMETER_REGISTRY_CHILDREN_PACKAGE_NAMES = "toothpick_registry_children_package_names"; - /** * The name of the annotation processor option to make the TP annotation processor crash when it can't generate * a factory for a class. By default the behavior is not to crash but emit a warning. Passing the value {@code true} @@ -102,12 +88,9 @@ public abstract class ToothpickProcessor extends AbstractProcessor { protected Types typeUtils; protected Filer filer; - protected String toothpickRegistryPackageName; - protected List toothpickRegistryChildrenPackageNameList; protected String toothpickExcludeFilters = "java.*,android.*"; protected Boolean toothpickCrashWhenMethodIsNotPackageVisible; protected Set supportedAnnotationTypes = new HashSet<>(); - private boolean hasAlreadyRun; @Override public synchronized void init(ProcessingEnvironment processingEnv) { @@ -127,20 +110,12 @@ public void addSupportedAnnotationType(String typeFQN) { supportedAnnotationTypes.add(typeFQN); } - protected void wasRun() { - hasAlreadyRun = true; - } - - protected boolean hasAlreadyRun() { - return hasAlreadyRun; - } - - protected boolean writeToFile(CodeGenerator codeGenerator, String fileDescription, Element... originatingElements) { + protected boolean writeToFile(CodeGenerator codeGenerator, String fileDescription, Element originatingElement) { Writer writer = null; boolean success = true; try { - JavaFileObject jfo = filer.createSourceFile(codeGenerator.getFqcn(), originatingElements); + JavaFileObject jfo = filer.createSourceFile(codeGenerator.getFqcn(), originatingElement); writer = jfo.openWriter(); writer.write(codeGenerator.brewJava()); } catch (IOException e) { @@ -161,44 +136,13 @@ protected boolean writeToFile(CodeGenerator codeGenerator, String fileDescriptio } /** - * Reads both annotation compilers {@link ToothpickProcessor#PARAMETER_REGISTRY_PACKAGE_NAME} and - * {@link ToothpickProcessor#PARAMETER_REGISTRY_CHILDREN_PACKAGE_NAMES} and - * {@link ToothpickProcessor#PARAMETER_EXCLUDES} - * options from the arguments passed to the processor. + * Reads both annotation compilers {@link ToothpickProcessor#PARAMETER_EXCLUDES} + * option from the arguments passed to the processor. */ protected void readCommonProcessorOptions() { - readOptionRegistryPackageName(); - readOptionRegistryChildrenPackageNames(); readOptionExcludes(); } - private void readOptionRegistryPackageName() { - Map options = processingEnv.getOptions(); - if (toothpickRegistryPackageName == null) { - toothpickRegistryPackageName = options.get(PARAMETER_REGISTRY_PACKAGE_NAME); - } - if (toothpickRegistryPackageName == null) { - warning("No option -A%s to the compiler." + " No registries will be generated.", PARAMETER_REGISTRY_PACKAGE_NAME); - } - } - - private void readOptionRegistryChildrenPackageNames() { - Map options = processingEnv.getOptions(); - if (toothpickRegistryChildrenPackageNameList == null) { - toothpickRegistryChildrenPackageNameList = new ArrayList<>(); - String toothpickRegistryChildrenPackageNames = options.get(PARAMETER_REGISTRY_CHILDREN_PACKAGE_NAMES); - if (toothpickRegistryChildrenPackageNames != null) { - String[] registryPackageNames = toothpickRegistryChildrenPackageNames.split(","); - for (String registryPackageName : registryPackageNames) { - toothpickRegistryChildrenPackageNameList.add(registryPackageName.trim()); - } - } - } - if (toothpickRegistryChildrenPackageNameList == null) { - warning("No option -A%s was passed to the compiler." + " No sub registries will be used.", PARAMETER_REGISTRY_CHILDREN_PACKAGE_NAMES); - } - } - private void readOptionExcludes() { Map options = processingEnv.getOptions(); if (options.containsKey(PARAMETER_EXCLUDES)) { diff --git a/toothpick-compiler/src/main/java/toothpick/compiler/factory/FactoryProcessor.java b/toothpick-compiler/src/main/java/toothpick/compiler/factory/FactoryProcessor.java index 7b423964..a97712ec 100644 --- a/toothpick-compiler/src/main/java/toothpick/compiler/factory/FactoryProcessor.java +++ b/toothpick-compiler/src/main/java/toothpick/compiler/factory/FactoryProcessor.java @@ -1,13 +1,11 @@ package toothpick.compiler.factory; -import java.lang.annotation.Annotation; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; +import toothpick.Factory; +import toothpick.ProvidesSingletonInScope; +import toothpick.compiler.common.ToothpickProcessor; +import toothpick.compiler.factory.generators.FactoryGenerator; +import toothpick.compiler.factory.targets.ConstructorInjectionTarget; + import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedOptions; import javax.inject.Inject; @@ -19,14 +17,14 @@ import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.lang.model.util.ElementFilter; -import toothpick.Factory; -import toothpick.ProvidesSingletonInScope; -import toothpick.compiler.common.ToothpickProcessor; -import toothpick.compiler.factory.generators.FactoryGenerator; -import toothpick.compiler.factory.targets.ConstructorInjectionTarget; -import toothpick.compiler.registry.generators.RegistryGenerator; -import toothpick.compiler.registry.targets.RegistryInjectionTarget; -import toothpick.registries.factory.AbstractFactoryRegistry; +import java.lang.annotation.Annotation; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; import static java.lang.String.format; import static javax.lang.model.element.Modifier.PRIVATE; @@ -54,8 +52,6 @@ */ //http://stackoverflow.com/a/2067863/693752 @SupportedOptions({ - ToothpickProcessor.PARAMETER_REGISTRY_PACKAGE_NAME, // - ToothpickProcessor.PARAMETER_REGISTRY_CHILDREN_PACKAGE_NAMES, // ToothpickProcessor.PARAMETER_EXCLUDES, // ToothpickProcessor.PARAMETER_ANNOTATION_TYPES, // ToothpickProcessor.PARAMETER_CRASH_WHEN_NO_FACTORY_CAN_BE_CREATED, // @@ -64,9 +60,11 @@ public class FactoryProcessor extends ToothpickProcessor { private static final String SUPPRESS_WARNING_ANNOTATION_INJECTABLE_VALUE = "injectable"; - private Map mapTypeElementToConstructorInjectionTarget = new LinkedHashMap<>(); + private Map mapTypeElementToConstructorInjectionTarget; private Boolean crashWhenNoFactoryCanBeCreated; + private Map allRoundsGeneratedToTypeElement = new HashMap<>(); + @Override public Set getSupportedAnnotationTypes() { supportedAnnotationTypes.add(ToothpickProcessor.INJECT_ANNOTATION_CLASS_NAME); @@ -79,40 +77,20 @@ public Set getSupportedAnnotationTypes() { @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { - if (hasAlreadyRun()) { - return false; - } - - wasRun(); readCommonProcessorOptions(); readCrashWhenNoFactoryCanBeCreatedOption(); - findAndParseTargets(roundEnv, annotations); + mapTypeElementToConstructorInjectionTarget = new LinkedHashMap<>(); + findAndParseTargets(roundEnv, annotations); // Generate Factories - List elementsWithFactoryCreated = new ArrayList<>(); - for (Map.Entry entry : mapTypeElementToConstructorInjectionTarget.entrySet()) { ConstructorInjectionTarget constructorInjectionTarget = entry.getValue(); FactoryGenerator factoryGenerator = new FactoryGenerator(constructorInjectionTarget, typeUtils); TypeElement typeElement = entry.getKey(); String fileDescription = format("Factory for type %s", typeElement); - boolean success = writeToFile(factoryGenerator, fileDescription, typeElement); - if (success) { - elementsWithFactoryCreated.add(typeElement); - } - } - - // Generate Registry - //this allows tests to by pass the option mechanism in processors - if (toothpickRegistryPackageName != null) { - RegistryInjectionTarget registryInjectionTarget = - new RegistryInjectionTarget(Factory.class, AbstractFactoryRegistry.class, toothpickRegistryPackageName, - toothpickRegistryChildrenPackageNameList, elementsWithFactoryCreated); - - String fileDescription = "Factory registry"; - Element[] allTypes = elementsWithFactoryCreated.toArray(new Element[elementsWithFactoryCreated.size()]); - writeToFile(new RegistryGenerator(registryInjectionTarget, typeUtils), fileDescription, allTypes); + writeToFile(factoryGenerator, fileDescription, typeElement); + allRoundsGeneratedToTypeElement.put(factoryGenerator.getFqcn(), typeElement); } return false; @@ -401,22 +379,18 @@ private boolean canTypeHaveAFactory(TypeElement typeElement) { return !isAbstract && !isPrivate; } - //used for testing only - void setToothpickRegistryPackageName(String toothpickRegistryPackageName) { - this.toothpickRegistryPackageName = toothpickRegistryPackageName; - } - - //used for testing only - void setToothpickRegistryChildrenPackageNameList(List toothpickRegistryChildrenPackageNameList) { - this.toothpickRegistryChildrenPackageNameList = toothpickRegistryChildrenPackageNameList; - } - //used for testing only void setToothpickExcludeFilters(String toothpickExcludeFilters) { this.toothpickExcludeFilters = toothpickExcludeFilters; } + //used for testing only void setCrashWhenNoFactoryCanBeCreated(boolean crashWhenNoFactoryCanBeCreated) { this.crashWhenNoFactoryCanBeCreated = crashWhenNoFactoryCanBeCreated; } + + //used for testing only + TypeElement getOriginatingElement(String generatedQualifiedName) { + return allRoundsGeneratedToTypeElement.get(generatedQualifiedName); + } } diff --git a/toothpick-compiler/src/main/java/toothpick/compiler/factory/generators/FactoryGenerator.java b/toothpick-compiler/src/main/java/toothpick/compiler/factory/generators/FactoryGenerator.java index dd43e89a..e88e2013 100644 --- a/toothpick-compiler/src/main/java/toothpick/compiler/factory/generators/FactoryGenerator.java +++ b/toothpick-compiler/src/main/java/toothpick/compiler/factory/generators/FactoryGenerator.java @@ -25,7 +25,7 @@ */ public class FactoryGenerator extends CodeGenerator { - private static final String FACTORY_SUFFIX = "$$Factory"; + private static final String FACTORY_SUFFIX = "__Factory"; private ConstructorInjectionTarget constructorInjectionTarget; @@ -61,7 +61,7 @@ private void emitSuperMemberInjectorFieldIfNeeded(TypeSpec.Builder scopeMemberTy FieldSpec.Builder superMemberInjectorField = FieldSpec.builder(memberInjectorSuperParameterizedTypeName, "memberInjector", Modifier.PRIVATE) //TODO use proper typing here - .initializer("new $L$$$$MemberInjector()", getGeneratedFQNClassName(constructorInjectionTarget.superClassThatNeedsMemberInjection)); + .initializer("new $L__MemberInjector()", getGeneratedFQNClassName(constructorInjectionTarget.superClassThatNeedsMemberInjection)); scopeMemberTypeSpec.addField(superMemberInjectorField.build()); } } diff --git a/toothpick-compiler/src/main/java/toothpick/compiler/memberinjector/MemberInjectorProcessor.java b/toothpick-compiler/src/main/java/toothpick/compiler/memberinjector/MemberInjectorProcessor.java index b6bad464..37261591 100644 --- a/toothpick-compiler/src/main/java/toothpick/compiler/memberinjector/MemberInjectorProcessor.java +++ b/toothpick-compiler/src/main/java/toothpick/compiler/memberinjector/MemberInjectorProcessor.java @@ -1,28 +1,26 @@ package toothpick.compiler.memberinjector; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; +import toothpick.MemberInjector; +import toothpick.compiler.common.ToothpickProcessor; +import toothpick.compiler.memberinjector.generators.MemberInjectorGenerator; +import toothpick.compiler.memberinjector.targets.FieldInjectionTarget; +import toothpick.compiler.memberinjector.targets.MethodInjectionTarget; + import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedOptions; import javax.inject.Inject; -import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.lang.model.util.ElementFilter; -import toothpick.MemberInjector; -import toothpick.compiler.common.ToothpickProcessor; -import toothpick.compiler.memberinjector.generators.MemberInjectorGenerator; -import toothpick.compiler.memberinjector.targets.FieldInjectionTarget; -import toothpick.compiler.memberinjector.targets.MethodInjectionTarget; -import toothpick.compiler.registry.generators.RegistryGenerator; -import toothpick.compiler.registry.targets.RegistryInjectionTarget; -import toothpick.registries.memberinjector.AbstractMemberInjectorRegistry; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; /** * This processor's role is to create {@link MemberInjector}. @@ -37,34 +35,32 @@ //http://stackoverflow.com/a/2067863/693752 @SupportedAnnotationTypes({ ToothpickProcessor.INJECT_ANNOTATION_CLASS_NAME }) @SupportedOptions({ - ToothpickProcessor.PARAMETER_REGISTRY_PACKAGE_NAME, // - ToothpickProcessor.PARAMETER_REGISTRY_CHILDREN_PACKAGE_NAMES, // ToothpickProcessor.PARAMETER_EXCLUDES, // ToothpickProcessor.PARAMETER_CRASH_WHEN_INJECTED_METHOD_IS_NOT_PACKAGE }) // public class MemberInjectorProcessor extends ToothpickProcessor { - private Map> mapTypeElementToFieldInjectorTargetList = new LinkedHashMap<>(); - private Map> mapTypeElementToMethodInjectorTargetList = new LinkedHashMap<>(); - private Map mapTypeElementToSuperTypeElementThatNeedsInjection = new LinkedHashMap<>(); + private Map> mapTypeElementToFieldInjectorTargetList; + private Map> mapTypeElementToMethodInjectorTargetList; + private Map mapTypeElementToSuperTypeElementThatNeedsInjection; + + private Map allRoundsGeneratedToTypeElement = new HashMap<>(); @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { - if (hasAlreadyRun()) { - return false; - } - - wasRun(); readCommonProcessorOptions(); readOptionCrashWhenMethodIsNotPackageProtected(); + + mapTypeElementToFieldInjectorTargetList = new LinkedHashMap<>(); + mapTypeElementToMethodInjectorTargetList = new LinkedHashMap<>(); + mapTypeElementToSuperTypeElementThatNeedsInjection = new LinkedHashMap<>(); findAndParseTargets(roundEnv); // Generate member scopes Set elementWithInjectionSet = new HashSet<>(); elementWithInjectionSet.addAll(mapTypeElementToFieldInjectorTargetList.keySet()); elementWithInjectionSet.addAll(mapTypeElementToMethodInjectorTargetList.keySet()); - List elementsWithMemberInjectorCreated = new ArrayList<>(); for (TypeElement typeElement : elementWithInjectionSet) { List fieldInjectionTargetList = mapTypeElementToFieldInjectorTargetList.get(typeElement); @@ -77,21 +73,8 @@ public boolean process(Set annotations, RoundEnvironment methodInjectionTargetList, // typeUtils); String fileDescription = String.format("MemberInjector for type %s", typeElement); - boolean success = writeToFile(memberInjectorGenerator, fileDescription, typeElement); - if (success) { - elementsWithMemberInjectorCreated.add(typeElement); - } - } - - // Generate Registry - if (toothpickRegistryPackageName != null) { - RegistryInjectionTarget registryInjectionTarget = - new RegistryInjectionTarget(MemberInjector.class, AbstractMemberInjectorRegistry.class, toothpickRegistryPackageName, - toothpickRegistryChildrenPackageNameList, elementsWithMemberInjectorCreated); - - String fileDescription = "MemberInjector registry"; - Element[] allTypes = elementsWithMemberInjectorCreated.toArray(new Element[elementsWithMemberInjectorCreated.size()]); - writeToFile(new RegistryGenerator(registryInjectionTarget, typeUtils), fileDescription, allTypes); + writeToFile(memberInjectorGenerator, fileDescription, typeElement); + allRoundsGeneratedToTypeElement.put(memberInjectorGenerator.getFqcn(), typeElement); } return false; @@ -182,16 +165,6 @@ private MethodInjectionTarget createMethodInjectionTarget(ExecutableElement meth return methodInjectionTarget; } - //used for testing only - void setToothpickRegistryPackageName(String toothpickRegistryPackageName) { - this.toothpickRegistryPackageName = toothpickRegistryPackageName; - } - - //used for testing only - void setToothpickRegistryChildrenPackageNameList(List toothpickRegistryChildrenPackageNameList) { - this.toothpickRegistryChildrenPackageNameList = toothpickRegistryChildrenPackageNameList; - } - //used for testing only void setToothpickExcludeFilters(String toothpickExcludeFilters) { this.toothpickExcludeFilters = toothpickExcludeFilters; @@ -201,4 +174,9 @@ void setToothpickExcludeFilters(String toothpickExcludeFilters) { void setCrashOrWarnWhenMethodIsNotPackageVisible(boolean crashOrWarnWhenMethodIsNotPackageVisible) { this.toothpickCrashWhenMethodIsNotPackageVisible = crashOrWarnWhenMethodIsNotPackageVisible; } + + //used for testing only + TypeElement getOriginatingElement(String generatedQualifiedName) { + return allRoundsGeneratedToTypeElement.get(generatedQualifiedName); + } } diff --git a/toothpick-compiler/src/main/java/toothpick/compiler/memberinjector/generators/MemberInjectorGenerator.java b/toothpick-compiler/src/main/java/toothpick/compiler/memberinjector/generators/MemberInjectorGenerator.java index 9a789075..4d93b0d8 100644 --- a/toothpick-compiler/src/main/java/toothpick/compiler/memberinjector/generators/MemberInjectorGenerator.java +++ b/toothpick-compiler/src/main/java/toothpick/compiler/memberinjector/generators/MemberInjectorGenerator.java @@ -25,7 +25,7 @@ */ public class MemberInjectorGenerator extends CodeGenerator { - private static final String MEMBER_INJECTOR_SUFFIX = "$$MemberInjector"; + private static final String MEMBER_INJECTOR_SUFFIX = "__MemberInjector"; private TypeElement targetClass; private TypeElement superClassThatNeedsInjection; @@ -66,7 +66,7 @@ private void emitSuperMemberInjectorFieldIfNeeded(TypeSpec.Builder scopeMemberTy FieldSpec.Builder superMemberInjectorField = FieldSpec.builder(MemberInjector.class, "superMemberInjector", Modifier.PRIVATE) //TODO use proper typing here - .initializer("new $L$$$$MemberInjector()", getGeneratedFQNClassName(superClassThatNeedsInjection)); + .initializer("new $L__MemberInjector()", getGeneratedFQNClassName(superClassThatNeedsInjection)); scopeMemberTypeSpec.addField(superMemberInjectorField.build()); } } diff --git a/toothpick-compiler/src/main/java/toothpick/compiler/registry/generators/RegistryGenerator.java b/toothpick-compiler/src/main/java/toothpick/compiler/registry/generators/RegistryGenerator.java deleted file mode 100644 index 5f84b831..00000000 --- a/toothpick-compiler/src/main/java/toothpick/compiler/registry/generators/RegistryGenerator.java +++ /dev/null @@ -1,221 +0,0 @@ -package toothpick.compiler.registry.generators; - -import com.squareup.javapoet.ClassName; -import com.squareup.javapoet.CodeBlock; -import com.squareup.javapoet.FieldSpec; -import com.squareup.javapoet.JavaFile; -import com.squareup.javapoet.MethodSpec; -import com.squareup.javapoet.ParameterizedTypeName; -import com.squareup.javapoet.TypeName; -import com.squareup.javapoet.TypeSpec; -import com.squareup.javapoet.TypeVariableName; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.lang.model.element.Modifier; -import javax.lang.model.element.TypeElement; -import javax.lang.model.util.Types; - -import toothpick.compiler.common.generators.CodeGenerator; -import toothpick.compiler.registry.targets.RegistryInjectionTarget; -import toothpick.registries.FactoryRegistry; -import toothpick.registries.MemberInjectorRegistry; - -/** - * Generates a Registry for a given {@link RegistryInjectionTarget}. - * - * See {@link FactoryRegistry} and {@link MemberInjectorRegistry} for Registry types. - */ -public class RegistryGenerator extends CodeGenerator { - - /* @VisibleForTesting */ static int groupSize = 200; - - private static final String MAP_FIELD_NAME = "classNameToIndex"; - private static final String GET_FROM_THIS_REGISTRY_METHOD_NAME = "getFromThisRegistry"; - private final RegistryInjectionTarget registryInjectionTarget; - - private final TypeVariableName typeVariable = TypeVariableName.get("T"); - private final ParameterizedTypeName factoryType; - private final ParameterizedTypeName clazzArgType; - private final int numGroups; - - private final List classNameList = new ArrayList<>(); - - public RegistryGenerator(RegistryInjectionTarget registryInjectionTarget, Types types) { - super(types); - this.registryInjectionTarget = registryInjectionTarget; - factoryType = ParameterizedTypeName.get(ClassName.get(registryInjectionTarget.type), typeVariable); - clazzArgType = ParameterizedTypeName.get(ClassName.get(Class.class), typeVariable); - - for (TypeElement element : registryInjectionTarget.injectionTargetList) { - classNameList.add(getGeneratedFQNClassName(element)); - } - - numGroups = (classNameList.size() + groupSize - 1) / groupSize; - } - - @Override - public String brewJava() { - TypeSpec.Builder classBuilder = TypeSpec.classBuilder(registryInjectionTarget.registryName) - .addModifiers(Modifier.PUBLIC, Modifier.FINAL) - .superclass(ClassName.get(registryInjectionTarget.superClass)); - - emitMapField(classBuilder); - emitConstructor(classBuilder); - emitRegisterMethods(classBuilder); - emitPublicGetterMethod(classBuilder); - emitGetFromThisRegistryMethod(classBuilder); - emitGetFromGroupMethods(classBuilder); - - JavaFile javaFile = JavaFile.builder(registryInjectionTarget.packageName, classBuilder.build()) - .addFileComment("Generated code from Toothpick. Do not modify!") - .build(); - - return javaFile.toString(); - } - - private void emitMapField(TypeSpec.Builder classBuilder) { - FieldSpec fieldSpec = FieldSpec.builder(ParameterizedTypeName.get(Map.class, String.class, Integer.class), - MAP_FIELD_NAME, - Modifier.PRIVATE, Modifier.FINAL) - .initializer("new $T<>()", HashMap.class) - .build(); - classBuilder.addField(fieldSpec); - } - - private void emitConstructor(TypeSpec.Builder classBuilder) { - MethodSpec.Builder constructorBuilder = MethodSpec.constructorBuilder().addModifiers(Modifier.PUBLIC); - - for (String childPackageName : registryInjectionTarget.childrenRegistryPackageNameList) { - ClassName registryClassName = ClassName.get(childPackageName, registryInjectionTarget.registryName); - constructorBuilder.addStatement("addChildRegistry(new $L())", registryClassName); - } - - for (int groupIndex = 0; groupIndex < numGroups; groupIndex++) { - constructorBuilder.addStatement("$L()", nameOfRegisterGroupMethod(groupIndex)); - } - - classBuilder.addMethod(constructorBuilder.build()); - } - - private void emitRegisterMethods(TypeSpec.Builder classBuilder) { - for (int groupIndex = 0; groupIndex < numGroups; groupIndex++) { - emitRegisterGroupMethod(classBuilder, groupIndex); - } - } - - private void emitRegisterGroupMethod(TypeSpec.Builder classBuilder, int groupIndex) { - MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(nameOfRegisterGroupMethod(groupIndex)) - .addModifiers(Modifier.PRIVATE); - - int groupStartIndex = groupIndex * groupSize; - for (int indexInGroup = 0; indexInGroup < groupSize; indexInGroup++) { - int index = groupStartIndex + indexInGroup; - if (index >= classNameList.size()) { - break; - } - methodBuilder.addStatement("$L.put($S, $L)", - MAP_FIELD_NAME, classNameList.get(index), index); - } - classBuilder.addMethod(methodBuilder.build()); - } - - private void emitPublicGetterMethod(TypeSpec.Builder classBuilder) { - MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(registryInjectionTarget.getterName) - .addTypeVariable(typeVariable) - .addAnnotation(Override.class) - .addModifiers(Modifier.PUBLIC) - .addParameter(clazzArgType, "clazz") - .returns(factoryType); - - methodBuilder.addStatement("$T factory = $L(clazz)", factoryType, GET_FROM_THIS_REGISTRY_METHOD_NAME); - - CodeBlock.Builder blockBuilder = CodeBlock.builder().beginControlFlow("if (factory == null)"); - blockBuilder.addStatement("return $L(clazz)", registryInjectionTarget.childrenGetterName); - blockBuilder.endControlFlow(); - methodBuilder.addCode(blockBuilder.build()); - - methodBuilder.addStatement("return factory"); - - classBuilder.addMethod(methodBuilder.build()); - } - - private void emitGetFromThisRegistryMethod(TypeSpec.Builder classBuilder) { - MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(GET_FROM_THIS_REGISTRY_METHOD_NAME) - .addTypeVariable(typeVariable) - .addModifiers(Modifier.PRIVATE) - .addParameter(clazzArgType, "clazz") - .returns(factoryType); - - if (classNameList.isEmpty()) { - methodBuilder.addStatement("return null"); - classBuilder.addMethod(methodBuilder.build()); - return; - } - - methodBuilder.addStatement("$T index = $L.get(clazz.getName())", Integer.class, MAP_FIELD_NAME); - - CodeBlock.Builder blockBuilder = CodeBlock.builder().beginControlFlow("if (index == null)"); - blockBuilder.addStatement("return null"); - blockBuilder.endControlFlow(); - methodBuilder.addCode(blockBuilder.build()); - - methodBuilder.addStatement("int groupIndex = index / $L", groupSize); - - CodeBlock.Builder switchBuilder = CodeBlock.builder().beginControlFlow("switch(groupIndex)"); - for (int groupIndex = 0; groupIndex < numGroups; groupIndex++) { - switchBuilder.addStatement("case $L: return $L(index)", - groupIndex, nameOfGetFromGroupMethod(groupIndex)); - } - switchBuilder.endControlFlow(); - methodBuilder.addCode(switchBuilder.build()); - - methodBuilder.addStatement("return null"); - - classBuilder.addMethod(methodBuilder.build()); - } - - private void emitGetFromGroupMethods(TypeSpec.Builder classBuilder) { - for (int groupIndex = 0; groupIndex < numGroups; groupIndex++) { - emitGetFromGroupMethod(classBuilder, groupIndex); - } - } - - private void emitGetFromGroupMethod(TypeSpec.Builder classBuilder, int groupIndex) { - MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(nameOfGetFromGroupMethod(groupIndex)) - .addTypeVariable(typeVariable) - .addModifiers(Modifier.PRIVATE) - .addParameter(TypeName.INT, "index") - .returns(factoryType); - - int groupStartIndex = groupIndex * groupSize; - String typeSimpleName = registryInjectionTarget.type.getSimpleName(); - CodeBlock.Builder switchBuilder = CodeBlock.builder().beginControlFlow("switch(index)"); - for (int index = groupStartIndex; - index < groupStartIndex + groupSize && index < classNameList.size(); index++) { - switchBuilder.addStatement("case $L: return ($L) new $L$$$$$L()", - index, typeSimpleName, classNameList.get(index), typeSimpleName); - } - switchBuilder.endControlFlow(); - methodBuilder.addCode(switchBuilder.build()); - methodBuilder.addStatement("return null"); - - classBuilder.addMethod(methodBuilder.build()); - } - - private String nameOfRegisterGroupMethod(int groupIndex) { - return "registerGroup" + groupIndex; - } - - private String nameOfGetFromGroupMethod(int groupIndex) { - return "getFromGroup" + groupIndex; - } - - @Override - public String getFqcn() { - return registryInjectionTarget.getFqcn(); - } -} diff --git a/toothpick-compiler/src/main/java/toothpick/compiler/registry/targets/RegistryInjectionTarget.java b/toothpick-compiler/src/main/java/toothpick/compiler/registry/targets/RegistryInjectionTarget.java deleted file mode 100644 index df0c077f..00000000 --- a/toothpick-compiler/src/main/java/toothpick/compiler/registry/targets/RegistryInjectionTarget.java +++ /dev/null @@ -1,57 +0,0 @@ -package toothpick.compiler.registry.targets; - -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import javax.lang.model.element.TypeElement; -import toothpick.compiler.registry.generators.RegistryGenerator; -import toothpick.registries.FactoryRegistry; -import toothpick.registries.MemberInjectorRegistry; - -/** - * Stores the information needed by {@link RegistryGenerator} to generate a Registry. - * - * See {@link FactoryRegistry} and {@link MemberInjectorRegistry} for Registry types. - */ -public class RegistryInjectionTarget { - - private static final String REGISTRY_NAME = "%sRegistry"; - private static final String GETTER_NAME = "get%s"; - private static final String CHILDREN_GETTER_NAME = "get%sInChildrenRegistries"; - - public Class type; // Factory.class - public Class superClass; // toothpick.registries.factory.AbstractFactoryRegistry - public String packageName; - public List childrenRegistryPackageNameList; - public List injectionTargetList; - - public String registryName; - public String getterName; - public String childrenGetterName; - - public RegistryInjectionTarget(Class type, Class superClass, String packageName, - List childrenRegistryPackageNameList, List injectionTargetList) { - this.type = type; - this.superClass = superClass; - this.packageName = packageName; - this.childrenRegistryPackageNameList = childrenRegistryPackageNameList; - this.injectionTargetList = injectionTargetList; - Collections.sort(injectionTargetList, new TypeElementComparator()); - - String typeSimpleName = type.getSimpleName(); - this.registryName = String.format(REGISTRY_NAME, typeSimpleName); - this.getterName = String.format(GETTER_NAME, typeSimpleName); - this.childrenGetterName = String.format(CHILDREN_GETTER_NAME, typeSimpleName); - } - - public String getFqcn() { - return packageName + "." + registryName; - } - - private static class TypeElementComparator implements Comparator { - @Override - public int compare(TypeElement t0, TypeElement t1) { - return t0.getQualifiedName().toString().compareTo(t1.getQualifiedName().toString()); - } - } -} diff --git a/toothpick-compiler/src/main/resources/META-INF/gradle/incremental.annotation.processors b/toothpick-compiler/src/main/resources/META-INF/gradle/incremental.annotation.processors new file mode 100644 index 00000000..f87f6df5 --- /dev/null +++ b/toothpick-compiler/src/main/resources/META-INF/gradle/incremental.annotation.processors @@ -0,0 +1,2 @@ +toothpick.compiler.factory.FactoryProcessor,isolating +toothpick.compiler.memberinjector.MemberInjectorProcessor,isolating diff --git a/toothpick-compiler/src/test/java/toothpick/compiler/factory/BaseFactoryTest.java b/toothpick-compiler/src/test/java/toothpick/compiler/factory/BaseFactoryTest.java index a5882169..01607a06 100644 --- a/toothpick-compiler/src/test/java/toothpick/compiler/factory/BaseFactoryTest.java +++ b/toothpick-compiler/src/test/java/toothpick/compiler/factory/BaseFactoryTest.java @@ -17,11 +17,11 @@ protected void assertThatCompileWithoutErrorButNoFactoryIsCreated(JavaFileObject .processedWith(ProcessorTestUtilities.factoryAndMemberInjectorProcessors()) .compilesWithoutError() .and() - .generatesFileNamed(StandardLocation.locationFor("CLASS_OUTPUT"), "test", noFactoryClass + "$$Factory.class"); + .generatesFileNamed(StandardLocation.locationFor("CLASS_OUTPUT"), "test", noFactoryClass + "__Factory.class"); fail("A factory was created when it shouldn't."); } catch (AssertionError e) { assertThat(e.getMessage(), containsString( - String.format("generated the file named \"%s$$Factory.class\" in package \"%s\";", noFactoryClass, noFactoryPackageName))); + String.format("generated the file named \"%s__Factory.class\" in package \"%s\";", noFactoryClass, noFactoryPackageName))); } } } diff --git a/toothpick-compiler/src/test/java/toothpick/compiler/factory/FactoryOriginatingElementTest.java b/toothpick-compiler/src/test/java/toothpick/compiler/factory/FactoryOriginatingElementTest.java new file mode 100644 index 00000000..f5e9184c --- /dev/null +++ b/toothpick-compiler/src/test/java/toothpick/compiler/factory/FactoryOriginatingElementTest.java @@ -0,0 +1,38 @@ +package toothpick.compiler.factory; + +import com.google.common.base.Joiner; +import com.google.testing.compile.JavaFileObjects; +import org.junit.Test; + +import javax.annotation.processing.Processor; +import javax.lang.model.element.TypeElement; +import javax.tools.JavaFileObject; + +import static com.google.common.truth.Truth.assert_; +import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource; +import static org.junit.Assert.assertTrue; + +public class FactoryOriginatingElementTest { + + @Test + public void testOriginatingElement() { + JavaFileObject source = JavaFileObjects.forSourceString("test.TestOriginatingElement", Joiner.on('\n').join(// + "package test;", // + "import javax.inject.Inject;", // + "public class TestOriginatingElement {", // + " @Inject public TestOriginatingElement() {}", // + "}" // + )); + + Iterable processors = ProcessorTestUtilities.factoryProcessors(); + + assert_().about(javaSource()) + .that(source) + .processedWith(processors) + .compilesWithoutError(); + + FactoryProcessor factoryProcessor = (FactoryProcessor) processors.iterator().next(); + TypeElement enclosingElement = factoryProcessor.getOriginatingElement("test.TestOriginatingElement__Factory"); + assertTrue(enclosingElement.getQualifiedName().contentEquals("test.TestOriginatingElement")); + } +} diff --git a/toothpick-compiler/src/test/java/toothpick/compiler/factory/FactoryRegistryTest.java b/toothpick-compiler/src/test/java/toothpick/compiler/factory/FactoryRegistryTest.java deleted file mode 100644 index cf52f118..00000000 --- a/toothpick-compiler/src/test/java/toothpick/compiler/factory/FactoryRegistryTest.java +++ /dev/null @@ -1,460 +0,0 @@ -package toothpick.compiler.factory; - -import com.google.common.base.Joiner; -import com.google.testing.compile.JavaFileObjects; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestRule; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import javax.annotation.processing.Processor; -import javax.tools.JavaFileObject; - -import toothpick.compiler.registry.generators.RegistryGeneratorGroupSizeRule; - -import static com.google.common.truth.Truth.assert_; -import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource; -import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources; - -public class FactoryRegistryTest { - - @Rule - public final TestRule groupSizeRule = new RegistryGeneratorGroupSizeRule(3); - - @Test - public void testRegistry_withNoFactories() { - JavaFileObject source = injectableClass("Class0"); - - JavaFileObject expectedSource = JavaFileObjects.forSourceString("toothpick/FactoryRegistry", Joiner.on("\n").join( - "package toothpick;", // - "", // - "import java.lang.Class;", // - "import java.lang.Integer;", // - "import java.lang.Override;", // - "import java.lang.String;", // - "import java.util.HashMap;", // - "import java.util.Map;", // - "import toothpick.registries.factory.AbstractFactoryRegistry;", // - "", // - "public final class FactoryRegistry extends AbstractFactoryRegistry {", // - " private final Map classNameToIndex = new HashMap<>();", // - "", // - " public FactoryRegistry() {", // - " }", // - "", // - " @Override", // - " public Factory getFactory(Class clazz) {", // - " Factory factory = getFromThisRegistry(clazz);", // - " if (factory == null) {", // - " return getFactoryInChildrenRegistries(clazz);", // - " }", // - " return factory;", // - " }", // - "", // - " private Factory getFromThisRegistry(Class clazz) {", // - " return null;", // - " }", // - "}")); - - assert_().about(javaSource()) - .that(source) - .processedWith(ProcessorTestUtilities.factoryProcessors("toothpick", - Collections.EMPTY_LIST, "java.*,android.*,test.*")) - .compilesWithoutError() - .and() - .generatesSources(expectedSource); - } - - @Test - public void testRegistry_WithOneFactory() { - JavaFileObject source = injectableClass("Class0"); - - JavaFileObject expectedSource = JavaFileObjects.forSourceString("toothpick/FactoryRegistry", Joiner.on('\n').join( - "package toothpick;", // - "", // - "import java.lang.Class;", // - "import java.lang.Integer;", // - "import java.lang.Override;", // - "import java.lang.String;", // - "import java.util.HashMap;", // - "import java.util.Map;", // - "import toothpick.registries.factory.AbstractFactoryRegistry;", // - "", // - "public final class FactoryRegistry extends AbstractFactoryRegistry {", // - " private final Map classNameToIndex = new HashMap<>();", // - "", // - " public FactoryRegistry() {", // - " registerGroup0();", // - " }", // - "", // - " private void registerGroup0() {", // - " classNameToIndex.put(\"test.Class0\", 0);", // - " }", // - "", // - " @Override", // - " public Factory getFactory(Class clazz) {", // - " Factory factory = getFromThisRegistry(clazz);", // - " if (factory == null) {", // - " return getFactoryInChildrenRegistries(clazz);", // - " }", // - " return factory;", // - " }", // - "", // - " private Factory getFromThisRegistry(Class clazz) {", // - " Integer index = classNameToIndex.get(clazz.getName());", // - " if (index == null) {", // - " return null;", // - " }", // - " int groupIndex = index / 3;", // - " switch(groupIndex) {", // - " case 0: return getFromGroup0(index);", // - " }", // - " return null;", // - " }", // - "", // - " private Factory getFromGroup0(int index) {", // - " switch(index) {", // - " case 0: return (Factory) new test.Class0$$Factory();", // - " }", // - " return null;", // - " }", // - "}" - )); - - assert_().about(javaSource()) - .that(source) - .processedWith(defaultFactoryProcessor()) - .compilesWithoutError() - .and() - .generatesSources(expectedSource); - } - - @Test - public void testRegistry_WithOneCompleteGroupOfFactories() { - Iterable sources = injectableClasses("Class0", "Class1", "Class2"); - - JavaFileObject expectedSource = JavaFileObjects.forSourceString("toothpick/FactoryRegistry", Joiner.on('\n').join( - "package toothpick;", // - "", // - "import java.lang.Class;", // - "import java.lang.Integer;", // - "import java.lang.Override;", // - "import java.lang.String;", // - "import java.util.HashMap;", // - "import java.util.Map;", // - "import toothpick.registries.factory.AbstractFactoryRegistry;", // - "", // - "public final class FactoryRegistry extends AbstractFactoryRegistry {", // - " private final Map classNameToIndex = new HashMap<>();", // - "", // - " public FactoryRegistry() {", // - " registerGroup0();", // - " }", // - "", // - " private void registerGroup0() {", // - " classNameToIndex.put(\"test.Class0\", 0);", // - " classNameToIndex.put(\"test.Class1\", 1);", // - " classNameToIndex.put(\"test.Class2\", 2);", // - " }", // - "", // - " @Override", // - " public Factory getFactory(Class clazz) {", // - " Factory factory = getFromThisRegistry(clazz);", // - " if (factory == null) {", // - " return getFactoryInChildrenRegistries(clazz);", // - " }", // - " return factory;", // - " }", // - "", // - " private Factory getFromThisRegistry(Class clazz) {", // - " Integer index = classNameToIndex.get(clazz.getName());", // - " if (index == null) {", // - " return null;", // - " }", // - " int groupIndex = index / 3;", // - " switch(groupIndex) {", // - " case 0: return getFromGroup0(index);", // - " }", // - " return null;", // - " }", // - "", // - " private Factory getFromGroup0(int index) {", // - " switch(index) {", // - " case 0: return (Factory) new test.Class0$$Factory();", // - " case 1: return (Factory) new test.Class1$$Factory();", // - " case 2: return (Factory) new test.Class2$$Factory();", // - " }", // - " return null;", // - " }", // - "}" - )); - - assert_().about(javaSources()) - .that(sources) - .processedWith(defaultFactoryProcessor()) - .compilesWithoutError() - .and() - .generatesSources(expectedSource); - } - - @Test - public void testRegistry_WithOneComplete_AndOneIncomplete_GroupOfFactories() { - Iterable sources = injectableClasses("Class0", "Class1", "Class2", "Class3", "Class4"); - - JavaFileObject expectedSource = JavaFileObjects.forSourceString("toothpick/FactoryRegistry", Joiner.on('\n').join( - "package toothpick;", // - "", // - "import java.lang.Class;", // - "import java.lang.Integer;", // - "import java.lang.Override;", // - "import java.lang.String;", // - "import java.util.HashMap;", // - "import java.util.Map;", // - "import toothpick.registries.factory.AbstractFactoryRegistry;", // - "", // - "public final class FactoryRegistry extends AbstractFactoryRegistry {", // - " private final Map classNameToIndex = new HashMap<>();", // - "", // - " public FactoryRegistry() {", // - " registerGroup0();", // - " registerGroup1();", // - " }", // - "", // - " private void registerGroup0() {", // - " classNameToIndex.put(\"test.Class0\", 0);", // - " classNameToIndex.put(\"test.Class1\", 1);", // - " classNameToIndex.put(\"test.Class2\", 2);", // - " }", // - "", // - " private void registerGroup1() {", // - " classNameToIndex.put(\"test.Class3\", 3);", // - " classNameToIndex.put(\"test.Class4\", 4);", // - " }", // - "", // - " @Override", // - " public Factory getFactory(Class clazz) {", // - " Factory factory = getFromThisRegistry(clazz);", // - " if (factory == null) {", // - " return getFactoryInChildrenRegistries(clazz);", // - " }", // - " return factory;", // - " }", // - "", // - " private Factory getFromThisRegistry(Class clazz) {", // - " Integer index = classNameToIndex.get(clazz.getName());", // - " if (index == null) {", // - " return null;", // - " }", // - " int groupIndex = index / 3;", // - " switch(groupIndex) {", // - " case 0: return getFromGroup0(index);", // - " case 1: return getFromGroup1(index);", // - " }", // - " return null;", // - " }", // - "", // - " private Factory getFromGroup0(int index) {", // - " switch(index) {", // - " case 0: return (Factory) new test.Class0$$Factory();", // - " case 1: return (Factory) new test.Class1$$Factory();", // - " case 2: return (Factory) new test.Class2$$Factory();", // - " }", // - " return null;", // - " }", // - "", // - " private Factory getFromGroup1(int index) {", // - " switch(index) {", // - " case 3: return (Factory) new test.Class3$$Factory();", // - " case 4: return (Factory) new test.Class4$$Factory();", // - " }", // - " return null;", // - " }", // - "}" - )); - - assert_().about(javaSources()) - .that(sources) - .processedWith(defaultFactoryProcessor()) - .compilesWithoutError() - .and() - .generatesSources(expectedSource); - } - - @Test - public void testRegistry_WithTwoComplete_GroupsOfFactories() { - Iterable sources = injectableClasses("Class0", "Class1", "Class2", "Class3", "Class4", "Class5"); - - JavaFileObject expectedSource = JavaFileObjects.forSourceString("toothpick/FactoryRegistry", Joiner.on('\n').join( - "package toothpick;", // - "", // - "import java.lang.Class;", // - "import java.lang.Integer;", // - "import java.lang.Override;", // - "import java.lang.String;", // - "import java.util.HashMap;", // - "import java.util.Map;", // - "import toothpick.registries.factory.AbstractFactoryRegistry;", // - "", // - "public final class FactoryRegistry extends AbstractFactoryRegistry {", // - " private final Map classNameToIndex = new HashMap<>();", // - "", // - " public FactoryRegistry() {", // - " registerGroup0();", // - " registerGroup1();", // - " }", // - "", // - " private void registerGroup0() {", // - " classNameToIndex.put(\"test.Class0\", 0);", // - " classNameToIndex.put(\"test.Class1\", 1);", // - " classNameToIndex.put(\"test.Class2\", 2);", // - " }", // - "", // - " private void registerGroup1() {", // - " classNameToIndex.put(\"test.Class3\", 3);", // - " classNameToIndex.put(\"test.Class4\", 4);", // - " classNameToIndex.put(\"test.Class5\", 5);", // - " }", // - "", // - " @Override", // - " public Factory getFactory(Class clazz) {", // - " Factory factory = getFromThisRegistry(clazz);", // - " if (factory == null) {", // - " return getFactoryInChildrenRegistries(clazz);", // - " }", // - " return factory;", // - " }", // - "", // - " private Factory getFromThisRegistry(Class clazz) {", // - " Integer index = classNameToIndex.get(clazz.getName());", // - " if (index == null) {", // - " return null;", // - " }", // - " int groupIndex = index / 3;", // - " switch(groupIndex) {", // - " case 0: return getFromGroup0(index);", // - " case 1: return getFromGroup1(index);", // - " }", // - " return null;", // - " }", // - "", // - " private Factory getFromGroup0(int index) {", // - " switch(index) {", // - " case 0: return (Factory) new test.Class0$$Factory();", // - " case 1: return (Factory) new test.Class1$$Factory();", // - " case 2: return (Factory) new test.Class2$$Factory();", // - " }", // - " return null;", // - " }", // - "", // - " private Factory getFromGroup1(int index) {", // - " switch(index) {", // - " case 3: return (Factory) new test.Class3$$Factory();", // - " case 4: return (Factory) new test.Class4$$Factory();", // - " case 5: return (Factory) new test.Class5$$Factory();", // - " }", // - " return null;", // - " }", // - "}" - )); - - assert_().about(javaSources()) - .that(sources) - .processedWith(defaultFactoryProcessor()) - .compilesWithoutError() - .and() - .generatesSources(expectedSource); - } - - @Test - public void testRegistry_withDependencies() { - JavaFileObject source = injectableClass("Class0"); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("toothpick/FactoryRegistry", Joiner.on('\n').join(// - "package toothpick;", // - "", // - "import java.lang.Class;", // - "import java.lang.Integer;", // - "import java.lang.Override;", // - "import java.lang.String;", // - "import java.util.HashMap;", // - "import java.util.Map;", // - "import toothpick.registries.factory.AbstractFactoryRegistry;", // - "", // - "public final class FactoryRegistry extends AbstractFactoryRegistry {", // - " private final Map classNameToIndex = new HashMap<>();", // - "", // - " public FactoryRegistry() {", // - " addChildRegistry(new toothpick.FactoryRegistry());", // - " addChildRegistry(new toothpick.FactoryRegistry());", // - " registerGroup0();", // - " }", // - "", // - " private void registerGroup0() {", // - " classNameToIndex.put(\"test.Class0\", 0);", // - " }", // - "", // - " @Override", // - " public Factory getFactory(Class clazz) {", // - " Factory factory = getFromThisRegistry(clazz);", // - " if (factory == null) {", // - " return getFactoryInChildrenRegistries(clazz);", // - " }", // - " return factory;", // - " }", // - "", // - " private Factory getFromThisRegistry(Class clazz) {", // - " Integer index = classNameToIndex.get(clazz.getName());", // - " if (index == null) {", // - " return null;", // - " }", // - " int groupIndex = index / 3;", // - " switch(groupIndex) {", // - " case 0: return getFromGroup0(index);", // - " }", // - " return null;", // - " }", // - "", // - " private Factory getFromGroup0(int index) {", // - " switch(index) {", // - " case 0: return (Factory) new test.Class0$$Factory();", // - " }", // - " return null;", // - " }", // - "}")); - - assert_().about(javaSource()) - .that(source) - .processedWith(ProcessorTestUtilities.factoryProcessors("toothpick", Arrays.asList("toothpick", "toothpick"))) - .compilesWithoutError() - .and() - .generatesSources(expectedSource); - } - - - private Iterable injectableClasses(String... names) { - List list = new ArrayList<>(); - for (String name : names) { - list.add(injectableClass(name)); - } - return list; - } - - - private JavaFileObject injectableClass(String name) { - return JavaFileObjects.forSourceString("test." + name, Joiner.on('\n').join(// - "package test;", // - "import javax.inject.Inject;", // - "public class " + name + " {", // - " @Inject public " + name + "() {}", // - "}" // - )); - } - - private Iterable defaultFactoryProcessor() { - return ProcessorTestUtilities.factoryProcessors("toothpick", Collections.EMPTY_LIST); - } -} diff --git a/toothpick-compiler/src/test/java/toothpick/compiler/factory/FactoryTest.java b/toothpick-compiler/src/test/java/toothpick/compiler/factory/FactoryTest.java index a57408e7..669e7002 100644 --- a/toothpick-compiler/src/test/java/toothpick/compiler/factory/FactoryTest.java +++ b/toothpick-compiler/src/test/java/toothpick/compiler/factory/FactoryTest.java @@ -19,13 +19,13 @@ public void testEmptyConstructor_shouldWork_whenConstructorIsPublic() { "}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestEmptyConstructor$$Factory", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestEmptyConstructor__Factory", Joiner.on('\n').join(// "package test;", // "import java.lang.Override;", // "import toothpick.Factory;", // "import toothpick.Scope;", // "", // - "public final class TestEmptyConstructor$$Factory implements Factory {", // + "public final class TestEmptyConstructor__Factory implements Factory {", // " @Override", // " public TestEmptyConstructor createInstance(Scope scope) {", // " TestEmptyConstructor testEmptyConstructor = new TestEmptyConstructor();", // @@ -64,13 +64,13 @@ public void testEmptyConstructor_shouldWork_whenConstructorIsPackage() { "}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestEmptyConstructor$$Factory", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestEmptyConstructor__Factory", Joiner.on('\n').join(// "package test;", // "import java.lang.Override;", // "import toothpick.Factory;", // "import toothpick.Scope;", // "", // - "public final class TestEmptyConstructor$$Factory implements Factory {", // + "public final class TestEmptyConstructor__Factory implements Factory {", // " @Override", // " public TestEmptyConstructor createInstance(Scope scope) {", // " TestEmptyConstructor testEmptyConstructor = new TestEmptyConstructor();", // @@ -109,13 +109,13 @@ public void testEmptyConstructor_shouldWork_whenConstructorIsProtected() { "}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestEmptyConstructor$$Factory", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestEmptyConstructor__Factory", Joiner.on('\n').join(// "package test;", // "import java.lang.Override;", // "import toothpick.Factory;", // "import toothpick.Scope;", // "", // - "public final class TestEmptyConstructor$$Factory implements Factory {", // + "public final class TestEmptyConstructor__Factory implements Factory {", // " @Override", // " public TestEmptyConstructor createInstance(Scope scope) {", // " TestEmptyConstructor testEmptyConstructor = new TestEmptyConstructor();", // @@ -192,13 +192,13 @@ public void testInjectedConstructorInProtectedClass_shouldWork() { "}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/Wrapper$TestConstructorInProtectedClass$$Factory", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/Wrapper$TestConstructorInProtectedClass__Factory", Joiner.on('\n').join(// "package test;", // "import java.lang.Override;", // "import toothpick.Factory;", // "import toothpick.Scope;", // "", // - "public final class Wrapper$TestConstructorInProtectedClass$$Factory implements Factory {", // + "public final class Wrapper$TestConstructorInProtectedClass__Factory implements Factory {", // " @Override", // " public Wrapper.TestConstructorInProtectedClass createInstance(Scope scope) {", // " Wrapper.TestConstructorInProtectedClass testConstructorInProtectedClass = new Wrapper.TestConstructorInProtectedClass();", // @@ -237,13 +237,13 @@ public void testInjectedConstructorInPackageClass_shouldWork() { "}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestConstructorInPackageClass$$Factory", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestConstructorInPackageClass__Factory", Joiner.on('\n').join(// "package test;", // "import java.lang.Override;", // "import toothpick.Factory;", // "import toothpick.Scope;", // "", // - "public final class TestConstructorInPackageClass$$Factory implements Factory {", // + "public final class TestConstructorInPackageClass__Factory implements Factory {", // " @Override", // " public TestConstructorInPackageClass createInstance(Scope scope) {", // " TestConstructorInPackageClass testConstructorInPackageClass = new TestConstructorInPackageClass();", // @@ -301,13 +301,13 @@ public void test2Constructors_butOnlyOneIsInjected() { "}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/Test2Constructors$$Factory", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/Test2Constructors__Factory", Joiner.on('\n').join(// "package test;", // "import java.lang.Override;", // "import toothpick.Factory;", // "import toothpick.Scope;", // "", // - "public final class Test2Constructors$$Factory implements Factory {", // + "public final class Test2Constructors__Factory implements Factory {", // " @Override", // " public Test2Constructors createInstance(Scope scope) {", // " Test2Constructors test2Constructors = new Test2Constructors();", // @@ -347,15 +347,15 @@ public void testAClassThatNeedsInjection_shouldHaveAFactoryThatInjectsIt_whenItH "}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestAClassThatNeedsInjection$$Factory", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestAClassThatNeedsInjection__Factory", Joiner.on('\n').join(// "package test;", // "import java.lang.Override;", // "import toothpick.Factory;", // "import toothpick.MemberInjector;", // "import toothpick.Scope;", // "", // - "public final class TestAClassThatNeedsInjection$$Factory implements Factory {", // - " private MemberInjector memberInjector = new test.TestAClassThatNeedsInjection$$MemberInjector();", // + "public final class TestAClassThatNeedsInjection__Factory implements Factory {", // + " private MemberInjector memberInjector = new test.TestAClassThatNeedsInjection__MemberInjector();", // " @Override", // " public TestAClassThatNeedsInjection createInstance(Scope scope) {", // " scope = getTargetScope(scope);", // @@ -399,15 +399,15 @@ public void testAInnerClassThatNeedsInjection_shouldHaveAFactoryThatInjectsIt_wh "}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestAInnerClassThatNeedsInjection$InnerClass$$Factory", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestAInnerClassThatNeedsInjection$InnerClass__Factory", Joiner.on('\n').join(// "package test;", // "import java.lang.Override;", // "import toothpick.Factory;", // "import toothpick.MemberInjector;", // "import toothpick.Scope;", // "", // - "public final class TestAInnerClassThatNeedsInjection$InnerClass$$Factory implements Factory {", // - " private MemberInjector memberInjector = new test.TestAInnerClassThatNeedsInjection$InnerClass$$MemberInjector();", // + "public final class TestAInnerClassThatNeedsInjection$InnerClass__Factory implements Factory {", // + " private MemberInjector memberInjector = new test.TestAInnerClassThatNeedsInjection$InnerClass__MemberInjector();", // " @Override", // " public TestAInnerClassThatNeedsInjection.InnerClass createInstance(Scope scope) {", // " scope = getTargetScope(scope);", // @@ -452,15 +452,15 @@ public void testAClassThatInheritFromAnotherClassThatNeedsInjection_shouldHaveAF "}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestAClassThatNeedsInjection$$Factory", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestAClassThatNeedsInjection__Factory", Joiner.on('\n').join(// "package test;", // "import java.lang.Override;", // "import toothpick.Factory;", // "import toothpick.MemberInjector;", // "import toothpick.Scope;", // "", // - "public final class TestAClassThatNeedsInjection$$Factory implements Factory {", // - " private MemberInjector memberInjector = new test.SuperClassThatNeedsInjection$$MemberInjector();", // + "public final class TestAClassThatNeedsInjection__Factory implements Factory {", // + " private MemberInjector memberInjector = new test.SuperClassThatNeedsInjection__MemberInjector();", // " @Override", // " public TestAClassThatNeedsInjection createInstance(Scope scope) {", // " scope = getTargetScope(scope);", // @@ -502,15 +502,15 @@ public void testAClassThatNeedsInjection_shouldHaveAFactoryThatInjectsIt_whenItH "}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestAClassThatNeedsInjection$$Factory", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestAClassThatNeedsInjection__Factory", Joiner.on('\n').join(// "package test;", // "import java.lang.Override;", // "import toothpick.Factory;", // "import toothpick.MemberInjector;", // "import toothpick.Scope;", // "", // - "public final class TestAClassThatNeedsInjection$$Factory implements Factory {", // - " private MemberInjector memberInjector = new test.TestAClassThatNeedsInjection$$MemberInjector();", // + "public final class TestAClassThatNeedsInjection__Factory implements Factory {", // + " private MemberInjector memberInjector = new test.TestAClassThatNeedsInjection__MemberInjector();", // " @Override", // " public TestAClassThatNeedsInjection createInstance(Scope scope) {", // @@ -552,7 +552,7 @@ public void testNonEmptyConstructor() { "}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestNonEmptyConstructor$$Factory", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestNonEmptyConstructor__Factory", Joiner.on('\n').join(// "package test;", // "import java.lang.Integer;", // "import java.lang.Override;", // @@ -560,7 +560,7 @@ public void testNonEmptyConstructor() { "import toothpick.Factory;", // "import toothpick.Scope;", // "", // - "public final class TestNonEmptyConstructor$$Factory implements Factory {", // + "public final class TestNonEmptyConstructor__Factory implements Factory {", // " @Override", // " public TestNonEmptyConstructor createInstance(Scope scope) {", // " scope = getTargetScope(scope);", // @@ -603,7 +603,7 @@ public void testNonEmptyConstructorWithLazy() { "}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestNonEmptyConstructor$$Factory", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestNonEmptyConstructor__Factory", Joiner.on('\n').join(// "package test;", // "import java.lang.Integer;", // "import java.lang.Override;", // @@ -612,7 +612,7 @@ public void testNonEmptyConstructorWithLazy() { "import toothpick.Lazy;", // "import toothpick.Scope;", // "", // - "public final class TestNonEmptyConstructor$$Factory implements Factory {", // + "public final class TestNonEmptyConstructor__Factory implements Factory {", // " @Override", // " public TestNonEmptyConstructor createInstance(Scope scope) {", // " scope = getTargetScope(scope);", // @@ -655,7 +655,7 @@ public void testNonEmptyConstructorWithProvider() { "}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestNonEmptyConstructor$$Factory", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestNonEmptyConstructor__Factory", Joiner.on('\n').join(// "package test;", // "import java.lang.Integer;", // "import java.lang.Override;", // @@ -664,7 +664,7 @@ public void testNonEmptyConstructorWithProvider() { "import toothpick.Factory;", // "import toothpick.Scope;", // "", // - "public final class TestNonEmptyConstructor$$Factory implements Factory {", // + "public final class TestNonEmptyConstructor__Factory implements Factory {", // " @Override", // " public TestNonEmptyConstructor createInstance(Scope scope) {", // " scope = getTargetScope(scope);", // @@ -743,14 +743,14 @@ public void testNonEmptyConstructorWithGenerics() { "}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestNonEmptyConstructor$$Factory", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestNonEmptyConstructor__Factory", Joiner.on('\n').join(// "package test;", // "import java.lang.Override;", // "import java.util.List;", // "import toothpick.Factory;", // "import toothpick.Scope;", // "", // - "public final class TestNonEmptyConstructor$$Factory implements Factory {", // + "public final class TestNonEmptyConstructor__Factory implements Factory {", // " @Override", // " public TestNonEmptyConstructor createInstance(Scope scope) {", // " scope = getTargetScope(scope);", // @@ -846,14 +846,14 @@ public void testClassWithInjectedConstructorThrowingException() { "}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestClassConstructorThrowingException$$Factory", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestClassConstructorThrowingException__Factory", Joiner.on('\n').join(// "package test;", // "import java.lang.Override;", // "import java.lang.String;", // "import toothpick.Factory;", // "import toothpick.Scope;", // "", // - "public final class TestClassConstructorThrowingException$$Factory implements Factory {", // + "public final class TestClassConstructorThrowingException__Factory implements Factory {", // " @Override", // " public TestClassConstructorThrowingException createInstance(Scope scope) {", // " scope = getTargetScope(scope);", // @@ -899,7 +899,7 @@ public void testAClassWithSingletonAnnotation_shouldHaveAFactoryThatSaysItIsASin "}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestEmptyNonConstructor$$Factory", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestEmptyNonConstructor__Factory", Joiner.on('\n').join(// "package test;", // "import java.lang.Integer;", // "import java.lang.Override;", // @@ -907,7 +907,7 @@ public void testAClassWithSingletonAnnotation_shouldHaveAFactoryThatSaysItIsASin "import toothpick.Factory;", // "import toothpick.Scope;", // "", // - "public final class TestNonEmptyConstructor$$Factory implements Factory {", // + "public final class TestNonEmptyConstructor__Factory implements Factory {", // " @Override", // " public TestNonEmptyConstructor createInstance(Scope scope) {", // " scope = getTargetScope(scope);", // @@ -950,13 +950,13 @@ public void testAClassWithSingletonAnnotationAndNoConstructor_shouldHaveAFactory "}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestEmptyConstructor$$Factory", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestEmptyConstructor__Factory", Joiner.on('\n').join(// "package test;", // "import java.lang.Override;", // "import toothpick.Factory;", // "import toothpick.Scope;", // "", // - "public final class TestEmptyConstructor$$Factory implements Factory {", // + "public final class TestEmptyConstructor__Factory implements Factory {", // " @Override", // " public TestEmptyConstructor createInstance(Scope scope) {", // " TestEmptyConstructor testEmptyConstructor = new TestEmptyConstructor();", // @@ -1003,7 +1003,7 @@ public void testAClassWithEmptyScopedAnnotation_shouldHaveAFactoryThatSaysItIsSc "}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestEmptyNonConstructor$$Factory", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestEmptyNonConstructor__Factory", Joiner.on('\n').join(// "package test;", // "import java.lang.Integer;", // "import java.lang.Override;", // @@ -1011,7 +1011,7 @@ public void testAClassWithEmptyScopedAnnotation_shouldHaveAFactoryThatSaysItIsSc "import toothpick.Factory;", // "import toothpick.Scope;", // "", // - "public final class TestNonEmptyConstructor$$Factory implements Factory {", // + "public final class TestNonEmptyConstructor__Factory implements Factory {", // " @Override", // " public TestNonEmptyConstructor createInstance(Scope scope) {", // " scope = getTargetScope(scope);", // @@ -1059,13 +1059,13 @@ public void testAClassWithEmptyScopedAnnotationAndNoConstructor_shouldHaveAFacto "}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestEmptyConstructor$$Factory", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestEmptyConstructor__Factory", Joiner.on('\n').join(// "package test;", // "import java.lang.Override;", // "import toothpick.Factory;", // "import toothpick.Scope;", // "", // - "public final class TestEmptyConstructor$$Factory implements Factory {", // + "public final class TestEmptyConstructor__Factory implements Factory {", // " @Override", // " public TestEmptyConstructor createInstance(Scope scope) {", // " TestEmptyConstructor testEmptyConstructor = new TestEmptyConstructor();", // @@ -1107,7 +1107,7 @@ public void testAClassWithProvidesSingletonAnnotation_shouldHaveAFactoryThatSays "}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestEmptyNonConstructor$$Factory", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestEmptyNonConstructor__Factory", Joiner.on('\n').join(// "package test;", // "import java.lang.Integer;", // "import java.lang.Override;", // @@ -1115,7 +1115,7 @@ public void testAClassWithProvidesSingletonAnnotation_shouldHaveAFactoryThatSays "import toothpick.Factory;", // "import toothpick.Scope;", // "", // - "public final class TestNonEmptyConstructor$$Factory implements Factory {", // + "public final class TestNonEmptyConstructor__Factory implements Factory {", // " @Override", // " public TestNonEmptyConstructor createInstance(Scope scope) {", // " scope = getTargetScope(scope);", // diff --git a/toothpick-compiler/src/test/java/toothpick/compiler/factory/ProcessorTestUtilities.java b/toothpick-compiler/src/test/java/toothpick/compiler/factory/ProcessorTestUtilities.java index 1df60605..7c3a883d 100644 --- a/toothpick-compiler/src/test/java/toothpick/compiler/factory/ProcessorTestUtilities.java +++ b/toothpick-compiler/src/test/java/toothpick/compiler/factory/ProcessorTestUtilities.java @@ -4,7 +4,6 @@ import javax.annotation.processing.Processor; import java.util.Arrays; -import java.util.List; final class ProcessorTestUtilities { private ProcessorTestUtilities() { @@ -24,19 +23,6 @@ static Iterable factoryAndMemberInjectorProcessors() { return Arrays.asList(new MemberInjectorProcessor(), new FactoryProcessor()); } - static Iterable factoryProcessors(String toothpickRegistryPackageName, List toothpickRegistryChildrenPackageNameList) { - return factoryProcessors(toothpickRegistryPackageName, toothpickRegistryChildrenPackageNameList, "java.*,android.*"); - } - - static Iterable factoryProcessors(String toothpickRegistryPackageName, - List toothpickRegistryChildrenPackageNameList, String toothpickExcludeFilters) { - FactoryProcessor factoryProcessor = new FactoryProcessor(); - factoryProcessor.setToothpickRegistryPackageName(toothpickRegistryPackageName); - factoryProcessor.setToothpickRegistryChildrenPackageNameList(toothpickRegistryChildrenPackageNameList); - factoryProcessor.setToothpickExcludeFilters(toothpickExcludeFilters); - return Arrays.asList(factoryProcessor); - } - static Iterable factoryProcessorsWithAdditionalTypes(String... types) { FactoryProcessor factoryProcessor = new FactoryProcessor(); for (String type : types) { diff --git a/toothpick-compiler/src/test/java/toothpick/compiler/factory/RelaxedFactoryForClassContainingFieldsTest.java b/toothpick-compiler/src/test/java/toothpick/compiler/factory/RelaxedFactoryForClassContainingFieldsTest.java index 0dcfc115..a86819f9 100644 --- a/toothpick-compiler/src/test/java/toothpick/compiler/factory/RelaxedFactoryForClassContainingFieldsTest.java +++ b/toothpick-compiler/src/test/java/toothpick/compiler/factory/RelaxedFactoryForClassContainingFieldsTest.java @@ -19,16 +19,16 @@ public void testRelaxedFactoryCreationForInjectedField() { "}", // " class Foo {}")); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestRelaxedFactoryCreationForInjectField$$Factory", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestRelaxedFactoryCreationForInjectField__Factory", Joiner.on('\n').join(// "package test;", // "import java.lang.Override;", // "import toothpick.Factory;", // "import toothpick.MemberInjector;", // "import toothpick.Scope;", // "", // - "public final class TestRelaxedFactoryCreationForInjectField$$Factory implements Factory {", // + "public final class TestRelaxedFactoryCreationForInjectField__Factory implements Factory {", // " private MemberInjector memberInjector = " - + "new test.TestRelaxedFactoryCreationForInjectField$$MemberInjector();", + + "new test.TestRelaxedFactoryCreationForInjectField__MemberInjector();", // " @Override", // " public TestRelaxedFactoryCreationForInjectField createInstance(Scope scope) {", // diff --git a/toothpick-compiler/src/test/java/toothpick/compiler/factory/RelaxedFactoryForClassContainingMethodsTest.java b/toothpick-compiler/src/test/java/toothpick/compiler/factory/RelaxedFactoryForClassContainingMethodsTest.java index 478a3d66..d4d40e45 100644 --- a/toothpick-compiler/src/test/java/toothpick/compiler/factory/RelaxedFactoryForClassContainingMethodsTest.java +++ b/toothpick-compiler/src/test/java/toothpick/compiler/factory/RelaxedFactoryForClassContainingMethodsTest.java @@ -19,16 +19,16 @@ public void testRelaxedFactoryCreationForInjectedMethod() { "}", // " class Foo {}")); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestRelaxedFactoryCreationForInjectMethod$$Factory", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestRelaxedFactoryCreationForInjectMethod__Factory", Joiner.on('\n').join(// "package test;", // "import java.lang.Override;", // "import toothpick.Factory;", // "import toothpick.MemberInjector;", // "import toothpick.Scope;", // "", // - "public final class TestRelaxedFactoryCreationForInjectMethod$$Factory implements Factory {", // + "public final class TestRelaxedFactoryCreationForInjectMethod__Factory implements Factory {", // " private MemberInjector memberInjector" - + " = new test.TestRelaxedFactoryCreationForInjectMethod$$MemberInjector();", // + + " = new test.TestRelaxedFactoryCreationForInjectMethod__MemberInjector();", // " @Override", // " public TestRelaxedFactoryCreationForInjectMethod createInstance(Scope scope) {", // " scope = getTargetScope(scope);", // diff --git a/toothpick-compiler/src/test/java/toothpick/compiler/factory/RelaxedFactoryForScopeInstancesTest.java b/toothpick-compiler/src/test/java/toothpick/compiler/factory/RelaxedFactoryForScopeInstancesTest.java index 230da61c..c9707b7d 100644 --- a/toothpick-compiler/src/test/java/toothpick/compiler/factory/RelaxedFactoryForScopeInstancesTest.java +++ b/toothpick-compiler/src/test/java/toothpick/compiler/factory/RelaxedFactoryForScopeInstancesTest.java @@ -49,7 +49,7 @@ public void testOptimisticFactoryCreationForHasScopeInstances_shouldWork_whenThe .processedWith(ProcessorTestUtilities.factoryAndMemberInjectorProcessors()) .compilesWithoutError() .and() - .generatesFileNamed(StandardLocation.locationFor("CLASS_OUTPUT"), "test", "TestOptimisticFactoryCreationForHasScopeInstances$$Factory.class"); + .generatesFileNamed(StandardLocation.locationFor("CLASS_OUTPUT"), "test", "TestOptimisticFactoryCreationForHasScopeInstances__Factory.class"); } @Test diff --git a/toothpick-compiler/src/test/java/toothpick/compiler/factory/RelaxedFactoryForSingletonsTest.java b/toothpick-compiler/src/test/java/toothpick/compiler/factory/RelaxedFactoryForSingletonsTest.java index 65b4da5d..b5ad05e6 100644 --- a/toothpick-compiler/src/test/java/toothpick/compiler/factory/RelaxedFactoryForSingletonsTest.java +++ b/toothpick-compiler/src/test/java/toothpick/compiler/factory/RelaxedFactoryForSingletonsTest.java @@ -25,7 +25,7 @@ public void testOptimisticFactoryCreationForSingleton() { .processedWith(ProcessorTestUtilities.factoryAndMemberInjectorProcessors()) .compilesWithoutError() .and() - .generatesFileNamed(StandardLocation.locationFor("CLASS_OUTPUT"), "test", "TestOptimisticFactoryCreationForSingleton$$Factory.class"); + .generatesFileNamed(StandardLocation.locationFor("CLASS_OUTPUT"), "test", "TestOptimisticFactoryCreationForSingleton__Factory.class"); } @Test @@ -48,7 +48,7 @@ public void testOptimisticFactoryCreationForScopeAnnotation() { .processedWith(ProcessorTestUtilities.factoryProcessorsWithAdditionalTypes("test.CustomScope")) .compilesWithoutError() .and() - .generatesFileNamed(StandardLocation.locationFor("CLASS_OUTPUT"), "test", "TestOptimisticFactoryCreationForScopeAnnotation$$Factory.class"); + .generatesFileNamed(StandardLocation.locationFor("CLASS_OUTPUT"), "test", "TestOptimisticFactoryCreationForScopeAnnotation__Factory.class"); } @Test diff --git a/toothpick-compiler/src/test/java/toothpick/compiler/memberinjector/FieldMemberInjectorTest.java b/toothpick-compiler/src/test/java/toothpick/compiler/memberinjector/FieldMemberInjectorTest.java index 1d2350b2..24bcf10a 100644 --- a/toothpick-compiler/src/test/java/toothpick/compiler/memberinjector/FieldMemberInjectorTest.java +++ b/toothpick-compiler/src/test/java/toothpick/compiler/memberinjector/FieldMemberInjectorTest.java @@ -22,14 +22,14 @@ public void testSimpleFieldInjection() { "class Foo {}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestFieldInjection$$MemberInjector", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestFieldInjection__MemberInjector", Joiner.on('\n').join(// "package test;", // "", // "import java.lang.Override;", // "import toothpick.MemberInjector;", // "import toothpick.Scope;", // "", // - "public final class TestFieldInjection$$MemberInjector implements MemberInjector {", // + "public final class TestFieldInjection__MemberInjector implements MemberInjector {", // " @Override", // " public void inject(TestFieldInjection target, Scope scope) {", // " target.foo = scope.getInstance(Foo.class);", // @@ -58,14 +58,14 @@ public void testNamedFieldInjection_whenUsingNamed() { "class Foo {}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestFieldInjection$$MemberInjector", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestFieldInjection__MemberInjector", Joiner.on('\n').join(// "package test;", // "", // "import java.lang.Override;", // "import toothpick.MemberInjector;", // "import toothpick.Scope;", // "", // - "public final class TestFieldInjection$$MemberInjector implements MemberInjector {", // + "public final class TestFieldInjection__MemberInjector implements MemberInjector {", // " @Override", // " public void inject(TestFieldInjection target, Scope scope) {", // " target.foo = scope.getInstance(Foo.class, \"bar\");", // @@ -97,14 +97,14 @@ public void testNamedFieldInjection_whenUsingQualifierAnnotation() { "@interface Bar {}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestFieldInjection$$MemberInjector", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestFieldInjection__MemberInjector", Joiner.on('\n').join(// "package test;", // "", // "import java.lang.Override;", // "import toothpick.MemberInjector;", // "import toothpick.Scope;", // "", // - "public final class TestFieldInjection$$MemberInjector implements MemberInjector {", // + "public final class TestFieldInjection__MemberInjector implements MemberInjector {", // " @Override", // " public void inject(TestFieldInjection target, Scope scope) {", // " target.foo = scope.getInstance(Foo.class, \"test.Bar\");", // @@ -134,14 +134,14 @@ public void testNamedFieldInjection_whenUsingNonQualifierAnnotation() { "@interface Bar {}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestFieldInjection$$MemberInjector", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestFieldInjection__MemberInjector", Joiner.on('\n').join(// "package test;", // "", // "import java.lang.Override;", // "import toothpick.MemberInjector;", // "import toothpick.Scope;", // "", // - "public final class TestFieldInjection$$MemberInjector implements MemberInjector {", // + "public final class TestFieldInjection__MemberInjector implements MemberInjector {", // " @Override", // " public void inject(TestFieldInjection target, Scope scope) {", // " target.foo = scope.getInstance(Foo.class);", // @@ -174,14 +174,14 @@ public void testNamedProviderFieldInjection_whenUsingQualifierAnnotation() { "@interface Bar {}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestFieldInjection$$MemberInjector", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestFieldInjection__MemberInjector", Joiner.on('\n').join(// "package test;", // "", // "import java.lang.Override;", // "import toothpick.MemberInjector;", // "import toothpick.Scope;", // "", // - "public final class TestFieldInjection$$MemberInjector implements MemberInjector {", // + "public final class TestFieldInjection__MemberInjector implements MemberInjector {", // " @Override", // " public void inject(TestFieldInjection target, Scope scope) {", // " target.foo = scope.getProvider(Foo.class, \"test.Bar\");", // @@ -212,14 +212,14 @@ public void testNamedProviderFieldInjection_whenUsingNonQualifierAnnotation() { "@interface Bar {}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestFieldInjection$$MemberInjector", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestFieldInjection__MemberInjector", Joiner.on('\n').join(// "package test;", // "", // "import java.lang.Override;", // "import toothpick.MemberInjector;", // "import toothpick.Scope;", // "", // - "public final class TestFieldInjection$$MemberInjector implements MemberInjector {", // + "public final class TestFieldInjection__MemberInjector implements MemberInjector {", // " @Override", // " public void inject(TestFieldInjection target, Scope scope) {", // " target.foo = scope.getProvider(Foo.class);", // @@ -252,14 +252,14 @@ public void testNamedFieldInjection_shouldWork_whenUsingMoreThan2Annotation_butO "@interface Qurtz {}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestFieldInjection$$MemberInjector", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestFieldInjection__MemberInjector", Joiner.on('\n').join(// "package test;", // "", // "import java.lang.Override;", // "import toothpick.MemberInjector;", // "import toothpick.Scope;", // "", // - "public final class TestFieldInjection$$MemberInjector implements MemberInjector {", // + "public final class TestFieldInjection__MemberInjector implements MemberInjector {", // " @Override", // " public void inject(TestFieldInjection target, Scope scope) {", // " target.foo = scope.getInstance(Foo.class, \"test.Bar\");", // @@ -313,14 +313,14 @@ public void testProviderFieldInjection() { "class Foo {}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestFieldInjection$$MemberInjector", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestFieldInjection__MemberInjector", Joiner.on('\n').join(// "package test;", // "", // "import java.lang.Override;", // "import toothpick.MemberInjector;", // "import toothpick.Scope;", // "", // - "public final class TestFieldInjection$$MemberInjector implements MemberInjector {", // + "public final class TestFieldInjection__MemberInjector implements MemberInjector {", // " @Override", // " public void inject(TestFieldInjection target, Scope scope) {", // " target.foo = scope.getProvider(Foo.class);", // @@ -349,14 +349,14 @@ public void testLazyFieldInjection() { "class Foo {}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestFieldInjection$$MemberInjector", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestFieldInjection__MemberInjector", Joiner.on('\n').join(// "package test;", // "", // "import java.lang.Override;", // "import toothpick.MemberInjector;", // "import toothpick.Scope;", // "", // - "public final class TestFieldInjection$$MemberInjector implements MemberInjector {", // + "public final class TestFieldInjection__MemberInjector implements MemberInjector {", // " @Override", // " public void inject(TestFieldInjection target, Scope scope) {", // " target.foo = scope.getLazy(Foo.class);", // @@ -385,14 +385,14 @@ public void testLazyFieldInjectionOfGenericTypeButNotDeclaringLazyOfGenericType( "class Foo {}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestFieldInjection$$MemberInjector", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestFieldInjection__MemberInjector", Joiner.on('\n').join(// "package test;", // "", // "import java.lang.Override;", // "import toothpick.MemberInjector;", // "import toothpick.Scope;", // "", // - "public final class TestFieldInjection$$MemberInjector implements MemberInjector {", // + "public final class TestFieldInjection__MemberInjector implements MemberInjector {", // " @Override", // " public void inject(TestFieldInjection target, Scope scope) {", // " target.foo = scope.getLazy(Foo.class);", // @@ -421,14 +421,14 @@ public void testFieldInjection_shouldProduceMemberInjector_whenClassHas2Fields() "class Foo {}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestFieldInjection$$MemberInjector", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestFieldInjection__MemberInjector", Joiner.on('\n').join(// "package test;", // "", // "import java.lang.Override;", // "import toothpick.MemberInjector;", // "import toothpick.Scope;", // "", // - "public final class TestFieldInjection$$MemberInjector implements MemberInjector {", // + "public final class TestFieldInjection__MemberInjector implements MemberInjector {", // " @Override", // " public void inject(TestFieldInjection target, Scope scope) {", // " target.foo = scope.getInstance(Foo.class);", // @@ -581,15 +581,15 @@ public void testFieldInjection_shouldInjectAsAnInstanceOfSuperClass_whenSuperCla "class Foo {}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestMemberInjection$InnerClass$$MemberInjector", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestMemberInjection$InnerClass__MemberInjector", Joiner.on('\n').join(// "package test;", // "", // "import java.lang.Override;", // "import toothpick.MemberInjector;", // "import toothpick.Scope;", // "", // - "public final class TestMemberInjection$InnerClass$$MemberInjector implements MemberInjector {", // - " private MemberInjector superMemberInjector " + "= new test.TestMemberInjection$InnerSuperClass$$MemberInjector();", + "public final class TestMemberInjection$InnerClass__MemberInjector implements MemberInjector {", // + " private MemberInjector superMemberInjector " + "= new test.TestMemberInjection$InnerSuperClass__MemberInjector();", // " @Override", // " public void inject(TestMemberInjection.InnerClass target, Scope scope) {", // @@ -621,15 +621,15 @@ public void testMemberInjection_shouldInjectAsAnInstanceOfSuperClass_whenSuperCl "class Foo {}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestMemberInjection$$MemberInjector", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestMemberInjection__MemberInjector", Joiner.on('\n').join(// "package test;", // "", // "import java.lang.Override;", // "import toothpick.MemberInjector;", // "import toothpick.Scope;", // "", // - "public final class TestMemberInjection$$MemberInjector implements MemberInjector {", // - " private MemberInjector superMemberInjector " + "= new test.TestMemberInjectionParent$$MemberInjector();", + "public final class TestMemberInjection__MemberInjector implements MemberInjector {", // + " private MemberInjector superMemberInjector " + "= new test.TestMemberInjectionParent__MemberInjector();", // " @Override", // " public void inject(TestMemberInjection target, Scope scope) {", // diff --git a/toothpick-compiler/src/test/java/toothpick/compiler/memberinjector/MemberInjectorOriginatingElementTest.java b/toothpick-compiler/src/test/java/toothpick/compiler/memberinjector/MemberInjectorOriginatingElementTest.java new file mode 100644 index 00000000..dc3ed353 --- /dev/null +++ b/toothpick-compiler/src/test/java/toothpick/compiler/memberinjector/MemberInjectorOriginatingElementTest.java @@ -0,0 +1,40 @@ +package toothpick.compiler.memberinjector; + +import com.google.common.base.Joiner; +import com.google.testing.compile.JavaFileObjects; +import org.junit.Test; + +import javax.annotation.processing.Processor; +import javax.lang.model.element.TypeElement; +import javax.tools.JavaFileObject; + +import static com.google.common.truth.Truth.assert_; +import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource; +import static org.junit.Assert.assertTrue; + +public class MemberInjectorOriginatingElementTest { + + @Test + public void testOriginatingElement() { + JavaFileObject source = JavaFileObjects.forSourceString("test.TestOriginatingElement", Joiner.on('\n').join(// + "package test;", // + "import javax.inject.Inject;", // + "public class TestOriginatingElement {", // + " @Inject Foo foo;", // + " public TestOriginatingElement() {}", // + "}", // + "class Foo {}" // + )); + + Iterable processors = ProcessorTestUtilities.memberInjectorProcessors(); + + assert_().about(javaSource()) + .that(source) + .processedWith(processors) + .compilesWithoutError(); + + MemberInjectorProcessor memberInjectorProcessor = (MemberInjectorProcessor) processors.iterator().next(); + TypeElement enclosingElement = memberInjectorProcessor.getOriginatingElement("test.TestOriginatingElement__MemberInjector"); + assertTrue(enclosingElement.getQualifiedName().contentEquals("test.TestOriginatingElement")); + } +} diff --git a/toothpick-compiler/src/test/java/toothpick/compiler/memberinjector/MemberInjectorRegistryTest.java b/toothpick-compiler/src/test/java/toothpick/compiler/memberinjector/MemberInjectorRegistryTest.java deleted file mode 100644 index e465b65a..00000000 --- a/toothpick-compiler/src/test/java/toothpick/compiler/memberinjector/MemberInjectorRegistryTest.java +++ /dev/null @@ -1,203 +0,0 @@ -package toothpick.compiler.memberinjector; - -import com.google.common.base.Joiner; -import com.google.testing.compile.JavaFileObjects; - -import org.junit.Test; - -import java.util.Arrays; -import java.util.Collections; - -import javax.annotation.processing.Processor; -import javax.tools.JavaFileObject; - -import static com.google.common.truth.Truth.assert_; -import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource; - -public class MemberInjectorRegistryTest { - - @Test - public void testRegistry_withNoInjectors() { - JavaFileObject source = classWithMemberInjection("Class0"); - - JavaFileObject expectedSource = JavaFileObjects.forSourceString("toothpick/MemberInjectorRegistry", Joiner.on("\n").join( - "package toothpick;", // - "", // - "import java.lang.Class;", // - "import java.lang.Integer;", // - "import java.lang.Override;", // - "import java.lang.String;", // - "import java.util.HashMap;", // - "import java.util.Map;", // - "import toothpick.registries.memberinjector.AbstractMemberInjectorRegistry;", // - "", // - "public final class MemberInjectorRegistry extends AbstractMemberInjectorRegistry {", // - " private final Map classNameToIndex = new HashMap<>();", // - "", // - " public MemberInjectorRegistry() {", // - " }", // - "", // - " @Override", // - " public MemberInjector getMemberInjector(Class clazz) {", // - " MemberInjector factory = getFromThisRegistry(clazz);", // - " if (factory == null) {", // - " return getMemberInjectorInChildrenRegistries(clazz);", // - " }", // - " return factory;", // - " }", // - "", // - " private MemberInjector getFromThisRegistry(Class clazz) {", // - " return null;", // - " }", // - "}")); - - assert_().about(javaSource()) - .that(source) - .processedWith(ProcessorTestUtilities.memberInjectorProcessors("toothpick", Collections.EMPTY_LIST, "java.*,android.*,test.*")) - .compilesWithoutError() - .and() - .generatesSources(expectedSource); - } - - @Test - public void testRegistry_WithOneInjector() { - JavaFileObject source = classWithMemberInjection("Class0"); - - JavaFileObject expectedSource = JavaFileObjects.forSourceString("toothpick/MemberInjectorRegistry", Joiner.on('\n').join( - "package toothpick;", // - "", // - "import java.lang.Class;", // - "import java.lang.Integer;", // - "import java.lang.Override;", // - "import java.lang.String;", // - "import java.util.HashMap;", // - "import java.util.Map;", // - "import toothpick.registries.memberinjector.AbstractMemberInjectorRegistry;", // - "", // - "public final class MemberInjectorRegistry extends AbstractMemberInjectorRegistry {", // - " private final Map classNameToIndex = new HashMap<>();", // - "", // - " public MemberInjectorRegistry() {", // - " registerGroup0();", // - " }", // - "", // - " private void registerGroup0() {", // - " classNameToIndex.put(\"test.Class0\", 0);", // - " }", // - "", // - " @Override", // - " public MemberInjector getMemberInjector(Class clazz) {", // - " MemberInjector factory = getFromThisRegistry(clazz);", // - " if (factory == null) {", // - " return getMemberInjectorInChildrenRegistries(clazz);", // - " }", // - " return factory;", // - " }", // - "", // - " private MemberInjector getFromThisRegistry(Class clazz) {", // - " Integer index = classNameToIndex.get(clazz.getName());", // - " if (index == null) {", // - " return null;", // - " }", // - " int groupIndex = index / 200;", // - " switch(groupIndex) {", // - " case 0: return getFromGroup0(index);", // - " }", // - " return null;", // - " }", // - "", // - " private MemberInjector getFromGroup0(int index) {", // - " switch(index) {", // - " case 0: return (MemberInjector) new test.Class0$$MemberInjector();", // - " }", // - " return null;", // - " }", // - "}" - )); - - assert_().about(javaSource()) - .that(source) - .processedWith(defaultMemberInjectorProcessor()) - .compilesWithoutError() - .and() - .generatesSources(expectedSource); - } - - @Test - public void testRegistry_withDependencies() { - JavaFileObject source = classWithMemberInjection("Class0"); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("toothpick/MemberInjectorRegistry", Joiner.on('\n').join(// - "package toothpick;", // - "", // - "import java.lang.Class;", // - "import java.lang.Integer;", // - "import java.lang.Override;", // - "import java.lang.String;", // - "import java.util.HashMap;", // - "import java.util.Map;", // - "import toothpick.registries.memberinjector.AbstractMemberInjectorRegistry;", // - "", // - "public final class MemberInjectorRegistry extends AbstractMemberInjectorRegistry {", // - " private final Map classNameToIndex = new HashMap<>();", // - "", // - " public MemberInjectorRegistry() {", // - " addChildRegistry(new toothpick.MemberInjectorRegistry());", // - " addChildRegistry(new toothpick.MemberInjectorRegistry());", // - " registerGroup0();", // - " }", // - "", // - " private void registerGroup0() {", // - " classNameToIndex.put(\"test.Class0\", 0);", // - " }", // - "", // - " @Override", // - " public MemberInjector getMemberInjector(Class clazz) {", // - " MemberInjector factory = getFromThisRegistry(clazz);", // - " if (factory == null) {", // - " return getMemberInjectorInChildrenRegistries(clazz);", // - " }", // - " return factory;", // - " }", // - "", // - " private MemberInjector getFromThisRegistry(Class clazz) {", // - " Integer index = classNameToIndex.get(clazz.getName());", // - " if (index == null) {", // - " return null;", // - " }", // - " int groupIndex = index / 200;", // - " switch(groupIndex) {", // - " case 0: return getFromGroup0(index);", // - " }", // - " return null;", // - " }", // - "", // - " private MemberInjector getFromGroup0(int index) {", // - " switch(index) {", // - " case 0: return (MemberInjector) new test.Class0$$MemberInjector();", // - " }", // - " return null;", // - " }", // - "}")); - - assert_().about(javaSource()) - .that(source) - .processedWith(ProcessorTestUtilities.memberInjectorProcessors("toothpick", Arrays.asList("toothpick", "toothpick"))) - .compilesWithoutError() - .and() - .generatesSources(expectedSource); - } - - private JavaFileObject classWithMemberInjection(String name) { - return JavaFileObjects.forSourceString("test." + name, Joiner.on('\n').join(// - "package test;", // - "import javax.inject.Inject;", // - "public class " + name + " {", // - " @Inject String s;", // - "}" // - )); - } - - private Iterable defaultMemberInjectorProcessor() { - return ProcessorTestUtilities.memberInjectorProcessors("toothpick", Collections.EMPTY_LIST); - } -} diff --git a/toothpick-compiler/src/test/java/toothpick/compiler/memberinjector/MethodMemberInjectorTest.java b/toothpick-compiler/src/test/java/toothpick/compiler/memberinjector/MethodMemberInjectorTest.java index a5a1ae76..cf15805f 100644 --- a/toothpick-compiler/src/test/java/toothpick/compiler/memberinjector/MethodMemberInjectorTest.java +++ b/toothpick-compiler/src/test/java/toothpick/compiler/memberinjector/MethodMemberInjectorTest.java @@ -22,14 +22,14 @@ public void testSimpleMethodInjection() { "class Foo {}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestMethodInjection$$MemberInjector", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestMethodInjection__MemberInjector", Joiner.on('\n').join(// "package test;", // "", // "import java.lang.Override;", // "import toothpick.MemberInjector;", // "import toothpick.Scope;", // "", // - "public final class TestMethodInjection$$MemberInjector implements MemberInjector {", // + "public final class TestMethodInjection__MemberInjector implements MemberInjector {", // " @Override", // " public void inject(TestMethodInjection target, Scope scope) {", // " Foo param1 = scope.getInstance(Foo.class);", // @@ -59,7 +59,7 @@ public void testSimpleMethodInjectionWithLazy() { "class Foo {}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestMethodInjection$$MemberInjector", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestMethodInjection__MemberInjector", Joiner.on('\n').join(// "package test;", // "", // "import java.lang.Override;", // @@ -67,7 +67,7 @@ public void testSimpleMethodInjectionWithLazy() { "import toothpick.MemberInjector;", // "import toothpick.Scope;", // "", // - "public final class TestMethodInjection$$MemberInjector implements MemberInjector {", // + "public final class TestMethodInjection__MemberInjector implements MemberInjector {", // " @Override", // " public void inject(TestMethodInjection target, Scope scope) {", // " Lazy param1 = scope.getLazy(Foo.class);", // @@ -97,7 +97,7 @@ public void testSimpleMethodInjectionWithProvider() { "class Foo {}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestMethodInjection$$MemberInjector", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestMethodInjection__MemberInjector", Joiner.on('\n').join(// "package test;", // "", // "import java.lang.Override;", // @@ -105,7 +105,7 @@ public void testSimpleMethodInjectionWithProvider() { "import toothpick.MemberInjector;", // "import toothpick.Scope;", // "", // - "public final class TestMethodInjection$$MemberInjector implements MemberInjector {", // + "public final class TestMethodInjection__MemberInjector implements MemberInjector {", // " @Override", // " public void inject(TestMethodInjection target, Scope scope) {", // " Provider param1 = scope.getProvider(Foo.class);", // @@ -135,7 +135,7 @@ public void testSimpleMethodInjectionWithLazyOfGenericTypeButNotLazyOfGenericTyp "class Foo {}" // )); - JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestMethodInjection$$MemberInjector", Joiner.on('\n').join(// + JavaFileObject expectedSource = JavaFileObjects.forSourceString("test/TestMethodInjection__MemberInjector", Joiner.on('\n').join(// "package test;", // "", // "import java.lang.Override;", // @@ -143,7 +143,7 @@ public void testSimpleMethodInjectionWithLazyOfGenericTypeButNotLazyOfGenericTyp "import toothpick.MemberInjector;", // "import toothpick.Scope;", // "", // - "public final class TestMethodInjection$$MemberInjector implements MemberInjector {", // + "public final class TestMethodInjection__MemberInjector implements MemberInjector {", // " @Override", // " public void inject(TestMethodInjection target, Scope scope) {", // " Lazy param1 = scope.getLazy(Foo.class);", // @@ -277,17 +277,17 @@ public void testOverrideMethodInjection() { )); JavaFileObject expectedSource = - JavaFileObjects.forSourceString("test/TestMethodInjectionParent$TestMethodInjection$$MemberInjector", Joiner.on('\n').join(// + JavaFileObjects.forSourceString("test/TestMethodInjectionParent$TestMethodInjection__MemberInjector", Joiner.on('\n').join(// "package test;", // "", // "import java.lang.Override;", // "import toothpick.MemberInjector;", // "import toothpick.Scope;", // "", // - "public final class TestMethodInjectionParent$TestMethodInjection$$MemberInjector " + "public final class TestMethodInjectionParent$TestMethodInjection__MemberInjector " + "implements MemberInjector {", // - " private MemberInjector superMemberInjector = new test.TestMethodInjectionParent$$MemberInjector();\n", // + " private MemberInjector superMemberInjector = new test.TestMethodInjectionParent__MemberInjector();\n", // " @Override", // " public void inject(TestMethodInjectionParent.TestMethodInjection target, Scope scope) {", // " superMemberInjector.inject(target, scope);", // diff --git a/toothpick-compiler/src/test/java/toothpick/compiler/memberinjector/ProcessorTestUtilities.java b/toothpick-compiler/src/test/java/toothpick/compiler/memberinjector/ProcessorTestUtilities.java index b7aedda6..d74673bc 100644 --- a/toothpick-compiler/src/test/java/toothpick/compiler/memberinjector/ProcessorTestUtilities.java +++ b/toothpick-compiler/src/test/java/toothpick/compiler/memberinjector/ProcessorTestUtilities.java @@ -1,8 +1,7 @@ package toothpick.compiler.memberinjector; -import java.util.Arrays; -import java.util.List; import javax.annotation.processing.Processor; +import java.util.Arrays; final class ProcessorTestUtilities { private ProcessorTestUtilities() { @@ -17,18 +16,4 @@ static Iterable memberInjectorProcessorsFailingWhenMethodIs memberInjectorProcessor.setCrashOrWarnWhenMethodIsNotPackageVisible(true); return Arrays.asList(memberInjectorProcessor); } - - static Iterable memberInjectorProcessors(String toothpickRegistryPackageName, - List toothpickRegistryChildrenPackageNameList) { - return memberInjectorProcessors(toothpickRegistryPackageName, toothpickRegistryChildrenPackageNameList, "java.*,android.*"); - } - - static Iterable memberInjectorProcessors(String toothpickRegistryPackageName, - List toothpickRegistryChildrenPackageNameList, String toothpickExcludeFilters) { - MemberInjectorProcessor memberInjectorProcessor = new MemberInjectorProcessor(); - memberInjectorProcessor.setToothpickRegistryPackageName(toothpickRegistryPackageName); - memberInjectorProcessor.setToothpickRegistryChildrenPackageNameList(toothpickRegistryChildrenPackageNameList); - memberInjectorProcessor.setToothpickExcludeFilters(toothpickExcludeFilters); - return Arrays.asList(memberInjectorProcessor); - } } diff --git a/toothpick-compiler/src/test/java/toothpick/compiler/registry/generators/RegistryGeneratorGroupSizeRule.java b/toothpick-compiler/src/test/java/toothpick/compiler/registry/generators/RegistryGeneratorGroupSizeRule.java deleted file mode 100644 index 891cd6f4..00000000 --- a/toothpick-compiler/src/test/java/toothpick/compiler/registry/generators/RegistryGeneratorGroupSizeRule.java +++ /dev/null @@ -1,32 +0,0 @@ -package toothpick.compiler.registry.generators; - -import org.junit.rules.TestRule; -import org.junit.runner.Description; -import org.junit.runners.model.Statement; - -public final class RegistryGeneratorGroupSizeRule implements TestRule { - - private final int groupSizeForTests; - - public RegistryGeneratorGroupSizeRule(int groupSizeForTests) { - this.groupSizeForTests = groupSizeForTests; - } - - @Override - public Statement apply(final Statement base, Description description) { - final int defaultGroupSize = RegistryGenerator.groupSize; - - return new Statement() { - @Override - public void evaluate() throws Throwable { - try { - RegistryGenerator.groupSize = groupSizeForTests; - base.evaluate(); - } finally { - RegistryGenerator.groupSize = defaultGroupSize; - } - } - }; - } - -} diff --git a/toothpick-generated-core/build.gradle b/toothpick-generated-core/build.gradle deleted file mode 100644 index 2cbd580e..00000000 --- a/toothpick-generated-core/build.gradle +++ /dev/null @@ -1,12 +0,0 @@ -apply plugin: 'java-library' - -sourceCompatibility = 1.7 -targetCompatibility = 1.7 - -dependencies { - api project(':toothpick') - - testImplementation deps.junit -} - -apply from: rootProject.file('gradle/gradle-mvn-push.gradle') \ No newline at end of file diff --git a/toothpick-generated-core/gradle.properties b/toothpick-generated-core/gradle.properties deleted file mode 100644 index dce5d884..00000000 --- a/toothpick-generated-core/gradle.properties +++ /dev/null @@ -1,3 +0,0 @@ -POM_ARTIFACT_ID=toothpick-generated-core -POM_NAME=Toothpick Generated Core -POM_DESCRIPTION='Contains base classes of code generated by the compiler. Prevents a cycle between compiler and runtime.' \ No newline at end of file diff --git a/toothpick-generated-core/src/main/java/toothpick/registries/factory/AbstractFactoryRegistry.java b/toothpick-generated-core/src/main/java/toothpick/registries/factory/AbstractFactoryRegistry.java deleted file mode 100644 index 82d98197..00000000 --- a/toothpick-generated-core/src/main/java/toothpick/registries/factory/AbstractFactoryRegistry.java +++ /dev/null @@ -1,42 +0,0 @@ -package toothpick.registries.factory; - -import java.util.ArrayList; -import java.util.List; -import toothpick.registries.FactoryRegistry; -import toothpick.Factory; - -/** - * The base class of the {@link FactoryRegistry} classes generated by the toothpick annotation processor. - * Those {@link FactoryRegistry} can form a tree of {@link FactoryRegistry} and have the ability to run through the tree - * of their children {@link FactoryRegistry} to find a {@link Factory}. - * - * This class is meant to be used internally by toothpick. - */ -public abstract class AbstractFactoryRegistry implements FactoryRegistry { - - private List childrenRegistries = new ArrayList<>(); - - public void addChildRegistry(FactoryRegistry childRegistry) { - this.childrenRegistries.add(childRegistry); - } - - /** - * Explore the subtree of children registries via DFS to retrieve a {@link Factory} for a given class. - * This method will be called automatically by all factories generated by toothpick, if it is provided - * appropriate parameters when compiling each library. - * - * @param clazz the class to look the {@link Factory} for. - * @param the type of {@code clazz}. - * @return an instance of the {@link Factory} class asssociated with {@code clazz} or null if it can't find one. - */ - protected Factory getFactoryInChildrenRegistries(Class clazz) { - Factory factory; - for (FactoryRegistry registry : childrenRegistries) { - factory = registry.getFactory(clazz); - if (factory != null) { - return factory; - } - } - return null; - } -} diff --git a/toothpick-generated-core/src/main/java/toothpick/registries/memberinjector/AbstractMemberInjectorRegistry.java b/toothpick-generated-core/src/main/java/toothpick/registries/memberinjector/AbstractMemberInjectorRegistry.java deleted file mode 100644 index 9d8d3180..00000000 --- a/toothpick-generated-core/src/main/java/toothpick/registries/memberinjector/AbstractMemberInjectorRegistry.java +++ /dev/null @@ -1,42 +0,0 @@ -package toothpick.registries.memberinjector; - -import java.util.ArrayList; -import java.util.List; -import toothpick.MemberInjector; -import toothpick.registries.MemberInjectorRegistry; - -/** - * The base class of the {@link MemberInjectorRegistry} classes generated by the toothpick annotation processor. - * Those {@link MemberInjectorRegistry} can form a tree of {@link MemberInjectorRegistry} and have the ability to run through the tree - * of their children {@link MemberInjectorRegistry} to find a {@link MemberInjector}. - * - * This class is meant to be used internally by toothpick. - */ -public abstract class AbstractMemberInjectorRegistry implements MemberInjectorRegistry { - - private List childrenRegistries = new ArrayList<>(); - - public void addChildRegistry(MemberInjectorRegistry childRegistry) { - this.childrenRegistries.add(childRegistry); - } - - /** - * Explore the subtree of children registries via DFS to retrieve a {@link MemberInjector} for a given class. - * This method will be called automatically by all member scopes generated by toothpick, if it is provided - * appropriate parameters when compiling each library. - * - * @param clazz the class to look the {@link MemberInjector} for. - * @param the type of {@code clazz}. - * @return an instance of the {@link MemberInjector} class asssociated with {@code clazz} or null if it can't find one. - */ - protected MemberInjector getMemberInjectorInChildrenRegistries(Class clazz) { - MemberInjector memberInjector; - for (MemberInjectorRegistry registry : childrenRegistries) { - memberInjector = registry.getMemberInjector(clazz); - if (memberInjector != null) { - return memberInjector; - } - } - return null; - } -} diff --git a/toothpick-javax-annotations/gradle.properties b/toothpick-javax-annotations/gradle.properties index 06d93798..627b5e43 100644 --- a/toothpick-javax-annotations/gradle.properties +++ b/toothpick-javax-annotations/gradle.properties @@ -1,4 +1,4 @@ POM_ARTIFACT_ID=toothpick-javax-annotations POM_NAME=Toothpick Javax Annotations POM_DESCRIPTION='Javax annotations with class retention' -POM_PACKAGING='jar' \ No newline at end of file +POM_PACKAGING='jar' diff --git a/toothpick-runtime/build.gradle b/toothpick-runtime/build.gradle index ddacb51e..d47b2bd1 100644 --- a/toothpick-runtime/build.gradle +++ b/toothpick-runtime/build.gradle @@ -1,5 +1,3 @@ -import org.gradle.internal.jvm.Jvm - apply plugin: 'java-library' sourceCompatibility = 1.7 @@ -10,22 +8,23 @@ configurations { } dependencies { - api project(':toothpick-generated-core') + api project(':toothpick') api deps.inject - testImplementation deps.junit - testImplementation project(':toothpick-generated-core') + testImplementation deps.junit4 testImplementation deps.easymock testImplementation deps.powermock testImplementation deps.hamcrest - testImplementation files(Jvm.current().getToolsJar()) + testImplementation deps.powermock_rule testAnnotationProcessor project(':toothpick-compiler') } +test { + jvmArgs '-noverify' +} + compileTestJava { - options.annotationProcessorPath = configurations.testAnnotationProcessor - options.compilerArgs = ['-Atoothpick_registry_package_name=toothpick.test', - '-Atoothpick_annotations=toothpick.data.CustomScope',] + options.compilerArgs = ['-Atoothpick_annotations=toothpick.data.CustomScope',] } -apply from: rootProject.file('gradle/gradle-mvn-push.gradle') \ No newline at end of file +apply from: rootProject.file('gradle/gradle-mvn-push.gradle') diff --git a/toothpick-runtime/src/main/java/toothpick/InjectorImpl.java b/toothpick-runtime/src/main/java/toothpick/InjectorImpl.java index 15524d67..4affff56 100644 --- a/toothpick-runtime/src/main/java/toothpick/InjectorImpl.java +++ b/toothpick-runtime/src/main/java/toothpick/InjectorImpl.java @@ -1,6 +1,6 @@ package toothpick; -import toothpick.registries.MemberInjectorRegistryLocator; +import toothpick.locators.MemberInjectorLocator; /** * Default implementation of an injector. @@ -10,17 +10,15 @@ public final class InjectorImpl implements Injector { * {@inheritDoc} * *

- * ⚠ Warning ⚠ : This implementation needs a proper setup of {@link toothpick.registries.MemberInjectorRegistry} instances - * at the annotation processor level. We will bubble up the hierarchy, starting at class {@code T}. As soon - * as a {@link MemberInjector} is found, we use it to inject the members of {@code obj}. If registries are not find then - * you will observe strange behaviors at runtime : only members defined in super class will be injected. + * We will bubble up the hierarchy, starting at class {@code T}. As soon as a {@link MemberInjector} is found, + * we use it to inject the members of {@code obj}. *

*/ @Override public void inject(T obj, Scope scope) { Class currentClass = (Class) obj.getClass(); do { - MemberInjector memberInjector = MemberInjectorRegistryLocator.getMemberInjector(currentClass); + MemberInjector memberInjector = MemberInjectorLocator.getMemberInjector(currentClass); if (memberInjector != null) { memberInjector.inject(obj, scope); return; diff --git a/toothpick-runtime/src/main/java/toothpick/InternalProviderImpl.java b/toothpick-runtime/src/main/java/toothpick/InternalProviderImpl.java index 63a2a654..82030556 100644 --- a/toothpick-runtime/src/main/java/toothpick/InternalProviderImpl.java +++ b/toothpick-runtime/src/main/java/toothpick/InternalProviderImpl.java @@ -1,7 +1,7 @@ package toothpick; import javax.inject.Provider; -import toothpick.registries.FactoryRegistryLocator; +import toothpick.locators.FactoryLocator; /** * A non thread safe internal provider. It should never be exposed outside of Toothpick. @@ -84,7 +84,7 @@ public synchronized T get(Scope scope) { } if (factoryClass != null && factory == null) { - factory = FactoryRegistryLocator.getFactory(factoryClass); + factory = FactoryLocator.getFactory(factoryClass); //gc factoryClass = null; } @@ -100,7 +100,7 @@ public synchronized T get(Scope scope) { } if (providerFactoryClass != null && providerFactory == null) { - providerFactory = FactoryRegistryLocator.getFactory(providerFactoryClass); + providerFactory = FactoryLocator.getFactory(providerFactoryClass); //gc providerFactoryClass = null; } diff --git a/toothpick-runtime/src/main/java/toothpick/ScopeImpl.java b/toothpick-runtime/src/main/java/toothpick/ScopeImpl.java index 735ef074..07b7353b 100644 --- a/toothpick-runtime/src/main/java/toothpick/ScopeImpl.java +++ b/toothpick-runtime/src/main/java/toothpick/ScopeImpl.java @@ -4,7 +4,7 @@ import toothpick.config.Module; import toothpick.configuration.ConfigurationHolder; import toothpick.configuration.IllegalBindingException; -import toothpick.registries.FactoryRegistryLocator; +import toothpick.locators.FactoryLocator; import javax.inject.Provider; import java.util.ArrayList; @@ -326,7 +326,7 @@ private InternalProviderImpl createInternalProvider(Scope scope, Class //they will be a bit slower as we need to get the factory first //we need to know whether they are scoped or not, if so we scope them //if not, they are place in the pool - Factory factory = FactoryRegistryLocator.getFactory(clazz); + Factory factory = FactoryLocator.getFactory(clazz); if (factory.hasScopeAnnotation()) { //the new provider will have to work in the current scope diff --git a/toothpick-runtime/src/main/java/toothpick/configuration/Configuration.java b/toothpick-runtime/src/main/java/toothpick/configuration/Configuration.java index bf7bef9c..a4076f67 100644 --- a/toothpick-runtime/src/main/java/toothpick/configuration/Configuration.java +++ b/toothpick-runtime/src/main/java/toothpick/configuration/Configuration.java @@ -1,20 +1,16 @@ package toothpick.configuration; -import toothpick.Factory; -import toothpick.MemberInjector; import toothpick.Scope; import toothpick.config.Binding; /** * Strategy pattern that allows to change various behaviors of Toothpick. - * The default configuration is {@link #forProduction()} and {@link #enableReflection()}. + * The default configuration is {@link #forProduction()}. * A custom configuration can be created and used by toothpick, * it is even possible to use a composition of the built-in configurations. */ -public class Configuration implements RuntimeCheckConfiguration, ReflectionConfiguration, - MultipleRootScopeCheckConfiguration { +public class Configuration implements RuntimeCheckConfiguration, MultipleRootScopeCheckConfiguration { - private ReflectionConfiguration reflectionConfiguration = new ReflectionOnConfiguration(); private RuntimeCheckConfiguration runtimeCheckConfiguration = new RuntimeCheckOffConfiguration(); private MultipleRootScopeCheckConfiguration multipleRootScopeCheckConfiguration = new MultipleRootScopeCheckOffConfiguration(); @@ -51,32 +47,6 @@ public static Configuration forProduction() { return new Configuration(); } - /** - * Set enableReflection mode. - * It is slower than {@link #disableReflection()} but it does not - * need any additional setup of the annotation processors. - * It can be used in production or development. - * - * @return a configuration set up to use reflection. - */ - public Configuration enableReflection() { - this.reflectionConfiguration = new ReflectionOnConfiguration(); - return this; - } - - /** - * Set reflection free mode. - * It is faster than {@link #enableReflection()} but it needs - * some additional setup of the annotation processors. - * It can be used in production or development. - * - * @return an optimized reflection free configuration. - */ - public Configuration disableReflection() { - this.reflectionConfiguration = new ReflectionOffConfiguration(); - return this; - } - /** * Allows multiple root scopes in the scope forest. * @return a configuration that allows multiple root scopes. @@ -109,14 +79,6 @@ public Configuration preventMultipleRootScopes() { runtimeCheckConfiguration.checkCyclesEnd(clazz, name); } - @Override public Factory getFactory(Class clazz) { - return reflectionConfiguration.getFactory(clazz); - } - - @Override public MemberInjector getMemberInjector(Class clazz) { - return reflectionConfiguration.getMemberInjector(clazz); - } - @Override public void checkMultipleRootScopes(Scope scope) { multipleRootScopeCheckConfiguration.checkMultipleRootScopes(scope); } diff --git a/toothpick-runtime/src/main/java/toothpick/configuration/ReflectionConfiguration.java b/toothpick-runtime/src/main/java/toothpick/configuration/ReflectionConfiguration.java deleted file mode 100644 index efcb7639..00000000 --- a/toothpick-runtime/src/main/java/toothpick/configuration/ReflectionConfiguration.java +++ /dev/null @@ -1,9 +0,0 @@ -package toothpick.configuration; - -import toothpick.Factory; -import toothpick.MemberInjector; - -interface ReflectionConfiguration { - Factory getFactory(Class clazz); - MemberInjector getMemberInjector(Class clazz); -} diff --git a/toothpick-runtime/src/main/java/toothpick/configuration/ReflectionOffConfiguration.java b/toothpick-runtime/src/main/java/toothpick/configuration/ReflectionOffConfiguration.java deleted file mode 100644 index cc109448..00000000 --- a/toothpick-runtime/src/main/java/toothpick/configuration/ReflectionOffConfiguration.java +++ /dev/null @@ -1,18 +0,0 @@ -package toothpick.configuration; - -import toothpick.Factory; -import toothpick.MemberInjector; -import toothpick.registries.FactoryRegistryLocator; -import toothpick.registries.MemberInjectorRegistryLocator; - -class ReflectionOffConfiguration implements ReflectionConfiguration { - @Override - public Factory getFactory(Class clazz) { - return FactoryRegistryLocator.getFactoryUsingRegistries(clazz); - } - - @Override - public MemberInjector getMemberInjector(Class clazz) { - return MemberInjectorRegistryLocator.getMemberInjectorUsingRegistries(clazz); - } -} diff --git a/toothpick-runtime/src/main/java/toothpick/configuration/ReflectionOnConfiguration.java b/toothpick-runtime/src/main/java/toothpick/configuration/ReflectionOnConfiguration.java deleted file mode 100644 index e7e21b55..00000000 --- a/toothpick-runtime/src/main/java/toothpick/configuration/ReflectionOnConfiguration.java +++ /dev/null @@ -1,18 +0,0 @@ -package toothpick.configuration; - -import toothpick.Factory; -import toothpick.MemberInjector; -import toothpick.registries.FactoryRegistryLocator; -import toothpick.registries.MemberInjectorRegistryLocator; - -class ReflectionOnConfiguration implements ReflectionConfiguration { - @Override - public Factory getFactory(Class clazz) { - return FactoryRegistryLocator.getFactoryUsingReflection(clazz); - } - - @Override - public MemberInjector getMemberInjector(Class clazz) { - return MemberInjectorRegistryLocator.getMemberInjectorUsingReflection(clazz); - } -} diff --git a/toothpick-runtime/src/main/java/toothpick/locators/FactoryLocator.java b/toothpick-runtime/src/main/java/toothpick/locators/FactoryLocator.java new file mode 100644 index 00000000..b0928f85 --- /dev/null +++ b/toothpick-runtime/src/main/java/toothpick/locators/FactoryLocator.java @@ -0,0 +1,24 @@ +package toothpick.locators; + +import toothpick.Factory; + +/** + * The locator retrieves a {@link Factory} for a given class. + * In case no generated factory for a given class, we throw a {@link NoFactoryFoundException}. + * + * @see Factory + */ +public class FactoryLocator { + private FactoryLocator() { + } + + + public static Factory getFactory(Class clazz) { + try { + Class> factoryClass = (Class>) Class.forName(clazz.getName() + "__Factory"); + return factoryClass.newInstance(); + } catch (Exception e) { + throw new NoFactoryFoundException(clazz, e); + } + } +} diff --git a/toothpick-runtime/src/main/java/toothpick/locators/MemberInjectorLocator.java b/toothpick-runtime/src/main/java/toothpick/locators/MemberInjectorLocator.java new file mode 100644 index 00000000..7bcc12e4 --- /dev/null +++ b/toothpick-runtime/src/main/java/toothpick/locators/MemberInjectorLocator.java @@ -0,0 +1,25 @@ +package toothpick.locators; + +import toothpick.MemberInjector; + +/** + * Locates the {@link MemberInjector} instances. + * If not {@link MemberInjector} is found, we simply return {@code null}. + * This is required to fully support polymorphism when injecting dependencies. + * + * @see MemberInjector + */ +public class MemberInjectorLocator { + private MemberInjectorLocator() { + } + + public static MemberInjector getMemberInjector(Class clazz) { + try { + Class> memberInjectorClass = + (Class>) Class.forName(clazz.getName() + "__MemberInjector"); + return memberInjectorClass.newInstance(); + } catch (Exception e) { + return null; + } + } +} diff --git a/toothpick-runtime/src/main/java/toothpick/registries/NoFactoryFoundException.java b/toothpick-runtime/src/main/java/toothpick/locators/NoFactoryFoundException.java similarity index 63% rename from toothpick-runtime/src/main/java/toothpick/registries/NoFactoryFoundException.java rename to toothpick-runtime/src/main/java/toothpick/locators/NoFactoryFoundException.java index 97be417f..c97d6b7b 100644 --- a/toothpick-runtime/src/main/java/toothpick/registries/NoFactoryFoundException.java +++ b/toothpick-runtime/src/main/java/toothpick/locators/NoFactoryFoundException.java @@ -1,4 +1,4 @@ -package toothpick.registries; +package toothpick.locators; import static java.lang.String.format; @@ -10,9 +10,6 @@ public NoFactoryFoundException(Class clazz) { public NoFactoryFoundException(Class clazz, Throwable cause) { super(format("No factory could be found for class %s. " // + "Check that the class has either a @Inject annotated constructor " // - + "or contains @Inject annotated members. " - + "If using Registries, check that they are properly setup with " - + "annotation processor arguments.", clazz.getName()), cause); + + "or contains @Inject annotated members.", clazz.getName()), cause); } - } diff --git a/toothpick-runtime/src/main/java/toothpick/registries/FactoryRegistryLocator.java b/toothpick-runtime/src/main/java/toothpick/registries/FactoryRegistryLocator.java deleted file mode 100644 index 41796609..00000000 --- a/toothpick-runtime/src/main/java/toothpick/registries/FactoryRegistryLocator.java +++ /dev/null @@ -1,60 +0,0 @@ -package toothpick.registries; - -import toothpick.Factory; -import toothpick.configuration.ConfigurationHolder; - -/** - * Locates the {@link FactoryRegistry} instances. - * The registries form a tree, or a forest (collection of disjoint trees). - * Each registry knows of to find the registries it depends on (called children registries). - * When compiling a library, developers must pass to the annotation compiler the name of the children registries - * used by this library (i.e. the name of the registries of those libraries) and also provide the package - * name of the registry that will be generated for the library being compiled. - * - * The generated registry will know about its children. An application only has to list here the high level - * registries of the libraries that it uses. Their children libraries (and the tree they form with their own children - * libraries, etc..), will be explored by the high level root library that uses them. The application should declare - * root registries to the locator prior to performing any operation. - * - * In case no generated factory for a given class, we throw a {@link RuntimeException}. - * - * The locator acts as facade for all the {@link FactoryRegistry} instances in the forest to retrieve a {@link Factory} - * for a given class. - * - * @see FactoryRegistry - * @see Factory - */ -public class FactoryRegistryLocator { - private FactoryRegistryLocator() { - } - - private static FactoryRegistry rootRegistry; - - public static void setRootRegistry(FactoryRegistry rootRegistry) { - FactoryRegistryLocator.rootRegistry = rootRegistry; - } - - public static Factory getFactory(Class clazz) { - return ConfigurationHolder.configuration.getFactory(clazz); - } - - public static Factory getFactoryUsingRegistries(Class clazz) { - Factory factory; - if (rootRegistry != null) { - factory = rootRegistry.getFactory(clazz); - if (factory != null) { - return factory; - } - } - throw new NoFactoryFoundException(clazz); - } - - public static Factory getFactoryUsingReflection(Class clazz) { - try { - Class> factoryClass = (Class>) Class.forName(clazz.getName() + "$$Factory"); - return factoryClass.newInstance(); - } catch (Exception e) { - throw new NoFactoryFoundException(clazz, e); - } - } -} diff --git a/toothpick-runtime/src/main/java/toothpick/registries/MemberInjectorRegistryLocator.java b/toothpick-runtime/src/main/java/toothpick/registries/MemberInjectorRegistryLocator.java deleted file mode 100644 index 919aa47a..00000000 --- a/toothpick-runtime/src/main/java/toothpick/registries/MemberInjectorRegistryLocator.java +++ /dev/null @@ -1,49 +0,0 @@ -package toothpick.registries; - -import toothpick.MemberInjector; -import toothpick.configuration.ConfigurationHolder; - -/** - * Locates the {@link MemberInjectorRegistry} instances. - * Works in the same way as {@link FactoryRegistry}, except that is no {@link MemberInjector} is found, - * we simply return {@code null}. This is required to fully support polymorphism when injecting dependencies. - * - * @see FactoryRegistry - * @see MemberInjectorRegistry - * @see MemberInjector - */ -public class MemberInjectorRegistryLocator { - private MemberInjectorRegistryLocator() { - } - - private static MemberInjectorRegistry registry; - - public static void setRootRegistry(MemberInjectorRegistry registry) { - MemberInjectorRegistryLocator.registry = registry; - } - - public static MemberInjector getMemberInjector(Class clazz) { - return ConfigurationHolder.configuration.getMemberInjector(clazz); - } - - public static MemberInjector getMemberInjectorUsingRegistries(Class clazz) { - MemberInjector memberInjector; - if (registry != null) { - memberInjector = registry.getMemberInjector(clazz); - if (memberInjector != null) { - return memberInjector; - } - } - return null; - } - - public static MemberInjector getMemberInjectorUsingReflection(Class clazz) { - try { - Class> memberInjectorClass = - (Class>) Class.forName(clazz.getName() + "$$MemberInjector"); - return memberInjectorClass.newInstance(); - } catch (Exception e) { - return null; - } - } -} diff --git a/toothpick-runtime/src/test/java/toothpick/AllBindingsTestWithDefaultConfiguration.java b/toothpick-runtime/src/test/java/toothpick/AllBindingsTestWithDefaultConfiguration.java index fa69da7e..23cba956 100644 --- a/toothpick-runtime/src/test/java/toothpick/AllBindingsTestWithDefaultConfiguration.java +++ b/toothpick-runtime/src/test/java/toothpick/AllBindingsTestWithDefaultConfiguration.java @@ -1,6 +1,5 @@ package toothpick; -import javax.inject.Provider; import org.junit.Test; import toothpick.config.Module; import toothpick.data.Bar; @@ -8,14 +7,16 @@ import toothpick.data.Foo; import toothpick.data.FooProvider; import toothpick.data.FooProviderAnnotatedProvidesSingleton; +import toothpick.data.FooProviderAnnotatedSingletonImpl; import toothpick.data.FooProviderReusingInstance; import toothpick.data.FooSingleton; import toothpick.data.IFoo; import toothpick.data.IFooProvider; -import toothpick.data.FooProviderAnnotatedSingletonImpl; import toothpick.data.IFooSingleton; import toothpick.data.IFooWithBarProvider; +import javax.inject.Provider; + import static org.hamcrest.CoreMatchers.isA; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.CoreMatchers.notNullValue; @@ -31,7 +32,7 @@ * from guice that toothpick honors as well. * All things created by toothpick are injected. */ -public class AllBindingsTestWithDefaultConfiguration extends ToothpickBaseTest { +public class AllBindingsTestWithDefaultConfiguration { @Test public void simpleBinding_shouldCreateInjectedInstances_whenNotSingleton() { diff --git a/toothpick-runtime/src/test/java/toothpick/ScopeImplDumpTest.java b/toothpick-runtime/src/test/java/toothpick/ScopeImplDumpTest.java index 314dcca0..86cde72b 100644 --- a/toothpick-runtime/src/test/java/toothpick/ScopeImplDumpTest.java +++ b/toothpick-runtime/src/test/java/toothpick/ScopeImplDumpTest.java @@ -9,7 +9,7 @@ import static org.junit.Assert.assertThat; -public class ScopeImplDumpTest extends ToothpickBaseTest { +public class ScopeImplDumpTest { @Test public void testToString() { diff --git a/toothpick-runtime/src/test/java/toothpick/ScopeImplTest.java b/toothpick-runtime/src/test/java/toothpick/ScopeImplTest.java index 45bcac5f..f27cf8dc 100644 --- a/toothpick-runtime/src/test/java/toothpick/ScopeImplTest.java +++ b/toothpick-runtime/src/test/java/toothpick/ScopeImplTest.java @@ -5,7 +5,7 @@ import toothpick.data.Bar; import toothpick.data.Foo; import toothpick.data.IFoo; -import toothpick.registries.NoFactoryFoundException; +import toothpick.locators.NoFactoryFoundException; import javax.inject.Provider; @@ -14,7 +14,7 @@ import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; -public class ScopeImplTest extends ToothpickBaseTest { +public class ScopeImplTest { @Test public void installOverrideModules_shouldInstallOverrideBindings_whenCalledOnce() { diff --git a/toothpick-runtime/src/test/java/toothpick/ToothpickBaseTest.java b/toothpick-runtime/src/test/java/toothpick/ToothpickBaseTest.java deleted file mode 100644 index dfc0c3f6..00000000 --- a/toothpick-runtime/src/test/java/toothpick/ToothpickBaseTest.java +++ /dev/null @@ -1,24 +0,0 @@ -package toothpick; - -import org.junit.After; -import org.junit.BeforeClass; -import toothpick.configuration.Configuration; -import toothpick.registries.FactoryRegistryLocator; -import toothpick.registries.MemberInjectorRegistryLocator; - -public class ToothpickBaseTest { - protected ToothpickBaseTest() { - } - - @BeforeClass - public static void setUp() throws Exception { - MemberInjectorRegistryLocator.setRootRegistry(new toothpick.test.MemberInjectorRegistry()); - FactoryRegistryLocator.setRootRegistry(new toothpick.test.FactoryRegistry()); - Toothpick.setConfiguration(Configuration.forProduction().disableReflection()); - } - - @After - public void tearDown() throws Exception { - Toothpick.reset(); - } -} diff --git a/toothpick-runtime/src/test/java/toothpick/ToothpickTest.java b/toothpick-runtime/src/test/java/toothpick/ToothpickTest.java index c038b342..7b23cb5f 100644 --- a/toothpick-runtime/src/test/java/toothpick/ToothpickTest.java +++ b/toothpick-runtime/src/test/java/toothpick/ToothpickTest.java @@ -17,7 +17,7 @@ import static org.hamcrest.CoreMatchers.sameInstance; import static org.hamcrest.MatcherAssert.assertThat; -public class ToothpickTest extends ToothpickBaseTest { +public class ToothpickTest { @Test public void getScope_shouldNotReturnNull_whenNoScopeByThisKeyWasCreated() throws Exception { diff --git a/toothpick-runtime/src/test/java/toothpick/concurrency/BindingsMultiThreadTest.java b/toothpick-runtime/src/test/java/toothpick/concurrency/BindingsMultiThreadTest.java index f34ab1a5..697b83e6 100644 --- a/toothpick-runtime/src/test/java/toothpick/concurrency/BindingsMultiThreadTest.java +++ b/toothpick-runtime/src/test/java/toothpick/concurrency/BindingsMultiThreadTest.java @@ -4,9 +4,15 @@ import java.util.List; import java.util.Random; import java.util.concurrent.CopyOnWriteArrayList; +import org.easymock.Capture; +import org.easymock.IAnswer; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.powermock.api.easymock.PowerMock; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.rule.PowerMockRule; import toothpick.configuration.Configuration; import toothpick.Factory; import toothpick.Scope; @@ -17,36 +23,47 @@ import toothpick.concurrency.threads.TestableThread; import toothpick.concurrency.utils.ClassCreator; import toothpick.concurrency.utils.ThreadTestUtil; -import toothpick.registries.FactoryRegistry; -import toothpick.registries.FactoryRegistryLocator; -import toothpick.registries.MemberInjectorRegistryLocator; +import toothpick.locators.FactoryLocator; +import static org.easymock.EasyMock.capture; +import static org.easymock.EasyMock.expect; import static org.junit.Assert.assertTrue; import static toothpick.concurrency.utils.ThreadTestUtil.STANDARD_THREAD_COUNT; +@PrepareForTest(FactoryLocator.class) public class BindingsMultiThreadTest { + public @Rule PowerMockRule rule = new PowerMockRule(); + static final String ROOT_SCOPE = "ROOT_SCOPE"; final List scopeNames = new CopyOnWriteArrayList<>(); private static ClassCreator classCreator = new ClassCreator(); @Before - public void setUp() throws Exception { - Toothpick.setConfiguration(Configuration.forProduction().disableReflection()); + public void setUp() { + + PowerMock.mockStatic(FactoryLocator.class); + final Capture capturedClass = Capture.newInstance(); + expect(FactoryLocator.getFactory(capture(capturedClass))).andAnswer(new IAnswer() { + @Override public Factory answer() throws Throwable { + return new DynamicTestClassesFactory(capturedClass.getValue(), true); + } + }).anyTimes(); + PowerMock.replay(FactoryLocator.class); + Toothpick.setConfiguration(Configuration.forProduction()); Toothpick.openScope(ROOT_SCOPE); scopeNames.clear(); } @After - public void tearDown() throws Exception { + public void tearDown() { Toothpick.reset(); - FactoryRegistryLocator.setRootRegistry(null); - MemberInjectorRegistryLocator.setRootRegistry(null); ThreadTestUtil.shutdown(); + PowerMock.verify(FactoryLocator.class); } @Test - public void concurrentBindingInstall_shouldNotCrash() throws InterruptedException { + public void concurrentBindingInstall_shouldNotCrash() { //GIVEN final int addNodeThreadCount = STANDARD_THREAD_COUNT; List threadList = new ArrayList<>(); @@ -67,7 +84,7 @@ public void concurrentBindingInstall_shouldNotCrash() throws InterruptedExceptio } @Test - public void concurrentBindingInstallAndToString_shouldNotCrash() throws InterruptedException { + public void concurrentBindingInstallAndToString_shouldNotCrash() { //GIVEN final int addNodeThreadCount = STANDARD_THREAD_COUNT; List threadList = new ArrayList<>(); @@ -94,12 +111,11 @@ public void concurrentBindingInstallAndToString_shouldNotCrash() throws Interrup } @Test - public void concurrentBindingInstallAndGetInstance_shouldNotCrash() throws InterruptedException { + public void concurrentBindingInstallAndGetInstance_shouldNotCrash() { //GIVEN final int addNodeThreadCount = STANDARD_THREAD_COUNT; List threadList = new ArrayList<>(); Random random = new Random(); - FactoryRegistryLocator.setRootRegistry(new DynamicTestClassesFactoryRegistry(true)); //WHEN for (int indexThread = 0; indexThread < addNodeThreadCount; indexThread++) { @@ -123,12 +139,11 @@ public void concurrentBindingInstallAndGetInstance_shouldNotCrash() throws Inter } @Test - public void concurrentScopedGetInstance_shouldNotCrash() throws InterruptedException { + public void concurrentScopedGetInstance_shouldNotCrash() { //GIVEN final int addNodeThreadCount = STANDARD_THREAD_COUNT; List threadList = new ArrayList<>(); Random random = new Random(); - FactoryRegistryLocator.setRootRegistry(new DynamicTestClassesFactoryRegistry(true)); //WHEN for (int indexThread = 0; indexThread < addNodeThreadCount; indexThread++) { @@ -179,20 +194,4 @@ public boolean hasProvidesSingletonInScopeAnnotation() { return false; } } - - private static class DynamicTestClassesFactoryRegistry implements FactoryRegistry { - private boolean scoped; - - DynamicTestClassesFactoryRegistry(boolean scoped) { - this.scoped = scoped; - } - - @Override - public Factory getFactory(final Class clazz) { - if (clazz.getName().startsWith("Class_")) { - return new DynamicTestClassesFactory<>(clazz, scoped); - } - return null; - } - } } diff --git a/toothpick-runtime/src/test/java/toothpick/data/Qurtz.java b/toothpick-runtime/src/test/java/toothpick/data/Qurtz.java new file mode 100644 index 00000000..d5551611 --- /dev/null +++ b/toothpick-runtime/src/test/java/toothpick/data/Qurtz.java @@ -0,0 +1,7 @@ +package toothpick.data; + +/** + * Class with no annotations, no Factory or MemberInjector is generated. + */ +public class Qurtz { +} diff --git a/toothpick-runtime/src/test/java/toothpick/getInstance/CycleCheckTest.java b/toothpick-runtime/src/test/java/toothpick/getInstance/CycleCheckTest.java index 089f20e0..d6945368 100644 --- a/toothpick-runtime/src/test/java/toothpick/getInstance/CycleCheckTest.java +++ b/toothpick-runtime/src/test/java/toothpick/getInstance/CycleCheckTest.java @@ -1,19 +1,19 @@ package toothpick.getInstance; +import org.junit.After; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import toothpick.Scope; import toothpick.ScopeImpl; import toothpick.Toothpick; -import toothpick.ToothpickBaseTest; import toothpick.config.Module; import toothpick.configuration.Configuration; import toothpick.configuration.CyclicDependencyException; import toothpick.data.CyclicFoo; import toothpick.data.CyclicNamedFoo; import toothpick.data.IFoo; -import toothpick.registries.NoFactoryFoundException; +import toothpick.locators.NoFactoryFoundException; import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.CoreMatchers.sameInstance; @@ -24,21 +24,25 @@ * Creates a instance in the simplest possible way * without any module. */ -public class CycleCheckTest extends ToothpickBaseTest { +public class CycleCheckTest { @BeforeClass - public static void setUp() throws Exception { - ToothpickBaseTest.setUp(); - Toothpick.setConfiguration(Configuration.forDevelopment().disableReflection()); + public static void setUp() { + Toothpick.setConfiguration(Configuration.forDevelopment()); } @AfterClass - public static void staticTearDown() throws Exception { - Toothpick.setConfiguration(Configuration.forProduction().disableReflection()); + public static void staticTearDown() { + Toothpick.setConfiguration(Configuration.forProduction()); + } + + @After + public void tearDown() { + Toothpick.reset(); } @Test(expected = CyclicDependencyException.class) - public void testSimpleCycleDetection() throws Exception { + public void testSimpleCycleDetection() { //GIVEN Scope scope = new ScopeImpl(""); @@ -50,7 +54,7 @@ public void testSimpleCycleDetection() throws Exception { } @Test - public void testCycleDetection_whenSameClass_and_differentName_shouldNotCrash() throws Exception { + public void testCycleDetection_whenSameClass_and_differentName_shouldNotCrash() { //GIVEN final CyclicNamedFoo instance1 = new CyclicNamedFoo(); Scope scope = new ScopeImpl(""); @@ -70,7 +74,7 @@ public void testCycleDetection_whenSameClass_and_differentName_shouldNotCrash() } @Test(expected = NoFactoryFoundException.class) - public void testCycleDetection_whenGetInstanceFails_shouldCloseCycle() throws Exception { + public void testCycleDetection_whenGetInstanceFails_shouldCloseCycle() { //GIVEN Scope scope = new ScopeImpl(""); diff --git a/toothpick-runtime/src/test/java/toothpick/getInstance/NamedInstanceCreation.java b/toothpick-runtime/src/test/java/toothpick/getInstance/NamedInstanceCreation.java index b296c41a..39ad7f63 100644 --- a/toothpick-runtime/src/test/java/toothpick/getInstance/NamedInstanceCreation.java +++ b/toothpick-runtime/src/test/java/toothpick/getInstance/NamedInstanceCreation.java @@ -5,7 +5,6 @@ import org.junit.Test; import toothpick.Scope; import toothpick.ScopeImpl; -import toothpick.ToothpickBaseTest; import toothpick.config.Module; import toothpick.data.Foo; @@ -20,7 +19,7 @@ * Creates a instance in the simplest possible way * with a module that binds a single class. */ -public class NamedInstanceCreation extends ToothpickBaseTest { +public class NamedInstanceCreation { static Foo namedFooInstance = new Foo(); diff --git a/toothpick-runtime/src/test/java/toothpick/inject/InjectionWithoutModuleTest.java b/toothpick-runtime/src/test/java/toothpick/inject/InjectionWithoutModuleTest.java index 88705765..9189ed59 100644 --- a/toothpick-runtime/src/test/java/toothpick/inject/InjectionWithoutModuleTest.java +++ b/toothpick-runtime/src/test/java/toothpick/inject/InjectionWithoutModuleTest.java @@ -4,7 +4,6 @@ import toothpick.Scope; import toothpick.ScopeImpl; import toothpick.Toothpick; -import toothpick.ToothpickBaseTest; import toothpick.config.Module; import toothpick.data.Bar; import toothpick.data.Foo; @@ -22,7 +21,7 @@ * Creates a instance in the simplest possible way * without any module. */ -public class InjectionWithoutModuleTest extends ToothpickBaseTest { +public class InjectionWithoutModuleTest { @Test public void testSimpleInjection() throws Exception { diff --git a/toothpick-runtime/src/test/java/toothpick/inject/lazy/InjectionOfLazyProviderTest.java b/toothpick-runtime/src/test/java/toothpick/inject/lazy/InjectionOfLazyProviderTest.java index 3541574e..b6bdea76 100644 --- a/toothpick-runtime/src/test/java/toothpick/inject/lazy/InjectionOfLazyProviderTest.java +++ b/toothpick-runtime/src/test/java/toothpick/inject/lazy/InjectionOfLazyProviderTest.java @@ -5,7 +5,6 @@ import toothpick.Scope; import toothpick.ScopeImpl; import toothpick.Toothpick; -import toothpick.ToothpickBaseTest; import toothpick.config.Module; import toothpick.data.Bar; import toothpick.data.FooWithLazy; @@ -19,7 +18,7 @@ /* * Test injection of {@code Lazy}s. */ -public class InjectionOfLazyProviderTest extends ToothpickBaseTest { +public class InjectionOfLazyProviderTest { @Test public void testSimpleInjection() throws Exception { diff --git a/toothpick-runtime/src/test/java/toothpick/locators/FactoryLocatorTest.java b/toothpick-runtime/src/test/java/toothpick/locators/FactoryLocatorTest.java new file mode 100644 index 00000000..d7c7ca3c --- /dev/null +++ b/toothpick-runtime/src/test/java/toothpick/locators/FactoryLocatorTest.java @@ -0,0 +1,38 @@ +package toothpick.locators; + +import org.junit.Before; +import org.junit.Test; +import toothpick.Toothpick; +import toothpick.configuration.Configuration; +import toothpick.data.Foo; +import toothpick.data.Qurtz; + +import static org.junit.Assert.fail; + +public class FactoryLocatorTest { + + @Before + public void setUp() { + Toothpick.setConfiguration(Configuration.forProduction()); + } + + @Test + public void testGetFactory_shouldFindTheFactoryForFoo_whenTheFactoryIsGenerated() { + //GIVEN + //WHEN + FactoryLocator.getFactory(Foo.class); + + //THEN + // Should not crash + } + + @Test(expected = NoFactoryFoundException.class) + public void testGetFactory_shouldThrowAnException_whenTheFActoryIsNotGenerated() { + //GIVEN + //WHEN + FactoryLocator.getFactory(Qurtz.class); + + //THEN + fail("Should throw an exception"); + } +} diff --git a/toothpick-runtime/src/test/java/toothpick/locators/MemberInjectorLocatorTest.java b/toothpick-runtime/src/test/java/toothpick/locators/MemberInjectorLocatorTest.java new file mode 100644 index 00000000..cc58997b --- /dev/null +++ b/toothpick-runtime/src/test/java/toothpick/locators/MemberInjectorLocatorTest.java @@ -0,0 +1,41 @@ +package toothpick.locators; + +import org.junit.Before; +import org.junit.Test; +import toothpick.MemberInjector; +import toothpick.Toothpick; +import toothpick.configuration.Configuration; +import toothpick.data.Foo; +import toothpick.data.Qurtz; + +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertThat; + +public class MemberInjectorLocatorTest { + + @Before + public void setUp() { + Toothpick.setConfiguration(Configuration.forProduction()); + } + + @Test + public void testGetMemberInjector_shouldFindTheMemberInjectorForFoo_whenTheMemberInjectorIsGenerated() { + //GIVEN + //WHEN + MemberInjector memberInjector = MemberInjectorLocator.getMemberInjector(Foo.class); + + //THEN + assertThat(memberInjector, notNullValue()); + } + + @Test + public void testGetMemberInjector_shouldNotReturnNull_whenTheMemberInjectorIsNotGenerated() { + //GIVEN + //WHEN + MemberInjector memberInjector = MemberInjectorLocator.getMemberInjector(Qurtz.class); + + //THEN + assertThat(memberInjector, nullValue()); + } +} diff --git a/toothpick-runtime/src/test/java/toothpick/registries/NoFactoryFoundExceptionTest.java b/toothpick-runtime/src/test/java/toothpick/locators/NoFactoryFoundExceptionTest.java similarity index 96% rename from toothpick-runtime/src/test/java/toothpick/registries/NoFactoryFoundExceptionTest.java rename to toothpick-runtime/src/test/java/toothpick/locators/NoFactoryFoundExceptionTest.java index 14a0542a..3c2278ef 100644 --- a/toothpick-runtime/src/test/java/toothpick/registries/NoFactoryFoundExceptionTest.java +++ b/toothpick-runtime/src/test/java/toothpick/locators/NoFactoryFoundExceptionTest.java @@ -1,4 +1,4 @@ -package toothpick.registries; +package toothpick.locators; import org.junit.Test; diff --git a/toothpick-runtime/src/test/java/toothpick/registries/FactoryRegistryLocatorTest.java b/toothpick-runtime/src/test/java/toothpick/registries/FactoryRegistryLocatorTest.java deleted file mode 100644 index cdc4b057..00000000 --- a/toothpick-runtime/src/test/java/toothpick/registries/FactoryRegistryLocatorTest.java +++ /dev/null @@ -1,140 +0,0 @@ -package toothpick.registries; - -import org.junit.Before; -import org.junit.Test; -import toothpick.configuration.Configuration; -import toothpick.Factory; -import toothpick.Scope; -import toothpick.Toothpick; -import toothpick.data.Bar; -import toothpick.data.Foo; -import toothpick.registries.factory.AbstractFactoryRegistry; - -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; - -public class FactoryRegistryLocatorTest { - - @Before - public void setUp() throws Exception { - Toothpick.setConfiguration(Configuration.forProduction().disableReflection()); - } - - @Test(expected = RuntimeException.class) - public void testGetFactory_shouldThrowAnException_whenThereAreNoRegistries() throws Exception { - //GIVEN - FactoryRegistryLocator.setRootRegistry(null); - - //WHEN - FactoryRegistryLocator.getFactory(Foo.class); - - //THEN - fail("Should throw an exception"); - } - - @Test - public void testGetFactory_shouldFindTheFactory_whenThereIsARegistryThatKnowsTheFactory() throws Exception { - //GIVEN - FactoryRegistryLocator.setRootRegistry(new AbstractFactoryRegistry() { - @Override - public Factory getFactory(Class clazz) { - if (clazz == Foo.class) { - return (Factory) new FooFactory(); - } else { - return super.getFactoryInChildrenRegistries(clazz); - } - } - }); - - //WHEN - Factory factory = FactoryRegistryLocator.getFactory(Foo.class); - - //THEN - assertThat(factory, instanceOf(FooFactory.class)); - } - - @Test - public void testGetFactory_shouldFindTheFactory_whenAChildRegistryKnowsTheFactory() throws Exception { - //GIVEN - AbstractFactoryRegistry rootRegistry = new AbstractFactoryRegistry() { - @Override - public Factory getFactory(Class clazz) { - return getFactoryInChildrenRegistries(clazz); - } - }; - AbstractFactoryRegistry childRegistry = new AbstractFactoryRegistry() { - @Override - public Factory getFactory(Class clazz) { - if (clazz == Foo.class) { - return (Factory) new FooFactory(); - } else { - return null; - } - } - }; - rootRegistry.addChildRegistry(childRegistry); - FactoryRegistryLocator.setRootRegistry(rootRegistry); - - //WHEN - Factory factory = FactoryRegistryLocator.getFactory(Foo.class); - - //THEN - assertThat(factory, instanceOf(FooFactory.class)); - } - - @Test(expected = RuntimeException.class) - public void testGetFactory_shouldThrowAnException_whenThereIsNoRegistryThatKnowsTheFactory() throws Exception { - //GIVEN - AbstractFactoryRegistry rootRegistry = new AbstractFactoryRegistry() { - @Override - public Factory getFactory(Class clazz) { - if (clazz == Foo.class) { - return (Factory) new FooFactory(); - } else { - return super.getFactoryInChildrenRegistries(clazz); - } - } - }; - AbstractFactoryRegistry childRegistry = new AbstractFactoryRegistry() { - @Override - public Factory getFactory(Class clazz) { - if (clazz == Foo.class) { - return (Factory) new FooFactory(); - } else { - return null; - } - } - }; - rootRegistry.addChildRegistry(childRegistry); - FactoryRegistryLocator.setRootRegistry(rootRegistry); - - //WHEN - FactoryRegistryLocator.getFactory(Bar.class); - - //THEN - fail("Should throw an exception"); - } - - private static class FooFactory implements Factory { - @Override - public Foo createInstance(Scope scope) { - return null; - } - - @Override - public Scope getTargetScope(Scope currentScope) { - return currentScope; - } - - @Override - public boolean hasScopeAnnotation() { - return false; - } - - @Override - public boolean hasProvidesSingletonInScopeAnnotation() { - return false; - } - } -} \ No newline at end of file diff --git a/toothpick-runtime/src/test/java/toothpick/registries/MemberInjectorRegistryLocatorTest.java b/toothpick-runtime/src/test/java/toothpick/registries/MemberInjectorRegistryLocatorTest.java deleted file mode 100644 index 226d4dd1..00000000 --- a/toothpick-runtime/src/test/java/toothpick/registries/MemberInjectorRegistryLocatorTest.java +++ /dev/null @@ -1,120 +0,0 @@ -package toothpick.registries; - -import org.junit.Test; -import toothpick.configuration.Configuration; -import toothpick.MemberInjector; -import toothpick.Scope; -import toothpick.Toothpick; -import toothpick.data.Bar; -import toothpick.data.Foo; -import toothpick.registries.memberinjector.AbstractMemberInjectorRegistry; - -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.hamcrest.CoreMatchers.nullValue; -import static org.junit.Assert.assertThat; - -public class MemberInjectorRegistryLocatorTest { - - @Test - public void testGetMemberInjector_shouldReturnNull_whenThereAreNoRegistries() throws Exception { - //GIVEN - Toothpick.setConfiguration(Configuration.forProduction().disableReflection()); - MemberInjectorRegistryLocator.setRootRegistry(null); - - //WHEN - MemberInjector memberInjector = MemberInjectorRegistryLocator.getMemberInjector(Foo.class); - - //THEN - assertThat(memberInjector, nullValue()); - } - - @Test - public void testGetMemberInjector_shouldFindTheMemberInjector_whenThereIsARegistryThatKnowsTheMemberInjector() throws Exception { - //GIVEN - MemberInjectorRegistryLocator.setRootRegistry(new AbstractMemberInjectorRegistry() { - @Override - public MemberInjector getMemberInjector(Class clazz) { - if (clazz == Foo.class) { - return (MemberInjector) new FooMemberInjector(); - } else { - return getMemberInjectorInChildrenRegistries(clazz); - } - } - }); - - //WHEN - MemberInjector memberInjector = MemberInjectorRegistryLocator.getMemberInjector(Foo.class); - - //THEN - assertThat(memberInjector, instanceOf(FooMemberInjector.class)); - } - - @Test - public void testGetMemberInjector_shouldFindTheMemberInjector_whenAChildRegistryKnowsTheMemberInjector() throws Exception { - //GIVEN - AbstractMemberInjectorRegistry rootRegistry = new AbstractMemberInjectorRegistry() { - @Override - public MemberInjector getMemberInjector(Class clazz) { - return getMemberInjectorInChildrenRegistries(clazz); - } - }; - AbstractMemberInjectorRegistry childRegistry = new AbstractMemberInjectorRegistry() { - @Override - public MemberInjector getMemberInjector(Class clazz) { - if (clazz == Foo.class) { - return (MemberInjector) new FooMemberInjector(); - } else { - return getMemberInjectorInChildrenRegistries(clazz); - } - } - }; - rootRegistry.addChildRegistry(childRegistry); - MemberInjectorRegistryLocator.setRootRegistry(rootRegistry); - - //WHEN - MemberInjector memberInjector = MemberInjectorRegistryLocator.getMemberInjector(Foo.class); - - //THEN - assertThat(memberInjector, instanceOf(FooMemberInjector.class)); - } - - @Test - public void testGetMemberInjector_shouldReturnNull_whenThereIsNoRegistryThatKnowsTheMemberInjector() throws Exception { - //GIVEN - AbstractMemberInjectorRegistry rootRegistry = new AbstractMemberInjectorRegistry() { - @Override - public MemberInjector getMemberInjector(Class clazz) { - if (clazz == Foo.class) { - return (MemberInjector) new FooMemberInjector(); - } else { - return getMemberInjectorInChildrenRegistries(clazz); - } - } - }; - AbstractMemberInjectorRegistry childRegistry = new AbstractMemberInjectorRegistry() { - @Override - public MemberInjector getMemberInjector(Class clazz) { - if (clazz == Foo.class) { - return (MemberInjector) new FooMemberInjector(); - } else { - return getMemberInjectorInChildrenRegistries(clazz); - } - } - }; - rootRegistry.addChildRegistry(childRegistry); - MemberInjectorRegistryLocator.setRootRegistry(rootRegistry); - - //WHEN - MemberInjector memberInjector = MemberInjectorRegistryLocator.getMemberInjector(Bar.class); - - //THEN - assertThat(memberInjector, nullValue()); - } - - private static class FooMemberInjector implements MemberInjector { - @Override - public void inject(Foo foo, Scope scope) { - - } - } -} \ No newline at end of file diff --git a/toothpick-runtime/src/test/java/toothpick/scoping/ScopingTest.java b/toothpick-runtime/src/test/java/toothpick/scoping/ScopingTest.java index a6f7f46b..57bd1c04 100644 --- a/toothpick-runtime/src/test/java/toothpick/scoping/ScopingTest.java +++ b/toothpick-runtime/src/test/java/toothpick/scoping/ScopingTest.java @@ -1,9 +1,9 @@ package toothpick.scoping; +import org.junit.After; import org.junit.Test; import toothpick.Scope; import toothpick.Toothpick; -import toothpick.ToothpickBaseTest; import toothpick.config.Module; import toothpick.data.Bar; import toothpick.data.BarChild; @@ -29,9 +29,14 @@ /* * Tests scopes related features of toothpick. */ -public class ScopingTest extends ToothpickBaseTest { +public class ScopingTest { - @Test + @After + public void tearDown() throws Exception { + Toothpick.reset(); + } + + @Test public void childInjector_shouldReturnInstancesInItsScope_whenParentAlsoHasSameKeyInHisScope() throws Exception { //GIVEN diff --git a/toothpick-sample/build.gradle b/toothpick-sample/build.gradle index 6d1f71b1..64e9e73c 100644 --- a/toothpick-sample/build.gradle +++ b/toothpick-sample/build.gradle @@ -1,32 +1,21 @@ apply plugin: 'java' -configurations { - annotationProcessor +repositories { + google() + jcenter() } +apply from: '../deps.gradle' + dependencies { - implementation project(':toothpick-runtime') + implementation deps.tp_runtime - annotationProcessor project(':toothpick-compiler') + annotationProcessor deps.tp_compiler - testImplementation project(':toothpick-testing') - testImplementation deps.junit + testImplementation deps.tp_testing_junit5 + testImplementation deps.junit5_api + testRuntimeOnly deps.junit5_engine testImplementation deps.easymock + testImplementation deps.hamcrest + testAnnotationProcessor deps.tp_compiler } - -afterEvaluate { - if (project.tasks.findByName('check')) { - jacocoTestReport { - reports { - xml.enabled = false - html.enabled = false - } - } - } -} - -compileJava { - options.annotationProcessorPath = configurations.annotationProcessor - options.compilerArgs = ['-Atoothpick_registry_package_name=toothpick.sample',] -} - diff --git a/toothpick-sample/gradle/wrapper/gradle-wrapper.jar b/toothpick-sample/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..f6b961fd5a86aa5fbfe90f707c3138408be7c718 GIT binary patch literal 54329 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

<5G2M1WZP5 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 F{|7XC?P&l2 literal 0 HcmV?d00001 diff --git a/toothpick-sample/gradle/wrapper/gradle-wrapper.properties b/toothpick-sample/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..178d0f08 --- /dev/null +++ b/toothpick-sample/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Thu Jan 31 13:58:15 PST 2019 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-all.zip diff --git a/toothpick-sample/gradlew b/toothpick-sample/gradlew new file mode 100755 index 00000000..cccdd3d5 --- /dev/null +++ b/toothpick-sample/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/toothpick-sample/gradlew.bat b/toothpick-sample/gradlew.bat new file mode 100644 index 00000000..f9553162 --- /dev/null +++ b/toothpick-sample/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/toothpick-sample/settings.gradle b/toothpick-sample/settings.gradle new file mode 100644 index 00000000..53785818 --- /dev/null +++ b/toothpick-sample/settings.gradle @@ -0,0 +1 @@ +includeBuild '..' diff --git a/toothpick-sample/src/main/java/toothpick/sample/SecondEntryPoint.java b/toothpick-sample/src/main/java/toothpick/sample/SecondEntryPoint.java deleted file mode 100644 index 8d3507a1..00000000 --- a/toothpick-sample/src/main/java/toothpick/sample/SecondEntryPoint.java +++ /dev/null @@ -1,18 +0,0 @@ -package toothpick.sample; - -import javax.inject.Inject; -import toothpick.Scope; -import toothpick.Toothpick; - -// https://github.com/stephanenicolas/toothpick/wiki/Suppressing-compilation-warnings -@SuppressWarnings("Injectable") -public class SecondEntryPoint { - - @Inject Computer computer; - @Inject Computer2 computer2; - - private SecondEntryPoint() { - Scope scope = Toothpick.openScope("SecondEntryPoint"); - Toothpick.inject(this, scope); - } -} diff --git a/toothpick-sample/src/main/java/toothpick/sample/SimpleEntryPoint.java b/toothpick-sample/src/main/java/toothpick/sample/SimpleEntryPoint.java index a96967ca..051c1b4f 100644 --- a/toothpick-sample/src/main/java/toothpick/sample/SimpleEntryPoint.java +++ b/toothpick-sample/src/main/java/toothpick/sample/SimpleEntryPoint.java @@ -9,17 +9,17 @@ public class SimpleEntryPoint { @Inject Computer computer; Computer2 computer2; + public SimpleEntryPoint() { + Scope scope = Toothpick.openScope("SimpleEntryPoint"); + Toothpick.inject(this, scope); + } + @SuppressWarnings("unused") @Inject void setComputer2(Computer2 computer2) { this.computer2 = computer2; } - public SimpleEntryPoint() { - Scope scope = Toothpick.openScope("SimpleEntryPoint"); - Toothpick.inject(this, scope); - } - public int multiply() { return 3 * computer.compute() * computer2.compute(); } diff --git a/toothpick-sample/src/test/java/toothpick/sample/Computer2Test.java b/toothpick-sample/src/test/java/toothpick/sample/Computer2Test.java index 487741a0..e2fc6791 100644 --- a/toothpick-sample/src/test/java/toothpick/sample/Computer2Test.java +++ b/toothpick-sample/src/test/java/toothpick/sample/Computer2Test.java @@ -1,17 +1,16 @@ package toothpick.sample; -import org.easymock.TestSubject; -import org.junit.Test; +import org.junit.jupiter.api.Test; import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; -public class Computer2Test { +class Computer2Test { - @TestSubject private Computer2 computer2UnderTest = new Computer2(); + private Computer2 computer2UnderTest = new Computer2(); @Test - public void testMultiply() throws Exception { + void testMultiply() { //GIVEN //WHEN diff --git a/toothpick-sample/src/test/java/toothpick/sample/ComputerTest.java b/toothpick-sample/src/test/java/toothpick/sample/ComputerTest.java index 6ccd0acd..ef885730 100644 --- a/toothpick-sample/src/test/java/toothpick/sample/ComputerTest.java +++ b/toothpick-sample/src/test/java/toothpick/sample/ComputerTest.java @@ -1,37 +1,23 @@ package toothpick.sample; -import org.easymock.EasyMockRule; -import org.easymock.TestSubject; -import org.junit.After; -import org.junit.BeforeClass; -import org.junit.Rule; -import org.junit.Test; -import toothpick.Toothpick; -import toothpick.registries.FactoryRegistryLocator; -import toothpick.registries.MemberInjectorRegistryLocator; +import javax.inject.Inject; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import toothpick.testing.ToothPickExtension; import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; -public class ComputerTest { +class ComputerTest { - @Rule public EasyMockRule mocks = new EasyMockRule(this); - @TestSubject private Computer computerUnderTest = Toothpick.openScope("Computer").getInstance(Computer.class); + @RegisterExtension ToothPickExtension toothPickExtension = new ToothPickExtension(this, "MyScope"); - @BeforeClass - public static void setUp() throws Exception { - MemberInjectorRegistryLocator.setRootRegistry(new toothpick.sample.MemberInjectorRegistry()); - FactoryRegistryLocator.setRootRegistry(new toothpick.sample.FactoryRegistry()); - } - - @After - public void tearDown() throws Exception { - Toothpick.reset(); - } + @Inject Computer computerUnderTest; @Test - public void testMultiply() throws Exception { + void testMultiply() { //GIVEN + toothPickExtension.inject(this); //WHEN int result = computerUnderTest.compute(); @@ -39,4 +25,4 @@ public void testMultiply() throws Exception { //THEN assertThat(result, is(2)); } -} \ No newline at end of file +} diff --git a/toothpick-sample/src/test/java/toothpick/sample/ComputerTestWithRules.java b/toothpick-sample/src/test/java/toothpick/sample/ComputerTestWithRules.java deleted file mode 100644 index 69600ac8..00000000 --- a/toothpick-sample/src/test/java/toothpick/sample/ComputerTestWithRules.java +++ /dev/null @@ -1,26 +0,0 @@ -package toothpick.sample; - -import org.junit.Rule; -import org.junit.Test; -import toothpick.testing.ToothPickRule; - -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; - -public class ComputerTestWithRules { - - @Rule public ToothPickRule toothPickRule = new ToothPickRule(this, "").setRootRegistryPackage("toothpick.sample"); - - private Computer computerUnderTest = toothPickRule.getInstance(Computer.class); - - @Test - public void testMultiply() throws Exception { - //GIVEN - - //WHEN - int result = computerUnderTest.compute(); - - //THEN - assertThat(result, is(2)); - } -} \ No newline at end of file diff --git a/toothpick-sample/src/test/java/toothpick/sample/EasyMockExtension.java b/toothpick-sample/src/test/java/toothpick/sample/EasyMockExtension.java new file mode 100644 index 00000000..26be5a79 --- /dev/null +++ b/toothpick-sample/src/test/java/toothpick/sample/EasyMockExtension.java @@ -0,0 +1,19 @@ +package toothpick.sample; + +import org.easymock.EasyMockSupport; +import org.junit.jupiter.api.extension.BeforeEachCallback; +import org.junit.jupiter.api.extension.ExtensionContext; + +public class EasyMockExtension implements BeforeEachCallback { + + private final Object test; + + public EasyMockExtension(Object test) { + this.test = test; + } + + @Override + public void beforeEach(ExtensionContext context) throws Exception { + EasyMockSupport.injectMocks(test); + } +} diff --git a/toothpick-sample/src/test/java/toothpick/sample/SimpleEntryPointTest.java b/toothpick-sample/src/test/java/toothpick/sample/SimpleEntryPointTest.java index 6c67d84b..acdda07e 100644 --- a/toothpick-sample/src/test/java/toothpick/sample/SimpleEntryPointTest.java +++ b/toothpick-sample/src/test/java/toothpick/sample/SimpleEntryPointTest.java @@ -1,51 +1,36 @@ package toothpick.sample; -import org.easymock.EasyMockRule; +import javax.inject.Inject; import org.easymock.Mock; -import org.easymock.TestSubject; -import org.junit.After; -import org.junit.BeforeClass; -import org.junit.Rule; -import org.junit.Test; -import toothpick.Scope; -import toothpick.Toothpick; -import toothpick.config.Module; -import toothpick.registries.FactoryRegistryLocator; -import toothpick.registries.MemberInjectorRegistryLocator; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import toothpick.testing.ToothPickExtension; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.verify; import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; -public class SimpleEntryPointTest { +class SimpleEntryPointTest { + + @RegisterExtension ToothPickExtension toothPickExtension = new ToothPickExtension(this, "MyScope"); + @RegisterExtension EasyMockExtension easyMockExtension = new EasyMockExtension(this); - @Rule public EasyMockRule mocks = new EasyMockRule(this); - @TestSubject private SimpleEntryPoint simpleEntryPointUnderTest = new SimpleEntryPoint(); @Mock private Computer mockComputer; @Mock private Computer2 mockComputer2; - @BeforeClass - public static void setUp() throws Exception { - MemberInjectorRegistryLocator.setRootRegistry(new toothpick.sample.MemberInjectorRegistry()); - FactoryRegistryLocator.setRootRegistry(new toothpick.sample.FactoryRegistry()); - } - - @After - public void tearDown() throws Exception { - Toothpick.reset(); - } + @Inject SimpleEntryPoint simpleEntryPointUnderTest; @Test public void testMultiply() throws Exception { //GIVEN expect(mockComputer.compute()).andReturn(4); expect(mockComputer2.compute()).andReturn(4); + replay(mockComputer, mockComputer2); - final Scope scope = Toothpick.openScope("SimpleEntryPoint"); - scope.installTestModules(new TestModule()); + toothPickExtension.inject(this); //WHEN int result = simpleEntryPointUnderTest.multiply(); @@ -54,10 +39,4 @@ public void testMultiply() throws Exception { assertThat(result, is(48)); verify(mockComputer); } - - private class TestModule extends Module { - TestModule() { - bind(Computer.class).toInstance(mockComputer); - } - } -} \ No newline at end of file +} diff --git a/toothpick-sample/src/test/java/toothpick/sample/SimpleEntryPointTestWithRules.java b/toothpick-sample/src/test/java/toothpick/sample/SimpleEntryPointTestWithRules.java deleted file mode 100644 index f1b58a45..00000000 --- a/toothpick-sample/src/test/java/toothpick/sample/SimpleEntryPointTestWithRules.java +++ /dev/null @@ -1,49 +0,0 @@ -package toothpick.sample; - -import org.easymock.EasyMockRule; -import org.easymock.Mock; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.RuleChain; -import org.junit.rules.TestRule; -import toothpick.testing.ToothPickRule; - -import static org.easymock.EasyMock.expect; -import static org.easymock.EasyMock.replay; -import static org.easymock.EasyMock.verify; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; - -public class SimpleEntryPointTestWithRules { - - //do not use @Rule here, we use a chain below - public ToothPickRule toothPickRule = new ToothPickRule(this, "SimpleEntryPoint") - //for testing this can be optional. - //not adding the registry would lead to slightly different code being run compared to production - //to find factories and member injectors. - .setRootRegistryPackage("toothpick.sample"); - - @Rule public TestRule chain = RuleChain.outerRule(toothPickRule).around(new EasyMockRule(this)); - - @Mock private Computer mockComputer; - @Mock private Computer2 mockComputer2; - //do not use test subject from easymock, it by passes toothpick injection - private SimpleEntryPoint simpleEntryPointUnderTest = new SimpleEntryPoint(); - - @Test - public void testMultiply() throws Exception { - //GIVEN - expect(mockComputer.compute()).andReturn(4); - expect(mockComputer2.compute()).andReturn(4); - replay(mockComputer, mockComputer2); - - toothPickRule.inject(simpleEntryPointUnderTest); - - //WHEN - int result = simpleEntryPointUnderTest.multiply(); - - //THEN - assertThat(result, is(48)); - verify(mockComputer); - } -} \ No newline at end of file diff --git a/toothpick-testing-junit4/build.gradle b/toothpick-testing-junit4/build.gradle new file mode 100644 index 00000000..87083498 --- /dev/null +++ b/toothpick-testing-junit4/build.gradle @@ -0,0 +1,14 @@ +apply plugin: 'java-library' + +sourceCompatibility = 1.7 +targetCompatibility = 1.7 + +dependencies { + api project(':toothpick-testing') + implementation deps.junit4 + + testImplementation deps.easymock + testAnnotationProcessor project(':toothpick-compiler') +} + +apply from: rootProject.file('gradle/gradle-mvn-push.gradle') diff --git a/toothpick-testing-junit4/gradle.properties b/toothpick-testing-junit4/gradle.properties new file mode 100644 index 00000000..d5382f6e --- /dev/null +++ b/toothpick-testing-junit4/gradle.properties @@ -0,0 +1,4 @@ +POM_ARTIFACT_ID=toothpick-testing-junit4 +POM_NAME=Toothpick Testing Junit 4 +POM_DESCRIPTION='Junit 4 Testing support for Toothpick' +POM_PACKAGING='jar' diff --git a/toothpick-testing/src/main/java/toothpick/testing/ToothPickRule.java b/toothpick-testing-junit4/src/main/java/toothpick/testing/ToothPickRule.java similarity index 60% rename from toothpick-testing/src/main/java/toothpick/testing/ToothPickRule.java rename to toothpick-testing-junit4/src/main/java/toothpick/testing/ToothPickRule.java index bcf75fc7..3695503d 100644 --- a/toothpick-testing/src/main/java/toothpick/testing/ToothPickRule.java +++ b/toothpick-testing-junit4/src/main/java/toothpick/testing/ToothPickRule.java @@ -5,10 +5,6 @@ import org.junit.runners.model.Statement; import toothpick.Scope; import toothpick.Toothpick; -import toothpick.registries.FactoryRegistry; -import toothpick.registries.FactoryRegistryLocator; -import toothpick.registries.MemberInjectorRegistry; -import toothpick.registries.MemberInjectorRegistryLocator; public class ToothPickRule implements TestRule { private ToothPickTestModule testModule; @@ -50,18 +46,6 @@ public void inject(Object objectUnderTest) { Toothpick.inject(objectUnderTest, scope); } - public ToothPickRule setRootRegistryPackage(String rootRegistryPackageName) { - try { - Class factoryRegistryClass = Class.forName(rootRegistryPackageName + ".FactoryRegistry"); - Class memberInjectorRegistryClass = Class.forName(rootRegistryPackageName + ".MemberInjectorRegistry"); - FactoryRegistryLocator.setRootRegistry((FactoryRegistry) factoryRegistryClass.newInstance()); - MemberInjectorRegistryLocator.setRootRegistry((MemberInjectorRegistry) memberInjectorRegistryClass.newInstance()); - return this; - } catch (Exception e) { - throw new IllegalArgumentException("Invalid package to find registries : " + rootRegistryPackageName, e); - } - } - public T getInstance(Class clazz) { return getInstance(clazz, null); } diff --git a/toothpick-testing/src/main/java/toothpick/testing/ToothPickStatement.java b/toothpick-testing-junit4/src/main/java/toothpick/testing/ToothPickStatement.java similarity index 100% rename from toothpick-testing/src/main/java/toothpick/testing/ToothPickStatement.java rename to toothpick-testing-junit4/src/main/java/toothpick/testing/ToothPickStatement.java diff --git a/toothpick-testing/src/test/java/toothpick/testing/SimpleTest.java b/toothpick-testing-junit4/src/test/java/toothpick/testing/SimpleTest.java similarity index 100% rename from toothpick-testing/src/test/java/toothpick/testing/SimpleTest.java rename to toothpick-testing-junit4/src/test/java/toothpick/testing/SimpleTest.java diff --git a/toothpick-testing/src/test/java/toothpick/testing/TestCustomScopeWithNamedBinding.java b/toothpick-testing-junit4/src/test/java/toothpick/testing/TestCustomScopeWithNamedBinding.java similarity index 96% rename from toothpick-testing/src/test/java/toothpick/testing/TestCustomScopeWithNamedBinding.java rename to toothpick-testing-junit4/src/test/java/toothpick/testing/TestCustomScopeWithNamedBinding.java index 05439f53..7965eabb 100644 --- a/toothpick-testing/src/test/java/toothpick/testing/TestCustomScopeWithNamedBinding.java +++ b/toothpick-testing-junit4/src/test/java/toothpick/testing/TestCustomScopeWithNamedBinding.java @@ -11,7 +11,7 @@ import static org.junit.Assert.assertThat; public class TestCustomScopeWithNamedBinding { - @Rule public ToothPickRule toothPickRule = new ToothPickRule(this, "Foo").setRootRegistryPackage("toothpick.testing"); + @Rule public ToothPickRule toothPickRule = new ToothPickRule(this, "Foo"); EntryPoint entryPoint; @After diff --git a/toothpick-testing/src/test/java/toothpick/testing/TestInjectionAndGetInstance.java b/toothpick-testing-junit4/src/test/java/toothpick/testing/TestInjectionAndGetInstance.java similarity index 87% rename from toothpick-testing/src/test/java/toothpick/testing/TestInjectionAndGetInstance.java rename to toothpick-testing-junit4/src/test/java/toothpick/testing/TestInjectionAndGetInstance.java index fb7ac77d..d76ad6e2 100644 --- a/toothpick-testing/src/test/java/toothpick/testing/TestInjectionAndGetInstance.java +++ b/toothpick-testing-junit4/src/test/java/toothpick/testing/TestInjectionAndGetInstance.java @@ -10,7 +10,7 @@ import static org.junit.Assert.assertThat; public class TestInjectionAndGetInstance { - @Rule public ToothPickRule toothPickRule = new ToothPickRule(this, "Foo").setRootRegistryPackage("toothpick.testing"); + @Rule public ToothPickRule toothPickRule = new ToothPickRule(this, "Foo"); EntryPoint entryPoint; @After @@ -43,12 +43,12 @@ public void testInject() throws Exception { assertThat(entryPoint.dependency, notNullValue()); } - public static class EntryPoint { + static class EntryPoint { @Inject Dependency dependency; } - public static class Dependency { - @Inject public Dependency() { + static class Dependency { + @Inject Dependency() { } } } diff --git a/toothpick-testing/src/test/java/toothpick/testing/TestMocking.java b/toothpick-testing-junit4/src/test/java/toothpick/testing/TestMocking.java similarity index 96% rename from toothpick-testing/src/test/java/toothpick/testing/TestMocking.java rename to toothpick-testing-junit4/src/test/java/toothpick/testing/TestMocking.java index 8cfd2138..467e27e7 100644 --- a/toothpick-testing/src/test/java/toothpick/testing/TestMocking.java +++ b/toothpick-testing-junit4/src/test/java/toothpick/testing/TestMocking.java @@ -18,7 +18,7 @@ import static org.junit.Assert.assertThat; public class TestMocking { - @Rule public ToothPickRule toothPickRule = new ToothPickRule(this, "Foo").setRootRegistryPackage("toothpick.testing"); + @Rule public ToothPickRule toothPickRule = new ToothPickRule(this, "Foo"); @Rule public TestRule chain = RuleChain.outerRule(toothPickRule).around(new EasyMockRule(this)); EntryPoint entryPoint; diff --git a/toothpick-testing/src/test/java/toothpick/testing/TestScopeName.java b/toothpick-testing-junit4/src/test/java/toothpick/testing/TestScopeName.java similarity index 100% rename from toothpick-testing/src/test/java/toothpick/testing/TestScopeName.java rename to toothpick-testing-junit4/src/test/java/toothpick/testing/TestScopeName.java diff --git a/toothpick-testing/src/test/java/toothpick/testing/ToothpickRuleTest.java b/toothpick-testing-junit4/src/test/java/toothpick/testing/ToothpickRuleTest.java similarity index 85% rename from toothpick-testing/src/test/java/toothpick/testing/ToothpickRuleTest.java rename to toothpick-testing-junit4/src/test/java/toothpick/testing/ToothpickRuleTest.java index 5712817a..f956494f 100644 --- a/toothpick-testing/src/test/java/toothpick/testing/ToothpickRuleTest.java +++ b/toothpick-testing-junit4/src/test/java/toothpick/testing/ToothpickRuleTest.java @@ -29,9 +29,4 @@ public void testInjectAndGetInstance() { public void testMock() { assertThat(JUnitCore.runClasses(TestMocking.class).wasSuccessful(), is(true)); } - - @Test - public void testBadRegistry() { - assertThat(JUnitCore.runClasses(TestBadRegistry.class).wasSuccessful(), is(true)); - } } diff --git a/toothpick-testing-junit5/build.gradle b/toothpick-testing-junit5/build.gradle new file mode 100644 index 00000000..667e43ee --- /dev/null +++ b/toothpick-testing-junit5/build.gradle @@ -0,0 +1,20 @@ +apply plugin: 'java-library' + +sourceCompatibility = 1.7 +targetCompatibility = 1.7 + +dependencies { + api project(':toothpick-testing') + implementation deps.junit5_api + + testRuntimeOnly deps.junit5_engine + testImplementation deps.easymock + testImplementation deps.hamcrest + testAnnotationProcessor project(':toothpick-compiler') +} + +test { + useJUnitPlatform() +} + +apply from: rootProject.file('gradle/gradle-mvn-push.gradle') diff --git a/toothpick-testing-junit5/gradle.properties b/toothpick-testing-junit5/gradle.properties new file mode 100644 index 00000000..42dae8b4 --- /dev/null +++ b/toothpick-testing-junit5/gradle.properties @@ -0,0 +1,4 @@ +POM_ARTIFACT_ID=toothpick-testing-junit5 +POM_NAME=Toothpick Testing Junit 5 +POM_DESCRIPTION='Junit 5 Testing support for Toothpick' +POM_PACKAGING='jar' diff --git a/toothpick-testing-junit5/src/main/java/toothpick/testing/ToothPickExtension.java b/toothpick-testing-junit5/src/main/java/toothpick/testing/ToothPickExtension.java new file mode 100644 index 00000000..77d87229 --- /dev/null +++ b/toothpick-testing-junit5/src/main/java/toothpick/testing/ToothPickExtension.java @@ -0,0 +1,56 @@ +package toothpick.testing; + +import org.junit.jupiter.api.extension.AfterEachCallback; +import org.junit.jupiter.api.extension.ExtensionContext; +import toothpick.Scope; +import toothpick.Toothpick; + +public class ToothPickExtension implements AfterEachCallback { + + private final ToothPickTestModule testModule; + private Scope scope; + + public ToothPickExtension(Object test) { + this(test, null); + } + + public ToothPickExtension(Object test, Object scopeName) { + this.testModule = new ToothPickTestModule(test); + if (scopeName != null) { + setScopeName(scopeName); + } + } + + @Override + public void afterEach(ExtensionContext context) throws Exception { + Toothpick.reset(); + } + + public void setScopeName(Object scopeName) { + if (scope != null) { + throw new IllegalStateException("scope is already initialized, use a constructor without a scope name for the rule."); + } + scope = Toothpick.openScope(scopeName); + scope.installTestModules(testModule); + } + + public ToothPickTestModule getTestModule() { + return testModule; + } + + public Scope getScope() { + return scope; + } + + public void inject(Object objectUnderTest) { + Toothpick.inject(objectUnderTest, scope); + } + + public T getInstance(Class clazz) { + return getInstance(clazz, null); + } + + public T getInstance(Class clazz, String name) { + return scope.getInstance(clazz, name); + } +} diff --git a/toothpick-testing-junit5/src/test/java/toothpick/testing/EasyMockExtension.java b/toothpick-testing-junit5/src/test/java/toothpick/testing/EasyMockExtension.java new file mode 100644 index 00000000..c6391bb3 --- /dev/null +++ b/toothpick-testing-junit5/src/test/java/toothpick/testing/EasyMockExtension.java @@ -0,0 +1,19 @@ +package toothpick.testing; + +import org.easymock.EasyMockSupport; +import org.junit.jupiter.api.extension.BeforeEachCallback; +import org.junit.jupiter.api.extension.ExtensionContext; + +public class EasyMockExtension implements BeforeEachCallback { + + private final Object test; + + public EasyMockExtension(Object test) { + this.test = test; + } + + @Override + public void beforeEach(ExtensionContext context) throws Exception { + EasyMockSupport.injectMocks(test); + } +} diff --git a/toothpick-testing-junit5/src/test/java/toothpick/testing/SimpleTest.java b/toothpick-testing-junit5/src/test/java/toothpick/testing/SimpleTest.java new file mode 100644 index 00000000..8605759b --- /dev/null +++ b/toothpick-testing-junit5/src/test/java/toothpick/testing/SimpleTest.java @@ -0,0 +1,34 @@ +package toothpick.testing; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.RegisterExtension; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +class SimpleTest { + + private static boolean wasRun = false; + + @RegisterExtension ToothPickExtension toothPickExtension = new ToothPickExtension(this) { + @Override + public void afterEach(ExtensionContext context) throws Exception { + super.afterEach(context); + wasRun = true; + } + }; + + @Test + void test() { + // THEN + assertThat(wasRun, is(false)); + } + + @AfterAll + static void tearDownAll() { + // THEN + assertThat(wasRun, is(true)); + } +} diff --git a/toothpick-testing-junit5/src/test/java/toothpick/testing/TestCustomScopeWithNamedBinding.java b/toothpick-testing-junit5/src/test/java/toothpick/testing/TestCustomScopeWithNamedBinding.java new file mode 100644 index 00000000..676ced44 --- /dev/null +++ b/toothpick-testing-junit5/src/test/java/toothpick/testing/TestCustomScopeWithNamedBinding.java @@ -0,0 +1,41 @@ +package toothpick.testing; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import toothpick.config.Module; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsNull.notNullValue; +import static org.hamcrest.core.IsSame.sameInstance; + +class TestCustomScopeWithNamedBinding { + + @RegisterExtension ToothPickExtension toothPickExtension = new ToothPickExtension(this, "Foo"); + + private EntryPoint entryPoint; + + @Test + void testGetInstance_shouldReturnNamedBinding_whenAskingNamedBinding() throws Exception { + //GIVEN + ModuleWithNamedBindings moduleWithNamedBindings = new ModuleWithNamedBindings(); + toothPickExtension.getScope().installModules(moduleWithNamedBindings); + + //WHEN + entryPoint = toothPickExtension.getInstance(EntryPoint.class, "Foo"); + + //THEN + assertThat(entryPoint, notNullValue()); + assertThat(entryPoint, sameInstance(moduleWithNamedBindings.instance)); + } + + private static class EntryPoint { + } + + private static class ModuleWithNamedBindings extends Module { + EntryPoint instance = new EntryPoint(); + + ModuleWithNamedBindings() { + bind(EntryPoint.class).withName("Foo").toInstance(instance); + } + } +} diff --git a/toothpick-testing-junit5/src/test/java/toothpick/testing/TestInjectionAndGetInstance.java b/toothpick-testing-junit5/src/test/java/toothpick/testing/TestInjectionAndGetInstance.java new file mode 100644 index 00000000..92b3b019 --- /dev/null +++ b/toothpick-testing-junit5/src/test/java/toothpick/testing/TestInjectionAndGetInstance.java @@ -0,0 +1,49 @@ +package toothpick.testing; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import javax.inject.Inject; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsNull.notNullValue; + +class TestInjectionAndGetInstance { + + @RegisterExtension ToothPickExtension toothPickExtension = new ToothPickExtension(this, "Foo"); + + private EntryPoint entryPoint; + + @Test + void testGetInstance() { + //GIVEN + //WHEN + entryPoint = toothPickExtension.getInstance(EntryPoint.class); + + //THEN + assertThat(entryPoint, notNullValue()); + assertThat(entryPoint.dependency, notNullValue()); + } + + @Test + void testInject() { + //GIVEN + EntryPoint entryPoint = new EntryPoint(); + + //WHEN + toothPickExtension.inject(entryPoint); + + //THEN + assertThat(entryPoint, notNullValue()); + assertThat(entryPoint.dependency, notNullValue()); + } + + static class EntryPoint { + @Inject Dependency dependency; + } + + static class Dependency { + @Inject Dependency() { + } + } +} diff --git a/toothpick-testing-junit5/src/test/java/toothpick/testing/TestMocking.java b/toothpick-testing-junit5/src/test/java/toothpick/testing/TestMocking.java new file mode 100644 index 00000000..1f8871f7 --- /dev/null +++ b/toothpick-testing-junit5/src/test/java/toothpick/testing/TestMocking.java @@ -0,0 +1,51 @@ +package toothpick.testing; + +import org.easymock.Mock; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import javax.inject.Inject; + +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsNull.notNullValue; + +class TestMocking { + + @RegisterExtension ToothPickExtension toothPickExtension = new ToothPickExtension(this, "Foo"); + @RegisterExtension EasyMockExtension easyMockExtension = new EasyMockExtension(this); + + @Mock Dependency dependency; + + private EntryPoint entryPoint; + + @Test + void testMock() { + //GIVEN + expect(dependency.num()).andReturn(2); + replay(dependency); + + //WHEN + entryPoint = toothPickExtension.getInstance(EntryPoint.class); + int num = entryPoint.dependency.num(); + + //THEN + verify(dependency); + assertThat(entryPoint, notNullValue()); + assertThat(entryPoint.dependency, notNullValue()); + assertThat(num, is(2)); + } + + public static class EntryPoint { + @Inject Dependency dependency; + } + + public static class Dependency { + public int num() { + return 1; + } + } +} diff --git a/toothpick-testing-junit5/src/test/java/toothpick/testing/TestScopeName.java b/toothpick-testing-junit5/src/test/java/toothpick/testing/TestScopeName.java new file mode 100644 index 00000000..8bfac504 --- /dev/null +++ b/toothpick-testing-junit5/src/test/java/toothpick/testing/TestScopeName.java @@ -0,0 +1,51 @@ +package toothpick.testing; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.function.Executable; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsNull.notNullValue; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class TestScopeName { + + @RegisterExtension ToothPickExtension toothPickExtension = new ToothPickExtension(this, "Foo"); + @RegisterExtension ToothPickExtension toothPickRuleWithoutScopeName = new ToothPickExtension(this); + + @Test + void testSetScopeName_shouldFail_whenScopeNameWasAlreadySet() { + assertThrows(IllegalStateException.class, new Executable() { + @Override + public void execute() { + toothPickExtension.setScopeName("Bar"); + } + }); + } + + @Test + void testSetScopeName_shouldFail_whenScopeNameAlreadyContainsATestModule() { + assertThrows(IllegalStateException.class, new Executable() { + @Override + public void execute() { + toothPickRuleWithoutScopeName.setScopeName("Foo"); + } + }); + } + + @Test + void testScopeNameSetByConstruction() { + assertThat(toothPickExtension.getScope(), notNullValue()); + assertThat(toothPickExtension.getScope().getName(), is((Object) "Foo")); + assertThat(toothPickExtension.getTestModule(), notNullValue()); + } + + @Test + void testSetScopeName() { + toothPickRuleWithoutScopeName.setScopeName("Bar"); + assertThat(toothPickRuleWithoutScopeName.getScope(), notNullValue()); + assertThat(toothPickRuleWithoutScopeName.getScope().getName(), is((Object) "Bar")); + assertThat(toothPickRuleWithoutScopeName.getTestModule(), notNullValue()); + } +} diff --git a/toothpick-testing/build.gradle b/toothpick-testing/build.gradle index 773e7069..3b4c743f 100644 --- a/toothpick-testing/build.gradle +++ b/toothpick-testing/build.gradle @@ -3,21 +3,10 @@ apply plugin: 'java-library' sourceCompatibility = 1.7 targetCompatibility = 1.7 -configurations { - testAnnotationProcessor -} - dependencies { api project(':toothpick-runtime') - implementation deps.junit - - testImplementation deps.easymock - testAnnotationProcessor project(':toothpick-compiler') -} - -compileTestJava { - options.annotationProcessorPath = configurations.testAnnotationProcessor - options.compilerArgs = ['-Atoothpick_registry_package_name=toothpick.testing',] + + testImplementation deps.junit4 } apply from: rootProject.file('gradle/gradle-mvn-push.gradle') diff --git a/toothpick-testing/gradle.properties b/toothpick-testing/gradle.properties index 850c1d99..b826afa7 100644 --- a/toothpick-testing/gradle.properties +++ b/toothpick-testing/gradle.properties @@ -1,4 +1,4 @@ POM_ARTIFACT_ID=toothpick-testing POM_NAME=Toothpick Testing POM_DESCRIPTION='Testing support for Toothpick' -POM_PACKAGING='jar' \ No newline at end of file +POM_PACKAGING='jar' diff --git a/toothpick-testing/src/test/java/toothpick/testing/TestBadRegistry.java b/toothpick-testing/src/test/java/toothpick/testing/TestBadRegistry.java deleted file mode 100644 index 70e03967..00000000 --- a/toothpick-testing/src/test/java/toothpick/testing/TestBadRegistry.java +++ /dev/null @@ -1,20 +0,0 @@ -package toothpick.testing; - -import org.junit.AfterClass; -import org.junit.Test; -import toothpick.Toothpick; - -public class TestBadRegistry { - - @AfterClass - public static void tearDown() throws Exception { - //needs to be performed after test execution - //not before as rule are initialized before @Before - Toothpick.reset(); - } - - @Test(expected = IllegalArgumentException.class) - public void test() throws Exception { - new ToothPickRule(this, "Foo").setRootRegistryPackage("foo"); - } -} diff --git a/toothpick/build.gradle b/toothpick/build.gradle index b464e5bf..67188dee 100644 --- a/toothpick/build.gradle +++ b/toothpick/build.gradle @@ -6,7 +6,7 @@ targetCompatibility = 1.7 dependencies { implementation deps.inject - testImplementation deps.junit + testImplementation deps.junit4 } apply from: rootProject.file('gradle/gradle-mvn-push.gradle') \ No newline at end of file diff --git a/toothpick/gradle.properties b/toothpick/gradle.properties index 07eeb3c3..719b3760 100644 --- a/toothpick/gradle.properties +++ b/toothpick/gradle.properties @@ -1,4 +1,4 @@ POM_ARTIFACT_ID=toothpick POM_NAME=Toothpick POM_DESCRIPTION='Interfaces, public API of toothpick' -POM_PACKAGING='jar' \ No newline at end of file +POM_PACKAGING='jar' diff --git a/toothpick/src/main/java/toothpick/Factory.java b/toothpick/src/main/java/toothpick/Factory.java index 4a94643f..982739da 100644 --- a/toothpick/src/main/java/toothpick/Factory.java +++ b/toothpick/src/main/java/toothpick/Factory.java @@ -4,7 +4,7 @@ /** * Creates instances of classes. - * Factories are discovered via a {@code FactoryRegistry}. + * Factories are discovered via the {@code FactoryLocator}. * Implementations are generated during annotation processing. * As soon as a class as an {@link javax.inject.Inject} annotated constructor, * a factory is created. All classes that need to be created via toothpick diff --git a/toothpick/src/main/java/toothpick/MemberInjector.java b/toothpick/src/main/java/toothpick/MemberInjector.java index 58145d9a..1dbfe2a3 100644 --- a/toothpick/src/main/java/toothpick/MemberInjector.java +++ b/toothpick/src/main/java/toothpick/MemberInjector.java @@ -3,7 +3,7 @@ /** * Inject member of an instance of a class. * All injected members are gonna be obtained in the scope of the current scope. - * MemberInjector are discovered via a {@code AbstractMemberInjectorRegistry}. + * MemberInjector are discovered via the {@code MemberInjectorLocator}. * Implementations are generated during annotation processing. * As soon as a class as an {@link javax.inject.Inject} annotated field or method, * a member scope is created. All classes that need to be injected via toothpick diff --git a/toothpick/src/main/java/toothpick/registries/FactoryRegistry.java b/toothpick/src/main/java/toothpick/registries/FactoryRegistry.java deleted file mode 100644 index a481e23b..00000000 --- a/toothpick/src/main/java/toothpick/registries/FactoryRegistry.java +++ /dev/null @@ -1,15 +0,0 @@ -package toothpick.registries; - -import toothpick.Factory; - -/** - * A component that can retrieve a {@link Factory} for a given class. - * The annotation processor can generate classes that implement this interface - * if it passed some arguments. This interface will not really be used by developers, - * they will use once each of the generated subclasses. - * - * See the FactoryRegistryLocator java docs in toothpick-runtime package. - */ -public interface FactoryRegistry { - Factory getFactory(Class clazz); -} diff --git a/toothpick/src/main/java/toothpick/registries/MemberInjectorRegistry.java b/toothpick/src/main/java/toothpick/registries/MemberInjectorRegistry.java deleted file mode 100644 index 42369a3d..00000000 --- a/toothpick/src/main/java/toothpick/registries/MemberInjectorRegistry.java +++ /dev/null @@ -1,15 +0,0 @@ -package toothpick.registries; - -import toothpick.MemberInjector; - -/** - * A component that can retrieve a {@link MemberInjector} for a given class. - * The annotation processor can generate classes that implement this interface - * if it passed some arguments. This interface will not really be used by developers, - * they will use once each of the generated subclasses. - * - * See the MemberInjectorLocator java docs in toothpick-runtime package. - */ -public interface MemberInjectorRegistry { - MemberInjector getMemberInjector(Class clazz); -}