├── popkorn-androidx-viewmodel ├── src │ ├── androidMain │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ │ ├── PopKornViewModelFactory.kt │ │ │ └── ViewModel.kt │ └── androidTest │ │ └── kotlin │ │ ├── data │ │ ├── TestViewModel.kt │ │ ├── TestViewModelResolver.kt │ │ ├── TestViewModelWithParams.kt │ │ ├── TestViewModelResolverPool.kt │ │ └── TestViewModelProviderPool.kt │ │ └── ViewModelTest.kt └── build.gradle.kts ├── .gitignore ├── .editorconfig ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── popkorn-compiler ├── src │ ├── main │ │ ├── resources │ │ │ └── META-INF │ │ │ │ ├── services │ │ │ │ └── javax.annotation.processing.Processor │ │ │ │ └── gradle │ │ │ │ └── incremental.annotation.processors │ │ └── kotlin │ │ │ └── cc │ │ │ └── popkorn │ │ │ └── compiler │ │ │ ├── PopKornException.kt │ │ │ ├── models │ │ │ └── DefaultImplementation.kt │ │ │ ├── utils │ │ │ ├── StringExtensions.kt │ │ │ ├── Logger.kt │ │ │ └── ElementExtensions.kt │ │ │ ├── PopKornCompiler.kt │ │ │ └── generators │ │ │ ├── MappingGenerator.kt │ │ │ ├── ResolverGenerator.kt │ │ │ └── ProviderGenerator.kt │ └── test │ │ └── kotlin │ │ └── cc │ │ └── popkorn │ │ └── compiler │ │ ├── utils │ │ ├── JavaParam.kt │ │ ├── JavaMethod.kt │ │ └── JavaClass.kt │ │ ├── PopKornCompilerTest.kt │ │ ├── DirectInjectableTests.kt │ │ └── ProvidedInjectableTests.kt └── build.gradle.kts ├── popkorn ├── src │ ├── commonTest │ │ └── kotlin │ │ │ ├── data │ │ │ ├── TestInterfaceNoResolver.kt │ │ │ ├── TestClassNoProvider.kt │ │ │ ├── TestClassByNew.kt │ │ │ ├── TestClassByUse.kt │ │ │ ├── TestClassByApp.kt │ │ │ ├── TestClassByHolder.kt │ │ │ ├── TestClassByNewAssisted.kt │ │ │ ├── TestCascadeClass.kt │ │ │ ├── TestInterface.kt │ │ │ ├── TestClassByNewAssisted2.kt │ │ │ ├── TestResolverPool.kt │ │ │ └── TestProviderPool.kt │ │ │ ├── PopKornTest.kt │ │ │ ├── ClientTests.kt │ │ │ ├── ResolverTests.kt │ │ │ ├── CreationTests.kt │ │ │ └── RuntimeTests.kt │ ├── commonMain │ │ └── kotlin │ │ │ ├── core │ │ │ ├── exceptions │ │ │ │ ├── AlreadyInjectableException.kt │ │ │ │ ├── InstanceNotFoundException.kt │ │ │ │ ├── PopKornNotInitializedException.kt │ │ │ │ ├── DefaultMethodNotFoundException.kt │ │ │ │ ├── DefaultConstructorNotFoundException.kt │ │ │ │ ├── NonExistingClassException.kt │ │ │ │ ├── DefaultImplementationNotFoundException.kt │ │ │ │ ├── HolderNotProvidedException.kt │ │ │ │ ├── ProviderNotFoundException.kt │ │ │ │ ├── ResolverNotFoundException.kt │ │ │ │ └── AssistedNotFoundException.kt │ │ │ ├── model │ │ │ │ ├── Empty.kt │ │ │ │ ├── Environment.kt │ │ │ │ └── Instance.kt │ │ │ ├── Scope.kt │ │ │ ├── Propagation.kt │ │ │ ├── config │ │ │ │ ├── InjectorConfig.kt │ │ │ │ ├── CreatorConfig.kt │ │ │ │ └── Parameters.kt │ │ │ ├── InjectorWithPreference.kt │ │ │ └── Injector.kt │ │ │ ├── instances │ │ │ ├── Purgeable.kt │ │ │ ├── Instances.kt │ │ │ ├── NewInstances.kt │ │ │ ├── PersistentInstances.kt │ │ │ ├── RuntimeInstances.kt │ │ │ ├── VolatileInstances.kt │ │ │ └── HolderInstances.kt │ │ │ ├── mapping │ │ │ └── Mapping.kt │ │ │ ├── resolvers │ │ │ ├── Resolver.kt │ │ │ └── RuntimeResolver.kt │ │ │ ├── pools │ │ │ ├── ProviderPool.kt │ │ │ ├── ResolverPool.kt │ │ │ ├── MappingProviderPool.kt │ │ │ └── MappingResolverPool.kt │ │ │ ├── annotations │ │ │ ├── Exclude.kt │ │ │ ├── Assisted.kt │ │ │ ├── ForEnvironments.kt │ │ │ ├── WithEnvironment.kt │ │ │ ├── Alias.kt │ │ │ ├── Injectable.kt │ │ │ └── InjectableProvider.kt │ │ │ ├── providers │ │ │ └── Provider.kt │ │ │ ├── InjectorManager.kt │ │ │ ├── Constants.kt │ │ │ ├── Platform.kt │ │ │ ├── InjectorController.kt │ │ │ └── PopKorn.kt │ ├── jvmMain │ │ └── kotlin │ │ │ ├── pools │ │ │ ├── Utils.kt │ │ │ ├── ReflectionResolverPool.kt │ │ │ └── ReflectionProviderPool.kt │ │ │ ├── config │ │ │ ├── InjectorConfigBuilder.kt │ │ │ └── CreatorConfigBuilder.kt │ │ │ ├── Platform.kt │ │ │ ├── InjectorJVM.kt │ │ │ └── PopKornCompat.kt │ ├── jsMain │ │ └── kotlin │ │ │ ├── PopKornCompat.kt │ │ │ ├── Platform.kt │ │ │ ├── config │ │ │ ├── InjectorConfigBuilder.kt │ │ │ └── CreatorConfigBuilder.kt │ │ │ └── InjectorJS.kt │ ├── nativeMain │ │ └── kotlin │ │ │ ├── PopKornCompat.kt │ │ │ └── Platform.kt │ └── iosMain │ │ └── kotlin │ │ ├── ReferenceClass.kt │ │ ├── PopKornCompat.kt │ │ ├── config │ │ ├── InjectorConfigBuilder.kt │ │ └── CreatorConfigBuilder.kt │ │ ├── Platform.kt │ │ └── InjectorObjC.kt └── build.gradle.kts ├── settings.gradle.kts ├── popkorn-example ├── src │ └── main │ │ ├── kotlin │ │ └── cc │ │ │ └── popkorn │ │ │ └── example │ │ │ ├── Main.kt │ │ │ ├── model │ │ │ ├── Ri.kt │ │ │ ├── Di.kt │ │ │ ├── D.kt │ │ │ └── R.kt │ │ │ ├── MyString.kt │ │ │ └── Example.kt │ │ └── java │ │ └── cc │ │ └── popkorn │ │ └── example │ │ ├── MyInteger.java │ │ └── ExampleJava.java └── build.gradle.kts ├── gradle.properties ├── .github └── workflows │ └── build.yml ├── samples └── androidx-viewmodel │ ├── build.gradle.kts │ └── src │ └── main │ ├── res │ └── layout │ │ ├── third_activity.xml │ │ ├── second_activity.xml │ │ ├── fragment.xml │ │ └── main_activity.xml │ ├── AndroidManifest.xml │ └── java │ ├── MainActivity.kt │ ├── SecondActivity.kt │ └── ThirdActivity.kt ├── gradlew.bat ├── CHANGELOG.md └── gradlew /popkorn-androidx-viewmodel/src/androidMain/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | local.properties 2 | credentials.properties 3 | build/ 4 | .idea/ 5 | .gradle/ 6 | kotlin-js-store 7 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*.{kt,kts}] 4 | indent_size=4 5 | ktlint_disabled_rules=no-wildcard-imports 6 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corbella83/PopKorn/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /popkorn-compiler/src/main/resources/META-INF/services/javax.annotation.processing.Processor: -------------------------------------------------------------------------------- 1 | cc.popkorn.compiler.PopKornCompiler 2 | -------------------------------------------------------------------------------- /popkorn/src/commonTest/kotlin/data/TestInterfaceNoResolver.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.data 2 | 3 | interface TestInterfaceNoResolver 4 | -------------------------------------------------------------------------------- /popkorn-compiler/src/main/resources/META-INF/gradle/incremental.annotation.processors: -------------------------------------------------------------------------------- 1 | cc.popkorn.compiler.PopKornCompiler,aggregating 2 | -------------------------------------------------------------------------------- /popkorn/src/commonTest/kotlin/data/TestClassNoProvider.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.data 2 | 3 | open class TestClassNoProvider(override val value: String?) : TestInterface 4 | -------------------------------------------------------------------------------- /popkorn-androidx-viewmodel/src/androidTest/kotlin/data/TestViewModel.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.androidx.viewModel.data 2 | 3 | import androidx.lifecycle.ViewModel 4 | 5 | class TestViewModel : ViewModel() 6 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/core/exceptions/AlreadyInjectableException.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.core.exceptions 2 | 3 | class AlreadyInjectableException : RuntimeException("You are trying to add an injectable that is already defined") 4 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/core/exceptions/InstanceNotFoundException.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.core.exceptions 2 | 3 | class InstanceNotFoundException : RuntimeException("Invalid instance. Seems like you didn't call addInjectable") 4 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "PopKorn" 2 | 3 | include(":popkorn") 4 | include(":popkorn-compiler") 5 | include(":popkorn-example") 6 | include(":popkorn-androidx-viewmodel") 7 | 8 | include(":samples:androidx-viewmodel") 9 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/core/exceptions/PopKornNotInitializedException.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.core.exceptions 2 | 3 | class PopKornNotInitializedException : RuntimeException("You must execute PopKornCompatKt.setup(...) before using this library") 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/core/exceptions/DefaultMethodNotFoundException.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.core.exceptions 2 | 3 | class DefaultMethodNotFoundException(element: String) : RuntimeException("Could not find method for default environment at $element") 4 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/core/exceptions/DefaultConstructorNotFoundException.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.core.exceptions 2 | 3 | class DefaultConstructorNotFoundException(element: String) : RuntimeException("Could not find constructor for default environment at $element") 4 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/core/exceptions/NonExistingClassException.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.core.exceptions 2 | 3 | import kotlin.reflect.KClass 4 | 5 | class NonExistingClassException(clazz: KClass<*>) : RuntimeException("Tried to get details of a non existing class: $clazz") 6 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/instances/Purgeable.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.instances 2 | 3 | /** 4 | * Interface that defines if a class is able to be purged 5 | * 6 | * @author Pau Corbella 7 | * @since 2.1.0 8 | */ 9 | internal interface Purgeable { 10 | 11 | fun purge() 12 | } 13 | -------------------------------------------------------------------------------- /popkorn-compiler/src/main/kotlin/cc/popkorn/compiler/PopKornException.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.compiler 2 | 3 | /** 4 | * Exceptions used when compiling PopKorn 5 | * 6 | * @author Pau Corbella 7 | * @since 1.0.0 8 | */ 9 | internal class PopKornException(msg: String) : RuntimeException(msg) 10 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/core/exceptions/DefaultImplementationNotFoundException.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.core.exceptions 2 | 3 | class DefaultImplementationNotFoundException(element: String, options: List) : RuntimeException("Could not find default implementation of $element: ${options.joinToString()}") 4 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/instances/Instances.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.instances 2 | 3 | /** 4 | * Interface that defines how to get an instance from a specific environment 5 | * 6 | * @author Pau Corbella 7 | * @since 1.0.0 8 | */ 9 | internal interface Instances { 10 | 11 | fun size(): Int 12 | } 13 | -------------------------------------------------------------------------------- /popkorn-example/src/main/kotlin/cc/popkorn/example/Main.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.example 2 | 3 | object Main { 4 | 5 | @JvmStatic 6 | fun main(args: Array) { 7 | Example().execute() 8 | println("ok kotlin") 9 | 10 | ExampleJava().execute() 11 | println("ok java") 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/mapping/Mapping.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.mapping 2 | 3 | import kotlin.reflect.KClass 4 | 5 | /** 6 | * Interface that maps any class to any object 7 | * 8 | * @author Pau Corbella 9 | * @since 1.1.0 10 | */ 11 | interface Mapping { 12 | 13 | fun find(original: KClass): Any? 14 | } 15 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/core/exceptions/HolderNotProvidedException.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.core.exceptions 2 | 3 | import cc.popkorn.getName 4 | import kotlin.reflect.KClass 5 | 6 | class HolderNotProvidedException(clazz: KClass<*>) : RuntimeException("To inject ${clazz.getName()} you must provide a holder with inject() { holder(...) }") 7 | -------------------------------------------------------------------------------- /popkorn-example/src/main/java/cc/popkorn/example/MyInteger.java: -------------------------------------------------------------------------------- 1 | package cc.popkorn.example; 2 | 3 | import cc.popkorn.annotations.InjectableProvider; 4 | import cc.popkorn.core.Scope; 5 | 6 | @InjectableProvider(scope = Scope.BY_USE) 7 | public class MyInteger { 8 | 9 | public int create() { 10 | return 54; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/core/exceptions/ProviderNotFoundException.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.core.exceptions 2 | 3 | import cc.popkorn.getName 4 | import kotlin.reflect.KClass 5 | 6 | class ProviderNotFoundException(val clazz: KClass<*>) : RuntimeException("Could not find Provider for this class: ${clazz.getName()}. Did you forget to add @Injectable?") 7 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/core/model/Empty.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.core.model 2 | 3 | /** 4 | * Model class to be used in any constructor/method for Injectable objects 5 | * You can define multiple constructors for different environments with the same parameters 6 | * 7 | * @author Pau Corbella 8 | * @since 1.3.0 9 | */ 10 | class Empty 11 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/core/model/Environment.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.core.model 2 | 3 | /** 4 | * Model class to be used in any constructor/method for Injectable objects 5 | * You can get the environment that is using at the moment 6 | * 7 | * @author Pau Corbella 8 | * @since 1.3.0 9 | */ 10 | class Environment(val value: String?) 11 | -------------------------------------------------------------------------------- /popkorn-example/src/main/kotlin/cc/popkorn/example/model/Ri.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.example.model 2 | 3 | interface R1i 4 | 5 | interface R2i 6 | 7 | interface R3i 8 | 9 | interface R4i 10 | 11 | interface R5i 12 | 13 | interface R6i 14 | 15 | interface R7i 16 | 17 | interface R8i 18 | 19 | interface R9i 20 | 21 | interface R10i 22 | 23 | interface R0i 24 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/core/exceptions/ResolverNotFoundException.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.core.exceptions 2 | 3 | import cc.popkorn.getName 4 | import kotlin.reflect.KClass 5 | 6 | class ResolverNotFoundException(clazz: KClass<*>) : RuntimeException("Could not find Resolver for this class: ${clazz.getName()}. Is this interface being used by an Injectable class?") 7 | -------------------------------------------------------------------------------- /popkorn-example/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | kotlin("jvm") 3 | kotlin("kapt") 4 | application 5 | } 6 | 7 | application { 8 | mainClass.set("cc.popkorn.example.Main") 9 | } 10 | 11 | kotlin { 12 | jvmToolchain(8) 13 | } 14 | 15 | dependencies { 16 | implementation(project(":popkorn")) 17 | kapt(project(":popkorn-compiler")) 18 | 19 | implementation(kotlin("stdlib")) 20 | } 21 | -------------------------------------------------------------------------------- /popkorn-compiler/src/main/kotlin/cc/popkorn/compiler/models/DefaultImplementation.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.compiler.models 2 | 3 | import javax.lang.model.element.TypeElement 4 | 5 | /** 6 | * Data class defining a class and its available environments 7 | * 8 | * @author Pau Corbella 9 | * @since 1.0.0 10 | */ 11 | internal data class DefaultImplementation(val element: TypeElement, val environments: List) 12 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/core/model/Instance.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.core.model 2 | 3 | import kotlin.reflect.KClass 4 | 5 | /** 6 | * Model class to be used to identify an instance 7 | * 8 | * @author Pau Corbella 9 | * @since 2.1.0 10 | */ 11 | internal data class Instance( 12 | val instance: T, 13 | val type: KClass = instance::class, 14 | val environment: String? = null 15 | ) 16 | -------------------------------------------------------------------------------- /popkorn-androidx-viewmodel/src/androidTest/kotlin/data/TestViewModelResolver.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.androidx.viewModel.data 2 | 3 | import cc.popkorn.resolvers.Resolver 4 | import kotlin.reflect.KClass 5 | 6 | class TestViewModelResolver : Resolver { 7 | override fun resolve(environment: String?): KClass { 8 | return TestViewModelWithParams::class 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/resolvers/Resolver.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.resolvers 2 | 3 | import kotlin.reflect.KClass 4 | 5 | /** 6 | * Interface that defines how a certain interface can be resolved 7 | * T must be an interface, while 'out T' must be a class 8 | * 9 | * @author Pau Corbella 10 | * @since 1.0.0 11 | */ 12 | interface Resolver { 13 | 14 | fun resolve(environment: String?): KClass 15 | } 16 | -------------------------------------------------------------------------------- /popkorn-example/src/main/kotlin/cc/popkorn/example/MyString.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.example 2 | 3 | import cc.popkorn.annotations.ForEnvironments 4 | import cc.popkorn.annotations.InjectableProvider 5 | import cc.popkorn.core.Scope 6 | 7 | @InjectableProvider(Scope.BY_APP) 8 | class MyString { 9 | 10 | fun createPro(): String = "Hello Pro" 11 | 12 | @ForEnvironments("pre") 13 | fun createPre(): String = "Hello Pre" 14 | } 15 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | libraryGroup=cc.popkorn 2 | 3 | libraryVersion=2.3.1 4 | 5 | systemProp.kotlinVersion=1.8.21 6 | 7 | org.gradle.jvmargs=-Xmx2048m 8 | org.gradle.caching=true 9 | org.gradle.parallel=true 10 | org.gradle.vfs.watch=true 11 | 12 | kotlin.code.style=official 13 | 14 | kotlin.mpp.enableGranularSourceSetsMetadata=true 15 | 16 | kotlin.native.enableDependencyPropagation=false 17 | 18 | android.useAndroidX=true 19 | kotlin.js.compiler=ir -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/core/exceptions/AssistedNotFoundException.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.core.exceptions 2 | 3 | import cc.popkorn.getName 4 | import kotlin.reflect.KClass 5 | 6 | class AssistedNotFoundException(clazz: KClass<*>, environment: String?) : 7 | RuntimeException("Could not find instance for this class: ${clazz.getName()} ${if (environment != null) "for environment $environment" else ""}. Please provide one using: inject() { assist(...) }") 8 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/pools/ProviderPool.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.pools 2 | 3 | import cc.popkorn.providers.Provider 4 | import kotlin.reflect.KClass 5 | 6 | /** 7 | * Interface to define how to obtain the providers 8 | * 9 | * @author Pau Corbella 10 | * @since 1.0.0 11 | */ 12 | interface ProviderPool { 13 | 14 | fun isPresent(clazz: KClass): Boolean 15 | 16 | fun create(clazz: KClass): Provider 17 | } 18 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/pools/ResolverPool.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.pools 2 | 3 | import cc.popkorn.resolvers.Resolver 4 | import kotlin.reflect.KClass 5 | 6 | /** 7 | * Interface to define how to obtain the resolvers 8 | * 9 | * @author Pau Corbella 10 | * @since 1.0.0 11 | */ 12 | interface ResolverPool { 13 | 14 | fun isPresent(clazz: KClass): Boolean 15 | 16 | fun create(clazz: KClass): Resolver 17 | } 18 | -------------------------------------------------------------------------------- /popkorn-example/src/main/kotlin/cc/popkorn/example/model/Di.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.example.model 2 | 3 | import cc.popkorn.annotations.Exclude 4 | 5 | interface DiA 6 | 7 | interface DiB 8 | 9 | interface DiC 10 | 11 | interface Wrapper { 12 | interface DiD 13 | } 14 | 15 | interface DiE 16 | 17 | interface DiF 18 | 19 | @Exclude 20 | interface DiG 21 | 22 | abstract class DaH : DiE 23 | 24 | abstract class DaI : DaH(), DiF 25 | 26 | abstract class DaJ 27 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/annotations/Exclude.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.annotations 2 | 3 | /** 4 | * This annotation applies ONLY for interfaces and abstract classes. It annotates the desired interfaces that 5 | * don't want to add as injectable. Needs to be BINARY to be detected between modules 6 | * when compiling 7 | * 8 | * @author Pau Corbella 9 | * @since 1.0.0 10 | */ 11 | @Target(AnnotationTarget.CLASS) 12 | @Retention(AnnotationRetention.BINARY) 13 | annotation class Exclude 14 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/annotations/Assisted.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.annotations 2 | 3 | /** 4 | * Annotation to be used in any constructor parameter that is not injectable and will be provided in 5 | * runtime (Can only be used in a class with BY_NEW scope). 6 | * 7 | * constructor(@Assisted id:Long, param1:Interface) 8 | * 9 | * @author Pau Corbella 10 | * @since 2.1.0 11 | */ 12 | @Target(AnnotationTarget.VALUE_PARAMETER) 13 | @Retention(AnnotationRetention.SOURCE) 14 | annotation class Assisted 15 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/providers/Provider.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.providers 2 | 3 | import cc.popkorn.InjectorManager 4 | import cc.popkorn.core.Scope 5 | import cc.popkorn.core.config.Parameters 6 | 7 | /** 8 | * Interface that defines how a certain class can be created 9 | * T cannot be an interface, only classes 10 | * 11 | * @author Pau Corbella 12 | * @since 1.0.0 13 | */ 14 | interface Provider { 15 | 16 | fun create(injector: InjectorManager, assisted: Parameters, environment: String?): T 17 | 18 | fun scope(): Scope 19 | } 20 | -------------------------------------------------------------------------------- /popkorn-compiler/src/main/kotlin/cc/popkorn/compiler/utils/StringExtensions.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.compiler.utils 2 | 3 | /** 4 | * Splits this qualified class into package (first) and class name (second) 5 | * 6 | * @return Returns a Pair containing the package (first) and class name (second) 7 | */ 8 | internal fun String.splitPackage(): Pair { 9 | val split = split(".") 10 | return if (split.size == 1) { 11 | Pair("", split.single()) 12 | } else { 13 | Pair(split.dropLast(1).joinToString("."), split.last()) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /popkorn/src/commonTest/kotlin/data/TestClassByNew.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.data 2 | 3 | import cc.popkorn.InjectorManager 4 | import cc.popkorn.core.Scope 5 | import cc.popkorn.core.config.Parameters 6 | import cc.popkorn.providers.Provider 7 | 8 | class TestClassByNew(environment: String?) : TestClassNoProvider(environment) 9 | 10 | class TestClassByNewProvider : Provider { 11 | override fun create(injector: InjectorManager, assisted: Parameters, environment: String?): TestClassByNew = TestClassByNew(environment) 12 | override fun scope() = Scope.BY_NEW 13 | } 14 | -------------------------------------------------------------------------------- /popkorn/src/commonTest/kotlin/data/TestClassByUse.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.data 2 | 3 | import cc.popkorn.InjectorManager 4 | import cc.popkorn.core.Scope 5 | import cc.popkorn.core.config.Parameters 6 | import cc.popkorn.providers.Provider 7 | 8 | class TestClassByUse(environment: String?) : TestClassNoProvider(environment) 9 | 10 | class TestClassByUseProvider : Provider { 11 | override fun create(injector: InjectorManager, assisted: Parameters, environment: String?): TestClassByUse = TestClassByUse(environment) 12 | override fun scope() = Scope.BY_USE 13 | } 14 | -------------------------------------------------------------------------------- /popkorn/src/commonTest/kotlin/data/TestClassByApp.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.data 2 | 3 | import cc.popkorn.InjectorManager 4 | import cc.popkorn.core.Scope 5 | import cc.popkorn.core.config.Parameters 6 | import cc.popkorn.providers.Provider 7 | 8 | open class TestClassByApp(environment: String?) : TestClassNoProvider(environment) 9 | 10 | class TestClassByAppProvider : Provider { 11 | override fun create(injector: InjectorManager, assisted: Parameters, environment: String?): TestClassByApp = TestClassByApp(environment) 12 | override fun scope() = Scope.BY_APP 13 | } 14 | -------------------------------------------------------------------------------- /popkorn/src/commonTest/kotlin/data/TestClassByHolder.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.data 2 | 3 | import cc.popkorn.InjectorManager 4 | import cc.popkorn.core.Scope 5 | import cc.popkorn.core.config.Parameters 6 | import cc.popkorn.providers.Provider 7 | 8 | class TestClassByHolder(environment: String?) : TestClassNoProvider(environment) 9 | 10 | class TestClassByHolderProvider : Provider { 11 | override fun create(injector: InjectorManager, assisted: Parameters, environment: String?): TestClassByHolder = TestClassByHolder(environment) 12 | override fun scope() = Scope.BY_HOLDER 13 | } 14 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/InjectorManager.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn 2 | 3 | import cc.popkorn.core.config.InjectorConfig 4 | import kotlin.reflect.KClass 5 | 6 | /** 7 | * Interface with the available methods to manage injections 8 | * 9 | * @author Pau Corbella 10 | * @since 2.1.0 11 | */ 12 | interface InjectorManager { 13 | 14 | fun inject(clazz: KClass, environment: String? = null, config: (InjectorConfig.Builder.() -> Unit)? = null): T 15 | 16 | fun injectOrNull(clazz: KClass, environment: String? = null, config: (InjectorConfig.Builder.() -> Unit)? = null): T? 17 | } 18 | -------------------------------------------------------------------------------- /popkorn-androidx-viewmodel/src/androidMain/kotlin/PopKornViewModelFactory.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.androidx.viewModel 2 | 3 | import androidx.lifecycle.ViewModel 4 | import androidx.lifecycle.ViewModelProvider 5 | import cc.popkorn.core.config.InjectorConfig 6 | import cc.popkorn.popKorn 7 | 8 | class PopKornViewModelFactory( 9 | private val environment: String? = null, 10 | private val config: (InjectorConfig.Builder.() -> Unit)? 11 | ) : ViewModelProvider.Factory { 12 | 13 | override fun create(modelClass: Class) = 14 | popKorn().inject(modelClass.kotlin, environment, config) 15 | } 16 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/annotations/ForEnvironments.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.annotations 2 | 3 | /** 4 | * Annotation to define the environments that an @Injectable class can be injected to or 5 | * to define the constructors to be used when injecting an @Injectable class or 6 | * to define the method to be used when injecting an @InjectableProvider class 7 | * 8 | * @author Pau Corbella 9 | * @since 1.0.0 10 | */ 11 | @Target(AnnotationTarget.CLASS, AnnotationTarget.CONSTRUCTOR, AnnotationTarget.FUNCTION) 12 | @Retention(AnnotationRetention.SOURCE) 13 | annotation class ForEnvironments(vararg val value: String) 14 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/Constants.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn 2 | 3 | private val PROHIBITED_PACKAGES = 4 | arrayOf(Regex("java\\..*"), Regex("javax\\..*"), Regex("kotlin\\..*"), Regex("kotlinx\\..*")) 5 | 6 | const val RESOLVER_SUFFIX = "Resolver" 7 | const val PROVIDER_SUFFIX = "Provider" 8 | 9 | const val RESOLVER_MAPPINGS = "popkorn.resolver.mappings" 10 | const val PROVIDER_MAPPINGS = "popkorn.provider.mappings" 11 | 12 | fun normalizeQualifiedName(path: String): String { 13 | val isProhibited = PROHIBITED_PACKAGES.map { path.matches(it) }.any { it } 14 | return if (isProhibited) "cc.popkorn.$path" else path 15 | } 16 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/annotations/WithEnvironment.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.annotations 2 | 3 | /** 4 | * Annotation to use a specific environment as an implementation of a constructor/method parameter 5 | * 6 | * constructor(param1:Interface, @WithEnvironment("PRO") param2:Interface) 7 | * this will inject the default implementation of Interface as param1 and 8 | * the implementation of Interface in the environment PRO as param2 9 | * 10 | * @author Pau Corbella 11 | * @since 1.0.0 12 | */ 13 | @Target(AnnotationTarget.VALUE_PARAMETER) 14 | @Retention(AnnotationRetention.SOURCE) 15 | annotation class WithEnvironment(val value: String) 16 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/annotations/Alias.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.annotations 2 | 3 | /** 4 | * Annotation to use a specific implementation (defined in any injectable class) in a constructor/method parameter 5 | * 6 | * constructor(param1:Interface, @Alias("name") param2:Interface) 7 | * this will inject the default implementation of Interface as param1 and 8 | * "name" implementation of Interface as param2 9 | * 10 | * @author Pau Corbella 11 | * @since 1.0.0 12 | */ 13 | @Deprecated("Use environments instead") 14 | @Target(AnnotationTarget.VALUE_PARAMETER) 15 | @Retention(AnnotationRetention.SOURCE) 16 | annotation class Alias(val value: String) 17 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/Platform.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn 2 | 3 | import cc.popkorn.core.Injector 4 | import cc.popkorn.pools.ResolverPool 5 | import kotlin.reflect.KClass 6 | 7 | /** 8 | * Methods/Classes used in library that are Platform-dependent 9 | * 10 | * @author Pau Corbella 11 | * @since 2.0.0 12 | */ 13 | 14 | expect class WeakReference(referred: T) { 15 | fun clear() 16 | fun get(): T? 17 | } 18 | 19 | internal expect fun KClass.getName(): String 20 | 21 | internal expect fun KClass.needsResolver(resolverPool: ResolverPool): Boolean 22 | 23 | internal expect fun createDefaultInjector(): Injector 24 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/core/Scope.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.core 2 | 3 | /** 4 | * Enum defining available Scopes in PopKorn 5 | * BY_APP -> Instance will be created only once, for hence this instance will live forever 6 | * BY_USE -> Instance will be created if no one is using it, meaning that instances will live as long as others are using it 7 | * BY_HOLDER -> Instance will be created if used with a different holder, so will live as long as its holder (container) 8 | * BY_NEW -> Instance will be created every time is needed, so won't live at all 9 | * 10 | * @author Pau Corbella 11 | * @since 1.0.0 12 | */ 13 | enum class Scope { 14 | BY_APP, 15 | BY_USE, 16 | BY_HOLDER, 17 | BY_NEW 18 | } 19 | -------------------------------------------------------------------------------- /popkorn/src/commonTest/kotlin/data/TestClassByNewAssisted.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.data 2 | 3 | import cc.popkorn.InjectorManager 4 | import cc.popkorn.core.Scope 5 | import cc.popkorn.core.config.Parameters 6 | import cc.popkorn.providers.Provider 7 | 8 | class TestClassByNewAssisted(val param1: String, val param2: Int, environment: String?) : TestClassNoProvider(environment) 9 | 10 | class TestClassByNewAssistedProvider : Provider { 11 | override fun create(injector: InjectorManager, assisted: Parameters, environment: String?): TestClassByNewAssisted = TestClassByNewAssisted(assisted.get(String::class), assisted.get(Int::class), environment) 12 | override fun scope() = Scope.BY_NEW 13 | } 14 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/core/Propagation.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.core 2 | 3 | /** 4 | * Enum defining how far will extend injection from an Injectable class 5 | * NONE -> Only the class will be injectable (Default for @InjectableProvider) 6 | * DIRECT -> The class and its direct interfaces will be injectable 7 | * ALL -> The class and all its interfaces will be injectable (Default for @Injectable) 8 | * 9 | * For Example -> C1:I1 I1:I2 10 | * NONE -> Only C1 will be injectable 11 | * DIRECT -> C1 and I1 will be injectable 12 | * ALL -> C1, I1 and I2 will be injectable 13 | * 14 | * @author Pau Corbella 15 | * @since 1.2.0 16 | */ 17 | enum class Propagation { 18 | NONE, 19 | DIRECT, 20 | ALL 21 | } 22 | -------------------------------------------------------------------------------- /popkorn/src/commonTest/kotlin/data/TestCascadeClass.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.data 2 | 3 | import cc.popkorn.InjectorManager 4 | import cc.popkorn.core.Scope 5 | import cc.popkorn.core.config.Parameters 6 | import cc.popkorn.providers.Provider 7 | 8 | class TestCascadeClass(val param1: TestClassByApp, val param2: TestClassByUse, environment: String?) : TestClassNoProvider(environment) 9 | 10 | class TestCascadeClassProvider : Provider { 11 | override fun create(injector: InjectorManager, assisted: Parameters, environment: String?): TestCascadeClass = 12 | TestCascadeClass(injector.inject(TestClassByApp::class), injector.inject(TestClassByUse::class), environment) 13 | 14 | override fun scope() = Scope.BY_USE 15 | } 16 | -------------------------------------------------------------------------------- /popkorn/src/commonTest/kotlin/data/TestInterface.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.data 2 | 3 | import cc.popkorn.resolvers.Resolver 4 | import kotlin.reflect.KClass 5 | 6 | interface TestInterface { 7 | val value: String? 8 | } 9 | 10 | class TestInterfaceResolver : Resolver { 11 | override fun resolve(environment: String?): KClass { 12 | return when (environment) { 13 | "app" -> TestClassByApp::class 14 | "use" -> TestClassByUse::class 15 | "new" -> TestClassByNew::class 16 | "assist1" -> TestClassByNewAssisted::class 17 | "assist2" -> TestClassByNewAssisted2::class 18 | else -> TestClassByApp::class 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/instances/NewInstances.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.instances 2 | 3 | import cc.popkorn.InjectorManager 4 | import cc.popkorn.core.config.Parameters 5 | import cc.popkorn.providers.Provider 6 | 7 | /** 8 | * Instances implementation for Scope.BY_NEW 9 | * Doesn't matter the number of times get() is called, it will always return a new instance 10 | * 11 | * @author Pau Corbella 12 | * @since 1.0.0 13 | */ 14 | internal class NewInstances(private val injector: InjectorManager, private val provider: Provider) : Instances { 15 | 16 | fun get(parameters: Parameters, environment: String?): T { 17 | return provider.create(injector, parameters, environment) 18 | } 19 | 20 | override fun size() = 0 21 | } 22 | -------------------------------------------------------------------------------- /popkorn/src/commonTest/kotlin/data/TestClassByNewAssisted2.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.data 2 | 3 | import cc.popkorn.InjectorManager 4 | import cc.popkorn.core.Scope 5 | import cc.popkorn.core.config.Parameters 6 | import cc.popkorn.providers.Provider 7 | 8 | class TestClassByNewAssisted2(val param1: String, val param2: String, environment: String?) : TestClassNoProvider(environment) 9 | 10 | class TestClassByNewAssisted2Provider : Provider { 11 | override fun create(injector: InjectorManager, assisted: Parameters, environment: String?): TestClassByNewAssisted2 = 12 | TestClassByNewAssisted2(assisted.get(String::class, "env1"), assisted.get(String::class, "env2"), environment) 13 | 14 | override fun scope() = Scope.BY_NEW 15 | } 16 | -------------------------------------------------------------------------------- /popkorn/src/jvmMain/kotlin/pools/Utils.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.pools 2 | 3 | import kotlin.reflect.KClass 4 | 5 | internal fun KClass.getHierarchyName(): String { 6 | val parent = java.enclosingClass 7 | return if (parent == null) { // If the class its on its own 8 | java.name 9 | } else { 10 | "${parent.name}_${java.simpleName}" 11 | } 12 | } 13 | 14 | internal fun existClass(fullName: String): Boolean { 15 | return try { 16 | Class.forName(fullName) 17 | true 18 | } catch (e: Throwable) { 19 | false 20 | } 21 | } 22 | 23 | internal fun createClass(fullName: String): T? { 24 | return try { 25 | Class.forName(fullName).getDeclaredConstructor().newInstance() as T 26 | } catch (e: Throwable) { 27 | null 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /popkorn-androidx-viewmodel/src/androidTest/kotlin/data/TestViewModelWithParams.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.androidx.viewModel.data 2 | 3 | import androidx.lifecycle.ViewModel 4 | import cc.popkorn.InjectorManager 5 | import cc.popkorn.core.Scope 6 | import cc.popkorn.core.config.Parameters 7 | import cc.popkorn.providers.Provider 8 | 9 | open class TestViewModelWithParams(val name: String, val age: Int) : ViewModel() 10 | 11 | class TestViewModelWithParamsProvider : Provider { 12 | 13 | override fun create( 14 | injector: InjectorManager, 15 | assisted: Parameters, 16 | environment: String? 17 | ): TestViewModelWithParams { 18 | return TestViewModelWithParams(assisted.get(String::class), assisted.get(Int::class)) 19 | } 20 | 21 | override fun scope() = Scope.BY_NEW 22 | } 23 | -------------------------------------------------------------------------------- /popkorn-compiler/src/main/kotlin/cc/popkorn/compiler/utils/Logger.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.compiler.utils 2 | 3 | import javax.annotation.processing.Messager 4 | import javax.tools.Diagnostic 5 | 6 | /** 7 | * Logger to print compile time messages 8 | * 9 | * @author Pau Corbella 10 | * @since 1.0.0 11 | */ 12 | internal class Logger(private val messenger: Messager) { 13 | 14 | fun message(text: String) { 15 | messenger.printMessage(Diagnostic.Kind.NOTE, "PopKorn: $text \r\n") 16 | } 17 | 18 | fun warning(text: String) { 19 | messenger.printMessage(Diagnostic.Kind.WARNING, "PopKorn: $text \r\n") 20 | } 21 | 22 | fun error(text: String, exception: Throwable?) { 23 | messenger.printMessage(Diagnostic.Kind.ERROR, "PopKorn: $text \r\n") 24 | exception?.printStackTrace() 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/instances/PersistentInstances.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.instances 2 | 3 | import cc.popkorn.InjectorManager 4 | import cc.popkorn.core.config.Parameters 5 | import cc.popkorn.providers.Provider 6 | 7 | /** 8 | * Instances implementation for Scope.BY_APP 9 | * Calling get() for the same environment and T::class will return always the same instance 10 | * 11 | * @author Pau Corbella 12 | * @since 1.0.0 13 | */ 14 | internal class PersistentInstances(private val injector: InjectorManager, private val provider: Provider) : Instances { 15 | private val instances = hashMapOf() 16 | 17 | fun get(environment: String?): T { 18 | return instances.getOrPut(environment) { provider.create(injector, Parameters.EMPTY, environment) } 19 | } 20 | 21 | override fun size() = instances.size 22 | } 23 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/resolvers/RuntimeResolver.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.resolvers 2 | 3 | import cc.popkorn.core.exceptions.InstanceNotFoundException 4 | import kotlin.reflect.KClass 5 | 6 | /** 7 | * Class to be used when resolving the runtime injection instances 8 | * 9 | * @author Pau Corbella 10 | * @since 1.3.0 11 | */ 12 | internal class RuntimeResolver : Resolver { 13 | private val resolvers = hashMapOf>() 14 | 15 | override fun resolve(environment: String?): KClass { 16 | return resolvers[environment] ?: (resolvers[null] ?: throw InstanceNotFoundException()) 17 | } 18 | 19 | fun put(environment: String?, data: KClass) = resolvers.put(environment, data) 20 | 21 | fun remove(environment: String?) = resolvers.remove(environment) 22 | 23 | fun size() = resolvers.size 24 | } 25 | -------------------------------------------------------------------------------- /popkorn-androidx-viewmodel/src/androidTest/kotlin/data/TestViewModelResolverPool.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.androidx.viewModel.data 2 | 3 | import cc.popkorn.core.exceptions.ResolverNotFoundException 4 | import cc.popkorn.pools.ResolverPool 5 | import cc.popkorn.resolvers.Resolver 6 | import kotlin.reflect.KClass 7 | 8 | class TestViewModelResolverPool : ResolverPool { 9 | 10 | override fun isPresent(clazz: KClass): Boolean { 11 | return when (clazz) { 12 | TestViewModelWithParams::class -> true 13 | else -> false 14 | } 15 | } 16 | 17 | override fun create(clazz: KClass): Resolver { 18 | return when (clazz) { 19 | TestViewModelWithParams::class -> TestViewModelResolver() as Resolver 20 | else -> throw ResolverNotFoundException(clazz) 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/InjectorController.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn 2 | 3 | import cc.popkorn.core.config.CreatorConfig 4 | import kotlin.reflect.KClass 5 | 6 | /** 7 | * Interface with the available methods to manage injections 8 | * 9 | * @author Pau Corbella 10 | * @since 1.0.0 11 | */ 12 | interface InjectorController : InjectorManager { 13 | 14 | fun addInjectable(instance: T, type: KClass, environment: String? = null) 15 | 16 | fun addInjectable(instance: T, environment: String? = null) = addInjectable(instance, instance::class, environment) 17 | 18 | fun removeInjectable(type: KClass, environment: String? = null) 19 | 20 | fun create(clazz: KClass, environment: String? = null, config: (CreatorConfig.Builder.() -> Unit)? = null): T 21 | 22 | fun purge() 23 | 24 | fun reset() 25 | } 26 | -------------------------------------------------------------------------------- /popkorn-androidx-viewmodel/src/androidTest/kotlin/data/TestViewModelProviderPool.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.androidx.viewModel.data 2 | 3 | import cc.popkorn.core.exceptions.ProviderNotFoundException 4 | import cc.popkorn.pools.ProviderPool 5 | import cc.popkorn.providers.Provider 6 | import kotlin.reflect.KClass 7 | 8 | class TestViewModelProviderPool : ProviderPool { 9 | 10 | override fun isPresent(clazz: KClass): Boolean { 11 | return when (clazz) { 12 | TestViewModelWithParams::class -> true 13 | else -> false 14 | } 15 | } 16 | 17 | override fun create(clazz: KClass): Provider { 18 | return when (clazz) { 19 | TestViewModelWithParams::class -> TestViewModelWithParamsProvider() as Provider 20 | else -> throw ProviderNotFoundException(clazz) 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /popkorn-compiler/src/test/kotlin/cc/popkorn/compiler/utils/JavaParam.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.compiler.utils 2 | 3 | /** 4 | * Class to create a java parameter by code 5 | * 6 | * @author Pau Corbella 7 | * @since 1.2.0 8 | */ 9 | class JavaParam(private val name: String, private val type: String) { 10 | private val annotations = arrayListOf() 11 | 12 | fun alias(alias: String): JavaParam { 13 | this.annotations.add("@Alias(\"$alias\")") 14 | return this 15 | } 16 | 17 | fun withEnvironment(environment: String): JavaParam { 18 | this.annotations.add("@WithEnvironment(\"$environment\")") 19 | return this 20 | } 21 | 22 | fun assisted(): JavaParam { 23 | this.annotations.add("@Assisted") 24 | return this 25 | } 26 | 27 | fun construct(): String { 28 | return "${annotations.joinToString(" ")} $type $name" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /popkorn/src/jsMain/kotlin/PopKornCompat.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn 2 | 3 | import cc.popkorn.mapping.Mapping 4 | 5 | /** 6 | * Compatibility class to use PopKorn from js code 7 | * 8 | * @author Pau Corbella 9 | * @since 2.0.0 10 | */ 11 | 12 | internal lateinit var resolverMappings: Set 13 | internal lateinit var providerMappings: Set 14 | 15 | /** 16 | * This method needs to be called on JS platform before using PopKorn. This is because in js cannot 17 | * automatically locate the mapping files 18 | * 19 | * @param resolvers All the resolver mappings that PopKorn generated 20 | * @param providers All the provider mappings that PopKorn generated 21 | */ 22 | fun setup(resolvers: Set, providers: Set) { 23 | if (::resolverMappings.isInitialized || ::providerMappings.isInitialized) return 24 | resolverMappings = resolvers 25 | providerMappings = providers 26 | } 27 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | strategy: 8 | matrix: 9 | os: [ macOS-latest, windows-latest, ubuntu-latest ] 10 | 11 | runs-on: ${{matrix.os}} 12 | 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v2 16 | 17 | - name: Set up Java 18 | uses: actions/setup-java@v1 19 | with: 20 | java-version: 15 21 | 22 | - name: Gradle cache 23 | uses: actions/cache@v2 24 | with: 25 | path: | 26 | ~/.gradle/caches 27 | ~/.gradle/wrapper 28 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }} 29 | restore-keys: | 30 | ${{ runner.os }}-gradle- 31 | 32 | - name: Build all projects 33 | run: ./gradlew build 34 | 35 | - name: Run all tests 36 | run: ./gradlew check 37 | -------------------------------------------------------------------------------- /popkorn/src/nativeMain/kotlin/PopKornCompat.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn 2 | 3 | import cc.popkorn.mapping.Mapping 4 | 5 | /** 6 | * Compatibility class to use PopKorn from native code 7 | * 8 | * @author Pau Corbella 9 | * @since 2.0.0 10 | */ 11 | 12 | internal lateinit var resolverMappings: Set 13 | internal lateinit var providerMappings: Set 14 | 15 | /** 16 | * This method needs to be called on Native platform before using PopKorn. This is because in native cannot 17 | * automatically locate the mapping files 18 | * 19 | * @param resolvers All the resolver mappings that PopKorn generated 20 | * @param providers All the provider mappings that PopKorn generated 21 | */ 22 | fun setup(resolvers: Set, providers: Set) { 23 | if (::resolverMappings.isInitialized || ::providerMappings.isInitialized) return 24 | resolverMappings = resolvers 25 | providerMappings = providers 26 | } 27 | -------------------------------------------------------------------------------- /samples/androidx-viewmodel/build.gradle.kts: -------------------------------------------------------------------------------- 1 | val appCompatVersion = "1.2.0" 2 | val coreVersion = "1.3.2" 3 | 4 | plugins { 5 | id("com.android.application") 6 | kotlin("android") 7 | kotlin("kapt") 8 | } 9 | 10 | repositories { 11 | mavenCentral() 12 | google() 13 | } 14 | 15 | android { 16 | compileSdk = 34 17 | 18 | defaultConfig { 19 | minSdk = 15 20 | targetSdk = 34 21 | versionCode = 1 22 | versionName = "1.0" 23 | } 24 | 25 | namespace = "cc.popkorn.samples.androidx.viewmodel" 26 | } 27 | 28 | kotlin { 29 | jvmToolchain(8) 30 | } 31 | 32 | dependencies { 33 | implementation(project(":popkorn")) 34 | implementation(project(":popkorn-androidx-viewmodel")) 35 | kapt(project(":popkorn-compiler")) 36 | 37 | implementation("androidx.appcompat:appcompat:$appCompatVersion") 38 | implementation("androidx.core:core-ktx:$coreVersion") 39 | } 40 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/annotations/Injectable.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.annotations 2 | 3 | import cc.popkorn.core.Propagation 4 | import cc.popkorn.core.Scope 5 | import kotlin.reflect.KClass 6 | 7 | /** 8 | * Annotation to define that a class can be injected. 9 | * By default, this annotation adds also as an injectable object all its interfaces (Propagation.ALL) unless otherwise specified 10 | * Also, if not defined, takes the scope BY_APP by default 11 | * If you want to exclude some of them, do it through parameter 'exclude' 12 | * 13 | * @author Pau Corbella 14 | * @since 1.0.0 15 | */ 16 | @Target(AnnotationTarget.CLASS) 17 | @Retention(AnnotationRetention.SOURCE) 18 | annotation class Injectable( 19 | val scope: Scope = Scope.BY_APP, 20 | @Deprecated("Use environments instead") val alias: String = "", 21 | val propagation: Propagation = Propagation.ALL, 22 | vararg val exclude: KClass<*> = arrayOf() 23 | ) 24 | -------------------------------------------------------------------------------- /popkorn/src/commonTest/kotlin/data/TestResolverPool.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.data 2 | 3 | import cc.popkorn.core.exceptions.ResolverNotFoundException 4 | import cc.popkorn.pools.ResolverPool 5 | import cc.popkorn.resolvers.Resolver 6 | import kotlin.reflect.KClass 7 | 8 | /** 9 | * ResolverPool that define how test interfaces are resolved 10 | * 11 | * @author Pau Corbella 12 | * @since 2.0.0 13 | */ 14 | class TestResolverPool : ResolverPool { 15 | 16 | override fun isPresent(clazz: KClass): Boolean { 17 | return when (clazz) { 18 | TestInterface::class -> true 19 | else -> false 20 | } 21 | } 22 | 23 | override fun create(clazz: KClass): Resolver { 24 | return when (clazz) { 25 | TestInterface::class -> TestInterfaceResolver() as Resolver 26 | else -> throw ResolverNotFoundException(clazz) 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /samples/androidx-viewmodel/src/main/res/layout/third_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | 21 | 22 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/instances/RuntimeInstances.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.instances 2 | 3 | import cc.popkorn.core.exceptions.InstanceNotFoundException 4 | 5 | /** 6 | * Instances implementation for manually scoped instances 7 | * Calling get() will return a previously added T::class. If not added or already removed, 8 | * will throw an InstanceNotFoundException 9 | * 10 | * @author Pau Corbella 11 | * @since 1.0.0 12 | */ 13 | internal class RuntimeInstances : Instances { 14 | private val instances = hashMapOf() 15 | 16 | fun get(environment: String?): T { 17 | return instances[environment] ?: instances[null] ?: throw InstanceNotFoundException() 18 | } 19 | 20 | fun put(environment: String?, data: T) = instances.put(environment, data) 21 | 22 | fun remove(environment: String?) { 23 | instances.remove(environment) 24 | } 25 | 26 | override fun size() = instances.size 27 | } 28 | -------------------------------------------------------------------------------- /popkorn/src/commonMain/kotlin/annotations/InjectableProvider.kt: -------------------------------------------------------------------------------- 1 | package cc.popkorn.annotations 2 | 3 | import cc.popkorn.core.Propagation 4 | import cc.popkorn.core.Scope 5 | import kotlin.reflect.KClass 6 | 7 | /** 8 | * Annotation to define a class that provides an injectable class 9 | * This is normally used with external classes, where you don't have 10 | * the source code to add @Injectable annotation 11 | * By default, only the provided class is injectable (Propagation.NONE) 12 | * Also, if not defined, takes the scope BY_APP by default 13 | * 14 | * @author Pau Corbella 15 | * @since 1.0.0 16 | */ 17 | @Target(AnnotationTarget.CLASS) 18 | @Retention(AnnotationRetention.SOURCE) 19 | annotation class InjectableProvider( 20 | val scope: Scope = Scope.BY_APP, 21 | @Deprecated("Use environments instead") val alias: String = "", 22 | val propagation: Propagation = Propagation.NONE, 23 | vararg val exclude: KClass<*> = arrayOf() 24 | ) 25 | -------------------------------------------------------------------------------- /samples/androidx-viewmodel/src/main/res/layout/second_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 15 | 16 |