Repository: evant/kotlin-inject
Pull request #27 (2020-08-02 00:59:04)

Support javax inject and scope annotations
see: #9


Patch:
diff --git a/kotlin-inject-compiler-core/src/main/kotlin/me/tatarka/inject/compiler/Ast.kt b/kotlin-inject-compiler-core/src/main/kotlin/me/tatarka/inject/compiler/Ast.kt
index 77ae2ac..15aa9f3 100644
--- a/kotlin-inject-compiler-core/src/main/kotlin/me/tatarka/inject/compiler/Ast.kt
+++ b/kotlin-inject-compiler-core/src/main/kotlin/me/tatarka/inject/compiler/Ast.kt
@@ -24,15 +24,15 @@ interface Messenger {
 }
 
 sealed class AstElement : AstAnnotated {
-    inline fun <reified T : Annotation> hasAnnotation() = hasAnnotation(T::class)
+    inline fun <reified T : Annotation> hasAnnotation() = hasAnnotation(T::class.qualifiedName!!)
 
-    inline fun <reified T : Annotation> typeAnnotatedWith(): AstClass? = typeAnnotatedWith(T::class)
+    inline fun <reified T : Annotation> typeAnnotatedWith(): AstClass? = typeAnnotatedWith(T::class.qualifiedName!!)
 }
 
 interface AstAnnotated {
-    fun <T : Annotation> hasAnnotation(kclass: KClass<T>): Boolean
+    fun hasAnnotation(className: String): Boolean
 
-    fun <T : Annotation> typeAnnotatedWith(kclass: KClass<T>): AstClass?
+    fun typeAnnotatedWith(className: String): AstClass?
 }
 
 abstract class AstBasicElement : AstElement() {
@@ -146,4 +146,4 @@ enum class AstModifier {
 }
 
 fun ParameterSpec.Companion.parametersOf(constructor: AstConstructor) =
-    constructor.parameters.map { it.asParameterSpec() }
+        constructor.parameters.map { it.asParameterSpec() }
diff --git a/kotlin-inject-compiler-core/src/main/kotlin/me/tatarka/inject/compiler/InjectGenerator.kt b/kotlin-inject-compiler-core/src/main/kotlin/me/tatarka/inject/compiler/InjectGenerator.kt
index 7ceaa1c..222d36e 100644
--- a/kotlin-inject-compiler-core/src/main/kotlin/me/tatarka/inject/compiler/InjectGenerator.kt
+++ b/kotlin-inject-compiler-core/src/main/kotlin/me/tatarka/inject/compiler/InjectGenerator.kt
@@ -9,7 +9,7 @@ import me.tatarka.inject.annotations.Scope
 import kotlin.reflect.KClass
 
 class InjectGenerator(provider: AstProvider, private val options: Options) :
-    AstProvider by provider {
+        AstProvider by provider {
 
     fun generate(astClass: AstClass, scopedClasses: Collection<AstClass> = emptyList()): FileSpec {
         if (AstModifier.ABSTRACT !in astClass.modifiers) {
@@ -20,205 +20,206 @@ class InjectGenerator(provider: AstProvider, private val options: Options) :
 
         val constructor = astClass.primaryConstructor
 
-        val scopedInjects = scopedClasses.filter { it.hasAnnotation<Inject>() }
+        val scopedInjects = scopedClasses.filter { it.isInject(options) }
 
         val injectComponent = generateInjectComponent(astClass, constructor, scopedInjects)
         val createFunction = generateCreate(astClass, constructor, injectComponent)
 
         return FileSpec.builder(astClass.packageName, "Inject${astClass.name}")
-            .addType(injectComponent)
-            .addFunction(createFunction)
-            .build()
+                .addType(injectComponent)
+                .addFunction(createFunction)
+                .build()
     }
 
     fun generateScopedInterfaces(scopedClasses: Collection<AstClass>): List<FileSpec> {
-        val scopedInjects = scopedClasses.filter { it.hasAnnotation<Inject>() }
-        val scopedInterfaces = scopedClasses.filter { !it.hasAnnotation<Inject>() && !it.hasAnnotation<Component>() }
+        val scopedInjects = scopedClasses.filter { it.isInject(options) }
+        val scopedInterfaces = scopedClasses.filter { !it.isInject(options) && !it.hasAnnotation<Component>() }
         return scopedInterfaces.map {
             FileSpec.builder(it.packageName, "Inject${it.name}")
-                .addType(generateScopedInterface(it, scopedInjects))
-                .build()
+                    .addType(generateScopedInterface(it, scopedInjects))
+                    .build()
         }
     }
 
     private fun generateInjectComponent(
-        astClass: AstClass,
-        constructor: AstConstructor?,
-        scopedInjects: Collection<AstClass>
+            astClass: AstClass,
+            constructor: AstConstructor?,
+            scopedInjects: Collection<AstClass>
     ): TypeSpec {
         val context = collectTypes(astClass, scopedInjects, isComponent = true)
 
         return TypeSpec.classBuilder("Inject${astClass.name}")
-            .addOriginatingElement(astClass)
-            .superclass(astClass.asClassName())
-            .apply {
-                if (context.scopeInterface != null) {
-                    addSuperinterface(
-                        ClassName(
-                            context.scopeInterface.packageName,
-                            "Inject${context.scopeInterface.name}"
+                .addOriginatingElement(astClass)
+                .superclass(astClass.asClassName())
+                .apply {
+                    if (context.scopeInterface != null) {
+                        addSuperinterface(
+                                ClassName(
+                                        context.scopeInterface.packageName,
+                                        "Inject${context.scopeInterface.name}"
+                                )
                         )
-                    )
-                }
-
-                if (constructor != null) {
-                    val funSpec = FunSpec.constructorBuilder()
-                    for (parameter in constructor.parameters) {
-                        val p = parameter.asParameterSpec()
-                        funSpec.addParameter(p)
-                        addSuperclassConstructorParameter("%N", p)
                     }
-                    primaryConstructor(funSpec.build())
-                }
 
-                try {
-                    for (type in context.collector.scoped) {
-                        val codeBlock = CodeBlock.builder()
-                        codeBlock.add("lazy { ")
-                        codeBlock.add(provide(TypeKey(type), context.withoutScoped(type)))
-                        codeBlock.add(" }")
-
-                        addProperty(
-                            PropertySpec.builder(
-                                type.asElement().simpleName.asScopedProp(),
-                                type.asTypeName()
-                            ).apply {
-                                if (context.scopeInterface != null) {
-                                    addModifiers(KModifier.OVERRIDE)
-                                }
-                            }.delegate(codeBlock.build())
-                                .build()
-                        )
+                    if (constructor != null) {
+                        val funSpec = FunSpec.constructorBuilder()
+                        for (parameter in constructor.parameters) {
+                            val p = parameter.asParameterSpec()
+                            funSpec.addParameter(p)
+                            addSuperclassConstructorParameter("%N", p)
+                        }
+                        primaryConstructor(funSpec.build())
                     }
 
-                    astClass.visitInheritanceChain { parentClass ->
-                        for (method in parentClass.methods) {
-                            if (method.isProvider()) {
-                                val codeBlock = CodeBlock.builder()
-                                codeBlock.add("return ")
-                                val returnType = method.returnTypeFor(astClass)
+                    try {
+                        for (type in context.collector.scoped) {
+                            val codeBlock = CodeBlock.builder()
+                            codeBlock.add("lazy { ")
+                            codeBlock.add(provide(TypeKey(type), context.withoutScoped(type)))
+                            codeBlock.add(" }")
 
-                                codeBlock.add(provide(key = TypeKey(returnType), context = context, source = method))
-
-                                addProperty(
+                            addProperty(
                                     PropertySpec.builder(
-                                        method.name,
-                                        returnType.asTypeName(),
-                                        KModifier.OVERRIDE
+                                            type.asElement().simpleName.asScopedProp(),
+                                            type.asTypeName()
+                                    ).apply {
+                                        if (context.scopeInterface != null) {
+                                            addModifiers(KModifier.OVERRIDE)
+                                        }
+                                    }.delegate(codeBlock.build())
+                                            .build()
+                            )
+                        }
+
+                        astClass.visitInheritanceChain { parentClass ->
+                            for (method in parentClass.methods) {
+                                if (method.isProvider()) {
+                                    val codeBlock = CodeBlock.builder()
+                                    codeBlock.add("return ")
+                                    val returnType = method.returnTypeFor(astClass)
+
+                                    codeBlock.add(provide(key = TypeKey(returnType), context = context, source = method))
+
+                                    addProperty(
+                                            PropertySpec.builder(
+                                                    method.name,
+                                                    returnType.asTypeName(),
+                                                    KModifier.OVERRIDE
+                                            )
+                                                    .getter(
+                                                            FunSpec.getterBuilder()
+                                                                    .addCode(codeBlock.build())
+                                                                    .build()
+                                                    )
+                                                    .build()
                                     )
-                                        .getter(
-                                            FunSpec.getterBuilder()
-                                                .addCode(codeBlock.build())
-                                                .build()
-                                        )
-                                        .build()
-                                )
+                                }
                             }
                         }
+                    } catch (e: FailedToGenerateException) {
+                        error(e.message.orEmpty(), e.element)
+                        // Create a stub component to prevent extra compile errors, the original one will still be reported.
                     }
-                } catch (e: FailedToGenerateException) {
-                    error(e.message.orEmpty(), e.element)
-                    // Create a stub component to prevent extra compile errors, the original one will still be reported.
                 }
-            }
-            .build()
+                .build()
     }
 
     private fun generateScopedInterface(
-        astClass: AstClass,
-        scopedInjects: Collection<AstClass>
+            astClass: AstClass,
+            scopedInjects: Collection<AstClass>
     ): TypeSpec {
         val context = collectTypes(astClass, scopedInjects, isComponent = false)
 
         return TypeSpec.interfaceBuilder("Inject${astClass.name}")
-            .addOriginatingElement(astClass)
-            .apply {
-                for (type in context.collector.scoped) {
-                    addProperty(
-                        PropertySpec.builder(
-                            type.asElement().simpleName.asScopedProp(),
-                            type.asTypeName()
-                        ).build()
-                    )
-                }
-            }.build()
+                .addOriginatingElement(astClass)
+                .apply {
+                    for (type in context.collector.scoped) {
+                        addProperty(
+                                PropertySpec.builder(
+                                        type.asElement().simpleName.asScopedProp(),
+                                        type.asTypeName()
+                                ).build()
+                        )
+                    }
+                }.build()
     }
 
     private fun generateCreate(
-        element: AstClass,
-        constructor: AstConstructor?,
-        injectComponent: TypeSpec
+            element: AstClass,
+            constructor: AstConstructor?,
+            injectComponent: TypeSpec
     ): FunSpec {
         return FunSpec.builder("create")
-            .apply {
-                if (constructor != null) {
-                    addParameters(ParameterSpec.parametersOf(constructor))
-                }
-                if (options.generateCompanionExtensions) {
-                    val companion = element.companion
-                    if (companion != null) {
-                        receiver(companion.type.asTypeName())
-                    } else {
-                        error(
-                            """Missing companion for class: ${element.asClassName()}.
+                .apply {
+                    if (constructor != null) {
+                        addParameters(ParameterSpec.parametersOf(constructor))
+                    }
+                    if (options.generateCompanionExtensions) {
+                        val companion = element.companion
+                        if (companion != null) {
+                            receiver(companion.type.asTypeName())
+                        } else {
+                            error(
+                                    """Missing companion for class: ${element.asClassName()}.
                             |When you have the option me.tatarka.inject.generateCompanionExtensions=true you must declare a companion option on the component class for the extension function to apply to.
                             |You can do so by adding 'companion object' to the class.
                         """.trimMargin(), element
-                        )
+                            )
+                        }
+                    } else {
+                        receiver(KClass::class.asClassName().plusParameter(element.type.asTypeName()))
                     }
-                } else {
-                    receiver(KClass::class.asClassName().plusParameter(element.type.asTypeName()))
                 }
-            }
-            .returns(element.type.asTypeName())
-            .apply {
-                val codeBlock = CodeBlock.builder()
-                codeBlock.add("return %N(", injectComponent)
-                if (constructor != null) {
-                    constructor.parameters.forEachIndexed { i, parameter ->
-                        if (i != 0) {
-                            codeBlock.add(", ")
+                .returns(element.type.asTypeName())
+                .apply {
+                    val codeBlock = CodeBlock.builder()
+                    codeBlock.add("return %N(", injectComponent)
+                    if (constructor != null) {
+                        constructor.parameters.forEachIndexed { i, parameter ->
+                            if (i != 0) {
+                                codeBlock.add(", ")
+                            }
+                            codeBlock.add("%L", parameter.name)
                         }
-                        codeBlock.add("%L", parameter.name)
                     }
+                    codeBlock.add(")")
+                    addCode(codeBlock.build())
                 }
-                codeBlock.add(")")
-                addCode(codeBlock.build())
-            }
-            .build()
+                .build()
     }
 
     private fun collectTypes(
-        astClass: AstClass,
-        scopedInjects: Collection<AstClass>,
-        isComponent: Boolean
+            astClass: AstClass,
+            scopedInjects: Collection<AstClass>,
+            isComponent: Boolean
     ): Context {
         val typeCollector = TypeCollector(
-            provider = this,
-            astClass = astClass,
-            isComponent = isComponent,
-            scopedInjects = scopedInjects
+                provider = this,
+                options = options,
+                astClass = astClass,
+                isComponent = isComponent,
+                scopedInjects = scopedInjects
         )
-        val elementScopeClass = astClass.scopeClass(messenger)
+        val elementScopeClass = astClass.scopeClass(messenger, options)
         val scopeFromParent = elementScopeClass != astClass
         return Context(
-            source = astClass,
-            collector = typeCollector,
-            scopeInterface = if (scopeFromParent) elementScopeClass else null
+                source = astClass,
+                collector = typeCollector,
+                scopeInterface = if (scopeFromParent) elementScopeClass else null
         )
     }
 
     private fun provide(
-        key: TypeKey,
-        context: Context,
-        source: AstElement? = null,
-        find: (TypeKey) -> Result? = { context.find(it) }
+            key: TypeKey,
+            context: Context,
+            source: AstElement? = null,
+            find: (TypeKey) -> Result? = { context.find(it) }
     ): CodeBlock {
         val result = find(key)
-            ?: throw FailedToGenerateException(
-                "Cannot find an @Inject constructor or provider for: $key",
-                source ?: context.source
-            )
+                ?: throw FailedToGenerateException(
+                        "Cannot find an @Inject constructor or provider for: $key",
+                        source ?: context.source
+                )
         return when (result) {
             is Result.Provides -> provideProvides(result, context)
             is Result.Scoped -> provideScoped(key, result)
@@ -232,8 +233,8 @@ class InjectGenerator(provider: AstProvider, private val options: Options) :
     }
 
     private fun provideProvides(
-        providesResult: Result.Provides,
-        context: Context
+            providesResult: Result.Provides,
+            context: Context
     ): CodeBlock {
         val codeBlock = CodeBlock.builder()
 
@@ -283,8 +284,8 @@ class InjectGenerator(provider: AstProvider, private val options: Options) :
     }
 
     private fun provideConstructor(
-        constructor: AstConstructor,
-        context: Context
+            constructor: AstConstructor,
+            context: Context
     ): CodeBlock {
         val codeBlock = CodeBlock.builder()
         codeBlock.add("%T(", constructor.type.asTypeName())
@@ -316,12 +317,12 @@ class InjectGenerator(provider: AstProvider, private val options: Options) :
                     add(", ")
                 }
                 add(
-                    provideProvides(
-                        Result.Provides(
-                            null,
-                            method
-                        ), context
-                    )
+                        provideProvides(
+                                Result.Provides(
+                                        null,
+                                        method
+                                ), context
+                        )
                 )
             }
             add(")")
@@ -433,15 +434,15 @@ class InjectGenerator(provider: AstProvider, private val options: Options) :
                 val injectedFunction = functions.find { it.hasAnnotation<Inject>() }
                 if (injectedFunction != null) {
                     return Result.NamedFunction(
-                        function = injectedFunction,
-                        args = key.type.arguments.dropLast(1)
+                            function = injectedFunction,
+                            args = key.type.arguments.dropLast(1)
                     )
                 }
             }
             val fKey = TypeKey(key.type.arguments.last())
             return Result.Function(
-                key = fKey,
-                args = key.type.arguments.dropLast(1)
+                    key = fKey,
+                    args = key.type.arguments.dropLast(1)
             )
         }
         if (key.type.name.startsWith("kotlin.Lazy")) {
@@ -452,11 +453,11 @@ class InjectGenerator(provider: AstProvider, private val options: Options) :
     }
 
     data class Context(
-        val source: AstClass,
-        val collector: TypeCollector,
-        val scopeInterface: AstClass? = null,
-        val args: List<Pair<AstType, String>> = emptyList(),
-        val skipScoped: AstType? = null
+            val source: AstClass,
+            val collector: TypeCollector,
+            val scopeInterface: AstClass? = null,
+            val args: List<Pair<AstType, String>> = emptyList(),
+            val skipScoped: AstType? = null
     ) {
         fun withoutScoped(scoped: AstType) = copy(skipScoped = scoped)
 
@@ -478,7 +479,15 @@ class InjectGenerator(provider: AstProvider, private val options: Options) :
 }
 
 
-fun AstElement.scopeType(): AstClass? = typeAnnotatedWith<Scope>()
+fun AstElement.scopeType(options: Options): AstClass? {
+    if (options.enableJavaxAnnotations) {
+        val type = typeAnnotatedWith("javax.inject.Scope")
+        if (type != null) {
+            return type
+        }
+    }
+    return typeAnnotatedWith<Scope>()
+}
 
 private fun String.asScopedProp(): String = "_" + decapitalize()
 
@@ -486,22 +495,31 @@ fun AstElement.isComponent() = hasAnnotation<Component>()
 
 fun AstMethod.isProvides(): Boolean = hasAnnotation<Provides>()
 
+fun AstClass.isInject(options: Options): Boolean {
+    if (options.enableJavaxAnnotations) {
+        if (primaryConstructor?.hasAnnotation("javax.inject.Inject") == true) {
+            return true
+        }
+    }
+    return hasAnnotation<Inject>()
+}
+
 fun AstMethod.isProvider(): Boolean =
-    !hasAnnotation<Provides>() && AstModifier.ABSTRACT in modifiers && when (this) {
-        is AstFunction -> parameters.isEmpty()
-        is AstProperty -> true
-    } && receiverParameterType == null && returnType.isNotUnit()
+        !hasAnnotation<Provides>() && AstModifier.ABSTRACT in modifiers && when (this) {
+            is AstFunction -> parameters.isEmpty()
+            is AstProperty -> true
+        } && receiverParameterType == null && returnType.isNotUnit()
 
-fun AstClass.scopeClass(messenger: Messenger): AstClass? {
+fun AstClass.scopeClass(messenger: Messenger, options: Options): AstClass? {
     var elementScopeClass: AstClass? = null
     visitInheritanceChain { parentClass ->
-        val parentScope = parentClass.scopeType()
+        val parentScope = parentClass.scopeType(options)
         if (parentScope != null) {
             if (elementScopeClass == null) {
                 elementScopeClass = parentClass
             } else {
                 messenger.error("Cannot apply scope: $parentScope", parentClass)
-                messenger.error("as scope: ${elementScopeClass!!.scopeType()} is already applied", elementScopeClass!!)
+                messenger.error("as scope: ${elementScopeClass!!.scopeType(options)} is already applied", elementScopeClass!!)
             }
         }
     }
diff --git a/kotlin-inject-compiler-core/src/main/kotlin/me/tatarka/inject/compiler/Options.kt b/kotlin-inject-compiler-core/src/main/kotlin/me/tatarka/inject/compiler/Options.kt
index 981b5d3..7dc834b 100644
--- a/kotlin-inject-compiler-core/src/main/kotlin/me/tatarka/inject/compiler/Options.kt
+++ b/kotlin-inject-compiler-core/src/main/kotlin/me/tatarka/inject/compiler/Options.kt
@@ -1,14 +1,16 @@
 package me.tatarka.inject.compiler
 
 private const val OPTION_GENERATE_COMPANION_EXTENSIONS = "me.tatarka.inject.generateCompanionExtensions"
+private const val OPTION_ENABLE_JAVAX_ANNOTATIONS = "me.tatarka.inject.enableJavaxAnnotations"
 
 data class Options(
-    val generateCompanionExtensions: Boolean
+        val generateCompanionExtensions: Boolean,
+        val enableJavaxAnnotations: Boolean
 ) {
     companion object {
         fun from(map: Map<String, String>) = Options(
-            generateCompanionExtensions = map[OPTION_GENERATE_COMPANION_EXTENSIONS]?.toBoolean()
-                ?: false
+                generateCompanionExtensions = map[OPTION_GENERATE_COMPANION_EXTENSIONS]?.toBoolean() ?: false,
+                enableJavaxAnnotations = map[OPTION_ENABLE_JAVAX_ANNOTATIONS]?.toBoolean() ?: false
         )
     }
 }
\ No newline at end of file
diff --git a/kotlin-inject-compiler-core/src/main/kotlin/me/tatarka/inject/compiler/TypeCollector.kt b/kotlin-inject-compiler-core/src/main/kotlin/me/tatarka/inject/compiler/TypeCollector.kt
index c9a8cd1..5539327 100644
--- a/kotlin-inject-compiler-core/src/main/kotlin/me/tatarka/inject/compiler/TypeCollector.kt
+++ b/kotlin-inject-compiler-core/src/main/kotlin/me/tatarka/inject/compiler/TypeCollector.kt
@@ -1,23 +1,21 @@
 package me.tatarka.inject.compiler
 
-import me.tatarka.inject.annotations.Inject
 import me.tatarka.inject.annotations.IntoMap
 import me.tatarka.inject.annotations.IntoSet
 import me.tatarka.inject.compiler.ContainerCreator.mapOf
 import me.tatarka.inject.compiler.ContainerCreator.setOf
-import java.util.*
 
-
-class TypeCollector private constructor(private val provider: AstProvider) : AstProvider by provider {
+class TypeCollector private constructor(private val provider: AstProvider, private val options: Options) : AstProvider by provider {
 
     companion object {
         operator fun invoke(
-            provider: AstProvider,
-            astClass: AstClass,
-            accessor: String? = null,
-            isComponent: Boolean = true,
-            scopedInjects: Collection<AstClass> = emptyList()
-        ): TypeCollector = TypeCollector(provider).apply {
+                provider: AstProvider,
+                options: Options,
+                astClass: AstClass,
+                accessor: String? = null,
+                isComponent: Boolean = true,
+                scopedInjects: Collection<AstClass> = emptyList()
+        ): TypeCollector = TypeCollector(provider, options).apply {
             collectTypes(astClass, accessor, isComponent, scopedInjects)
         }
     }
@@ -32,24 +30,24 @@ class TypeCollector private constructor(private val provider: AstProvider) : Ast
     private val scopedAccessors = mutableMapOf<AstClass, ScopedComponent>()
 
     private fun collectTypes(
-        astClass: AstClass,
-        accessor: String? = null,
-        isComponent: Boolean = true,
-        scopedInjects: Collection<AstClass> = emptyList()
+            astClass: AstClass,
+            accessor: String? = null,
+            isComponent: Boolean = true,
+            scopedInjects: Collection<AstClass> = emptyList()
     ) {
         val concreteMethods = mutableSetOf<AstMethod>()
         val providesMethods = mutableListOf<AstMethod>()
         val providerMethods = mutableListOf<AstMethod>()
 
-        val elementScopeClass = astClass.scopeClass(messenger)
-        val elementScope = elementScopeClass?.scopeType()
+        val elementScopeClass = astClass.scopeClass(messenger, options)
+        val elementScope = elementScopeClass?.scopeType(options)
 
         if (elementScope != null) {
             scopedAccessors[elementScope] = ScopedComponent(astClass, accessor)
         }
 
         for (injectClass in scopedInjects) {
-            if (injectClass.scopeType() == elementScope) {
+            if (injectClass.scopeType(options) == elementScope) {
                 _scoped.add(injectClass.type)
             }
         }
@@ -83,7 +81,7 @@ class TypeCollector private constructor(private val provider: AstProvider) : Ast
                 // If we aren't a component ourselves, allow obtaining types from providers as these may be contributed from the
                 // eventual implementation
                 if (!isComponent && method.isProvider()) {
-                   providerMethods.add(method)
+                    providerMethods.add(method)
                 }
             }
         }
@@ -101,7 +99,7 @@ class TypeCollector private constructor(private val provider: AstProvider) : Ast
             } else {
                 val returnType = method.returnTypeFor(astClass)
                 val key = TypeKey(returnType)
-                val scopeType = method.scopeType()
+                val scopeType = method.scopeType(options)
                 if (scopeType != null && scopeType != elementScope) {
                     error("@Provides scope:${scopeType} must match component scope: $elementScope", method)
                 }
@@ -111,7 +109,7 @@ class TypeCollector private constructor(private val provider: AstProvider) : Ast
                 }
             }
         }
-        
+
         for (method in providerMethods) {
             val returnType = method.returnTypeFor(astClass)
             val key = TypeKey(returnType)
@@ -124,9 +122,9 @@ class TypeCollector private constructor(private val provider: AstProvider) : Ast
                 if (parameter.isComponent()) {
                     val elemAstClass = parameter.type.toAstClass()
                     collectTypes(
-                        elemAstClass,
-                        accessor = if (accessor != null) "$accessor.${parameter.name}" else parameter.name,
-                        isComponent = elemAstClass.isComponent()
+                            elemAstClass,
+                            accessor = if (accessor != null) "$accessor.${parameter.name}" else parameter.name,
+                            isComponent = elemAstClass.isComponent()
                     )
                 }
             }
@@ -137,9 +135,9 @@ class TypeCollector private constructor(private val provider: AstProvider) : Ast
         val current = types[key]
         if (current == null) {
             types[key] = TypeCreator.Container(
-                creator = creator,
-                source = method,
-                methods = mutableListOf(method)
+                    creator = creator,
+                    source = method,
+                    methods = mutableListOf(method)
             )
         } else if (current is TypeCreator.Container && current.creator == creator) {
             current.methods.add(method)
@@ -152,10 +150,10 @@ class TypeCollector private constructor(private val provider: AstProvider) : Ast
         val oldValue = types[key]
         if (oldValue == null) {
             types[key] = TypeCreator.Method(
-                method = method,
-                accessor = accessor,
-                scope = method.scopeType(),
-                scopedComponent = scopedComponent
+                    method = method,
+                    accessor = accessor,
+                    scope = method.scopeType(options),
+                    scopedComponent = scopedComponent
             )
         } else {
             duplicate(key, newValue = method, oldValue = oldValue.source)
@@ -175,18 +173,18 @@ class TypeCollector private constructor(private val provider: AstProvider) : Ast
             return result
         }
         val astClass = key.type.toAstClass()
-        if (astClass.hasAnnotation<Inject>()) {
-            val scope = astClass.scopeType()
+        if (astClass.isInject(options)) {
+            val scope = astClass.scopeType(options)
             val scopedComponent = if (scope != null) scopedAccessors[scope] else null
             if (scope != null && scopedComponent == null) {
                 error("Cannot find component with scope: @$scope to inject $astClass", astClass)
                 return null
             }
             return TypeCreator.Constructor(
-                astClass.primaryConstructor!!,
-                accessor = scopedComponent?.accessor,
-                scope = scope,
-                scopedComponent = scopedComponent?.type
+                    astClass.primaryConstructor!!,
+                    accessor = scopedComponent?.accessor,
+                    scope = scope,
+                    scopedComponent = scopedComponent?.type
             )
         }
         return null
@@ -196,22 +194,22 @@ class TypeCollector private constructor(private val provider: AstProvider) : Ast
 sealed class TypeCreator(val source: AstElement) {
 
     class Constructor(
-        val constructor: AstConstructor,
-        val accessor: String? = null,
-        val scope: AstClass? = null,
-        val scopedComponent: AstClass? = null
+            val constructor: AstConstructor,
+            val accessor: String? = null,
+            val scope: AstClass? = null,
+            val scopedComponent: AstClass? = null
     ) :
-        TypeCreator(constructor)
+            TypeCreator(constructor)
 
     class Method(
-        val method: AstMethod,
-        val accessor: String? = null,
-        val scope: AstClass? = null,
-        val scopedComponent: AstClass? = null
+            val method: AstMethod,
+            val accessor: String? = null,
+            val scope: AstClass? = null,
+            val scopedComponent: AstClass? = null
     ) : TypeCreator(method)
 
     class Container(val creator: ContainerCreator, source: AstElement, val methods: MutableList<AstMethod>) :
-        TypeCreator(source)
+            TypeCreator(source)
 }
 
 enum class ContainerCreator {
@@ -219,6 +217,6 @@ enum class ContainerCreator {
 }
 
 data class ScopedComponent(
-    val type: AstClass,
-    val accessor: String?
+        val type: AstClass,
+        val accessor: String?
 )
diff --git a/kotlin-inject-compiler-kapt/src/main/kotlin/me/tatarka/inject/compiler/kapt/InjectCompiler.kt b/kotlin-inject-compiler-kapt/src/main/kotlin/me/tatarka/inject/compiler/kapt/InjectCompiler.kt
index c624d99..efcee8a 100644
--- a/kotlin-inject-compiler-kapt/src/main/kotlin/me/tatarka/inject/compiler/kapt/InjectCompiler.kt
+++ b/kotlin-inject-compiler-kapt/src/main/kotlin/me/tatarka/inject/compiler/kapt/InjectCompiler.kt
@@ -16,7 +16,7 @@ class InjectCompiler : BaseInjectCompiler() {
             if (element !is TypeElement) continue
 
             val astClass = element.toAstClass()
-            val scopeClass = astClass.scopeClass(messenger)
+            val scopeClass = astClass.scopeClass(messenger, options)
             // Only deal with non-scoped components
             if (scopeClass != null) continue
 
diff --git a/kotlin-inject-compiler-kapt/src/main/kotlin/me/tatarka/inject/compiler/kapt/ModelAst.kt b/kotlin-inject-compiler-kapt/src/main/kotlin/me/tatarka/inject/compiler/kapt/ModelAst.kt
index 20d37ea..83ff1af 100644
--- a/kotlin-inject-compiler-kapt/src/main/kotlin/me/tatarka/inject/compiler/kapt/ModelAst.kt
+++ b/kotlin-inject-compiler-kapt/src/main/kotlin/me/tatarka/inject/compiler/kapt/ModelAst.kt
@@ -19,7 +19,7 @@ import javax.tools.Diagnostic
 import kotlin.reflect.KClass
 
 interface ModelAstProvider :
-    AstProvider {
+        AstProvider {
 
     val env: ProcessingEnvironment
 
@@ -40,9 +40,9 @@ interface ModelAstProvider :
         for (element in ElementFilter.typesIn(packageElement.enclosedElements)) {
             for (function in ElementFilter.methodsIn(element.enclosedElements)) {
                 if (function.simpleName.contentEquals(functionName)
-                    && function.modifiers.contains(Modifier.STATIC) && function.modifiers.contains(Modifier.STATIC) && function.modifiers.contains(
-                        Modifier.FINAL
-                    )
+                        && function.modifiers.contains(Modifier.STATIC) && function.modifiers.contains(Modifier.STATIC) && function.modifiers.contains(
+                                Modifier.FINAL
+                        )
                 ) {
                     val metadata = element.metadata?.toKmPackage() ?: continue
                     val kmFunction = metadata.functions.find { it.name == functionName } ?: continue
@@ -56,9 +56,9 @@ interface ModelAstProvider :
     override fun declaredTypeOf(klass: KClass<*>, vararg astTypes: AstType): AstType {
         val type = elements.getTypeElement(klass.java.canonicalName)
         return ModelAstType(
-            this,
-            declaredType(type, astTypes.asList()),
-            klass.toKmType()
+                this,
+                declaredType(type, astTypes.asList()),
+                klass.toKmType()
         )
     }
 
@@ -89,12 +89,12 @@ class ModelAstMessenger(private val messager: Messager) : Messenger {
 private interface ModelAstElement : ModelAstProvider, AstAnnotated {
     val element: Element
 
-    override fun <T : Annotation> hasAnnotation(kclass: KClass<T>): Boolean {
-        return element.getAnnotation(kclass.java) != null
+    override fun hasAnnotation(className: String): Boolean {
+        return element.hasAnnotation(className)
     }
 
-    override fun <T : Annotation> typeAnnotatedWith(kclass: KClass<T>): AstClass? {
-        return element.typeAnnotatedWith(kclass)?.toAstClass()
+    override fun typeAnnotatedWith(className: String): AstClass? {
+        return element.typeAnnotatedWith(className)?.toAstClass()
     }
 }
 
@@ -103,16 +103,16 @@ private interface ModelAstMethod : ModelAstElement {
 }
 
 private class ModelBasicElement(provider: ModelAstProvider, override val element: Element) : AstBasicElement(),
-    ModelAstElement, ModelAstProvider by provider {
+        ModelAstElement, ModelAstProvider by provider {
     override val simpleName: String get() = element.simpleName.toString()
 }
 
 private class ModelAstClass(
-    provider: ModelAstProvider,
-    override val element: TypeElement,
-    val kmClass: KmClass?
+        provider: ModelAstProvider,
+        override val element: TypeElement,
+        val kmClass: KmClass?
 ) : AstClass(),
-    ModelAstElement, ModelAstProvider by provider {
+        ModelAstElement, ModelAstProvider by provider {
 
     override val packageName: String get() = elements.getPackageOf(element).qualifiedName.toString()
 
@@ -120,7 +120,7 @@ private class ModelAstClass(
 
     override val modifiers: Set<AstModifier> by lazy {
         collectModifiers(
-            kmClass?.flags
+                kmClass?.flags
         )
     }
 
@@ -150,10 +150,10 @@ private class ModelAstClass(
         ElementFilter.constructorsIn(element.enclosedElements).mapNotNull { constructor ->
             //TODO: not sure how to match constructors
             ModelAstConstructor(
-                this,
-                this,
-                constructor,
-                kmClass?.constructors?.first()
+                    this,
+                    this,
+                    constructor,
+                    kmClass?.constructors?.first()
             )
         }.firstOrNull()
     }
@@ -164,20 +164,20 @@ private class ModelAstClass(
                 for (property in kmClass.properties) {
                     if (method.matches(property)) {
                         return@mapNotNull ModelAstProperty(
-                            this,
-                            element,
-                            method,
-                            property
+                                this,
+                                element,
+                                method,
+                                property
                         )
                     }
                 }
                 for (function in kmClass.functions) {
                     if (method.matches(function)) {
                         return@mapNotNull ModelAstFunction(
-                            this,
-                            element,
-                            method,
-                            function
+                                this,
+                                element,
+                                method,
+                                function
                         )
                     }
                 }
@@ -198,12 +198,12 @@ private class ModelAstClass(
 }
 
 private class ModelAstConstructor(
-    provider: ModelAstProvider,
-    parent: AstClass,
-    override val element: ExecutableElement,
-    private val kmConstructor: KmConstructor?
+        provider: ModelAstProvider,
+        parent: AstClass,
+        override val element: ExecutableElement,
+        private val kmConstructor: KmConstructor?
 ) : AstConstructor(parent),
-    ModelAstElement, ModelAstProvider by provider {
+        ModelAstElement, ModelAstProvider by provider {
 
     override val parameters: List<AstParam> by lazy {
         element.parameters.mapNotNull { element ->
@@ -211,9 +211,9 @@ private class ModelAstConstructor(
                 for (parameter in kmConstructor.valueParameters) {
                     if (element.simpleName.contentEquals(parameter.name)) {
                         return@mapNotNull ModelAstParam(
-                            this,
-                            element,
-                            parameter
+                                this,
+                                element,
+                                parameter
                         )
                     }
                 }
@@ -224,26 +224,26 @@ private class ModelAstConstructor(
 }
 
 private class ModelAstFunction(
-    provider: ModelAstProvider,
-    val parent: TypeElement,
-    override val element: ExecutableElement,
-    private val kmFunction: KmFunction
+        provider: ModelAstProvider,
+        val parent: TypeElement,
+        override val element: ExecutableElement,
+        private val kmFunction: KmFunction
 ) : AstFunction(),
-    ModelAstMethod, ModelAstProvider by provider {
+        ModelAstMethod, ModelAstProvider by provider {
 
     override val name: String get() = kmFunction.name
 
     override val modifiers: Set<AstModifier> by lazy {
         collectModifiers(
-            kmFunction.flags
+                kmFunction.flags
         )
     }
 
     override val returnType: AstType
         get() = ModelAstType(
-            this,
-            element.returnType,
-            kmFunction.returnType
+                this,
+                element.returnType,
+                kmFunction.returnType
         )
 
     override fun returnTypeFor(enclosingClass: AstClass): AstType {
@@ -251,9 +251,9 @@ private class ModelAstFunction(
         val declaredType = enclosingClass.element.asType() as DeclaredType
         val methodType = types.asMemberOf(declaredType, element) as ExecutableType
         return ModelAstType(
-            this,
-            methodType.returnType,
-            kmFunction.returnType
+                this,
+                methodType.returnType,
+                kmFunction.returnType
         )
     }
 
@@ -267,9 +267,9 @@ private class ModelAstFunction(
             for (parameter in kmFunction.valueParameters) {
                 if (element.simpleName.contentEquals(parameter.name)) {
                     return@mapNotNull ModelAstParam(
-                        this,
-                        element,
-                        parameter
+                            this,
+                            element,
+                            parameter
                     )
                 }
             }
@@ -288,12 +288,12 @@ private class ModelAstFunction(
 }
 
 private class ModelAstProperty(
-    provider: ModelAstProvider,
-    val parent: TypeElement,
-    override val element: ExecutableElement,
-    private val kmProperty: KmProperty
+        provider: ModelAstProvider,
+        val parent: TypeElement,
+        override val element: ExecutableElement,
+        private val kmProperty: KmProperty
 ) : AstProperty(),
-    ModelAstMethod, ModelAstProvider by provider {
+        ModelAstMethod, ModelAstProvider by provider {
 
     override val name: String get() = kmProperty.name
 
@@ -311,9 +311,9 @@ private class ModelAstProperty(
 
     override val returnType: AstType
         get() = ModelAstType(
-            this,
-            element.returnType,
-            kmProperty.returnType
+                this,
+                element.returnType,
+                kmProperty.returnType
         )
 
     override fun returnTypeFor(enclosingClass: AstClass): AstType {
@@ -321,9 +321,9 @@ private class ModelAstProperty(
         val declaredType = enclosingClass.element.asType() as DeclaredType
         val methodType = types.asMemberOf(declaredType, element) as ExecutableType
         return ModelAstType(
-            this,
-            methodType.returnType,
-            kmProperty.returnType
+                this,
+                methodType.returnType,
+                kmProperty.returnType
         )
     }
 
@@ -347,12 +347,12 @@ private class ModelAstProperty(
         return elements.overrides(element, other.element, parent)
     }
 
-    override fun <T : Annotation> hasAnnotation(kclass: KClass<T>): Boolean {
-        return annotatedElement?.getAnnotation(kclass.java) != null
+    override fun hasAnnotation(className: String): Boolean {
+        return annotatedElement?.hasAnnotation(className) == true
     }
 
-    override fun <T : Annotation> typeAnnotatedWith(kclass: KClass<T>): AstClass? {
-        return annotatedElement?.typeAnnotatedWith(kclass)?.toAstClass()
+    override fun typeAnnotatedWith(className: String): AstClass? {
+        return annotatedElement?.typeAnnotatedWith(className)?.toAstClass()
     }
 
     override fun asMemberName(): MemberName {
@@ -361,11 +361,11 @@ private class ModelAstProperty(
 }
 
 private class ModelAstType(
-    provider: ModelAstProvider,
-    val type: TypeMirror,
-    private val kmType: KmType?
+        provider: ModelAstProvider,
+        val type: TypeMirror,
+        private val kmType: KmType?
 ) : AstType(),
-    ModelAstElement, ModelAstProvider by provider {
+        ModelAstElement, ModelAstProvider by provider {
 
     override val element: Element get() = types.asElement(type)
 
@@ -378,9 +378,9 @@ private class ModelAstType(
             kmType.annotations.map { annotation ->
                 val mirror = provider.elements.getTypeElement(annotation.className.replace('/', '.'))
                 ModelAstAnnotation(
-                    this,
-                    mirror.asType() as DeclaredType,
-                    annotation
+                        this,
+                        mirror.asType() as DeclaredType,
+                        annotation
                 )
             }
         } else {
@@ -406,14 +406,14 @@ private class ModelAstType(
     override fun isUnit(): Boolean = type is NoType
 
     override fun asElement(): AstBasicElement =
-        ModelBasicElement(this, element)
+            ModelBasicElement(this, element)
 
     override fun toAstClass(): AstClass = (element as TypeElement).toAstClass()
 
     private fun rawTypeName(): ClassName {
         val kotlinClassName =
-            (kmType?.classifier as? KmClassifier.Class)?.name?.replace('/', '.')?.let { ClassName.bestGuess(it) }
-                ?: ((type as DeclaredType).asElement() as TypeElement).asClassName()
+                (kmType?.classifier as? KmClassifier.Class)?.name?.replace('/', '.')?.let { ClassName.bestGuess(it) }
+                        ?: ((type as DeclaredType).asElement() as TypeElement).asClassName()
         return when (kotlinClassName.canonicalName) {
             "java.util.Map" -> ClassName("kotlin.collections", "Map")
             "java.util.Set" -> ClassName("kotlin.collections", "Set")
@@ -442,7 +442,7 @@ private class ModelAstType(
                 val rawType: ClassName = rawTypeName().copy(nullable = isNullable) as ClassName
                 val enclosingType = t.enclosingType
                 val enclosing = if (enclosingType.kind != TypeKind.NONE &&
-                    Modifier.STATIC !in t.asElement().modifiers
+                        Modifier.STATIC !in t.asElement().modifiers
                 )
                     enclosingType.accept(this, null) else
                     null
@@ -468,8 +468,8 @@ private class ModelAstType(
             }
 
             override fun visitTypeVariable(
-                t: TypeVariable,
-                p: Void?
+                    t: TypeVariable,
+                    p: Void?
             ): TypeName {
                 return t.asTypeVariableName()
             }
@@ -511,11 +511,11 @@ private class ModelAstType(
 }
 
 private class ModelAstAnnotation(
-    provider: ModelAstProvider,
-    val annotationType: DeclaredType,
-    private val kmAnnotation: KmAnnotation
+        provider: ModelAstProvider,
+        val annotationType: DeclaredType,
+        private val kmAnnotation: KmAnnotation
 ) : AstAnnotation(),
-    ModelAstElement, ModelAstProvider by provider {
+        ModelAstElement, ModelAstProvider by provider {
     override val element: Element get() = types.asElement(annotationType)
 
     override fun equals(other: Any?): Boolean {
@@ -530,17 +530,17 @@ private class ModelAstAnnotation(
     override fun toString(): String {
         return "@$annotationType(${
             kmAnnotation.arguments.toList()
-                .joinToString(separator = ", ") { (name, value) -> "$name=${value.value}" }
+                    .joinToString(separator = ", ") { (name, value) -> "$name=${value.value}" }
         })"
     }
 }
 
 private class ModelAstParam(
-    provider: ModelAstProvider,
-    override val element: VariableElement,
-    val kmValueParameter: KmValueParameter
+        provider: ModelAstProvider,
+        override val element: VariableElement,
+        val kmValueParameter: KmValueParameter
 ) : AstParam(),
-    ModelAstElement, ModelAstProvider by provider {
+        ModelAstElement, ModelAstProvider by provider {
 
     override val name: String get() = kmValueParameter.name
 
diff --git a/kotlin-inject-compiler-kapt/src/main/kotlin/me/tatarka/inject/compiler/kapt/ScopedInjectCompiler.kt b/kotlin-inject-compiler-kapt/src/main/kotlin/me/tatarka/inject/compiler/kapt/ScopedInjectCompiler.kt
index 00a2220..399231e 100644
--- a/kotlin-inject-compiler-kapt/src/main/kotlin/me/tatarka/inject/compiler/kapt/ScopedInjectCompiler.kt
+++ b/kotlin-inject-compiler-kapt/src/main/kotlin/me/tatarka/inject/compiler/kapt/ScopedInjectCompiler.kt
@@ -17,9 +17,9 @@ class ScopedInjectCompiler : BaseInjectCompiler() {
             if (element !is TypeElement) continue
             val astClass = element.toAstClass()
             // Only deal with scoped components
-            val scopedClass = astClass.scopeClass(messenger) ?: continue
+            val scopedClass = astClass.scopeClass(messenger, options) ?: continue
 
-            val scopeType = scopedClass.scopeType()!!
+            val scopeType = scopedClass.scopeType(options)!!
             val scopedClasses = scopedClasses(scopeType, env)
             allScopedClasses.addAll(scopedClasses)
 
diff --git a/kotlin-inject-compiler-kapt/src/main/kotlin/me/tatarka/inject/compiler/kapt/Util.kt b/kotlin-inject-compiler-kapt/src/main/kotlin/me/tatarka/inject/compiler/kapt/Util.kt
index 57c19c0..f912682 100644
--- a/kotlin-inject-compiler-kapt/src/main/kotlin/me/tatarka/inject/compiler/kapt/Util.kt
+++ b/kotlin-inject-compiler-kapt/src/main/kotlin/me/tatarka/inject/compiler/kapt/Util.kt
@@ -11,18 +11,19 @@ import javax.lang.model.element.Element
 import javax.lang.model.element.ExecutableElement
 import javax.lang.model.element.TypeElement
 import javax.lang.model.type.TypeMirror
-import kotlin.reflect.KClass
 
-fun <T : Annotation> Element.typeAnnotatedWith(type: KClass<T>) =
-    annotationMirrors.find {
-        it.annotationType.asElement().getAnnotation(type.java) != null
-    }?.annotationType?.asElement() as? TypeElement
+fun Element.hasAnnotation(className: String): Boolean {
+    return annotationMirrors.any { it.annotationType.toString() == className }
+}
 
-inline fun <reified T : Annotation> Element.typeAnnotatedWith() = typeAnnotatedWith(T::class)
+fun Element.typeAnnotatedWith(className: String) =
+        annotationMirrors.find {
+            it.annotationType.asElement().hasAnnotation(className)
+        }?.annotationType?.asElement() as? TypeElement
 
 fun TypeName.javaToKotlinType(): TypeName = if (this is ParameterizedTypeName) {
     (rawType.javaToKotlinType() as ClassName).parameterizedBy(
-        *typeArguments.map { it.javaToKotlinType() }.toTypedArray()
+            *typeArguments.map { it.javaToKotlinType() }.toTypedArray()
     )
 } else if (this is WildcardTypeName) {
     if (inTypes.isNotEmpty()) {
@@ -52,14 +53,14 @@ val TypeElement.metadata: KotlinClassMetadata?
     get() {
         val meta = getAnnotation(Metadata::class.java) ?: return null
         val header = KotlinClassHeader(
-            kind = meta.kind,
-            bytecodeVersion = meta.bytecodeVersion,
-            data1 = meta.data1,
-            data2 = meta.data2,
-            extraInt = meta.extraInt,
-            extraString = meta.extraString,
-            metadataVersion = meta.metadataVersion,
-            packageName = meta.packageName
+                kind = meta.kind,
+                bytecodeVersion = meta.bytecodeVersion,
+                data1 = meta.data1,
+                data2 = meta.data2,
+                extraInt = meta.extraInt,
+                extraString = meta.extraString,
+                metadataVersion = meta.metadataVersion,
+                packageName = meta.packageName
         )
         return KotlinClassMetadata.read(header)
     }
diff --git a/kotlin-inject-compiler-ksp/src/main/kotlin/me/tatarka/inject/compiler/ksp/InjectProcessor.kt b/kotlin-inject-compiler-ksp/src/main/kotlin/me/tatarka/inject/compiler/ksp/InjectProcessor.kt
index de82f6f..a2d2412 100644
--- a/kotlin-inject-compiler-ksp/src/main/kotlin/me/tatarka/inject/compiler/ksp/InjectProcessor.kt
+++ b/kotlin-inject-compiler-ksp/src/main/kotlin/me/tatarka/inject/compiler/ksp/InjectProcessor.kt
@@ -36,9 +36,9 @@ class InjectProcessor : SymbolProcessor, KSAstProvider {
         for (element in resolver.getSymbolsWithAnnotation(Component::class.qualifiedName!!)) {
             if (element !is KSClassDeclaration) continue
             val astClass = element.toAstClass()
-            val scopedClass = astClass.scopeClass(messenger)
+            val scopedClass = astClass.scopeClass(messenger, options)
 
-            val scopeType = scopedClass?.scopeType()
+            val scopeType = scopedClass?.scopeType(options)
             val scopedClasses = scopeType?.let { scopedClasses(it, resolver) } ?: emptyList()
             allScopeClasses.addAll(scopedClasses)
 
diff --git a/kotlin-inject-compiler-ksp/src/main/kotlin/me/tatarka/inject/compiler/ksp/KSAst.kt b/kotlin-inject-compiler-ksp/src/main/kotlin/me/tatarka/inject/compiler/ksp/KSAst.kt
index 012108f..1a0b30c 100644
--- a/kotlin-inject-compiler-ksp/src/main/kotlin/me/tatarka/inject/compiler/ksp/KSAst.kt
+++ b/kotlin-inject-compiler-ksp/src/main/kotlin/me/tatarka/inject/compiler/ksp/KSAst.kt
@@ -96,12 +96,12 @@ object KSAstMessenger : Messenger {
 private interface KSAstAnnotated : AstAnnotated, KSAstProvider {
     val declaration: KSAnnotated
 
-    override fun <T : Annotation> hasAnnotation(kclass: KClass<T>): Boolean {
-        return declaration.getAnnotation(kclass) != null
+    override fun hasAnnotation(className: String): Boolean {
+        return declaration.hasAnnotation(className)
     }
 
-    override fun <T : Annotation> typeAnnotatedWith(kclass: KClass<T>): AstClass? {
-        return (declaration.typeAnnotatedWith(kclass)?.declaration as? KSClassDeclaration)?.toAstClass()
+    override fun typeAnnotatedWith(className: String): AstClass? {
+        return (declaration.typeAnnotatedWith(className)?.declaration as? KSClassDeclaration)?.toAstClass()
     }
 }
 
@@ -189,9 +189,9 @@ private class KSAstEmptyConstructor(
 
     override val parameters: List<AstParam> = emptyList()
 
-    override fun <T : Annotation> hasAnnotation(kclass: KClass<T>): Boolean = false
+    override fun hasAnnotation(className: String): Boolean = false
 
-    override fun <T : Annotation> typeAnnotatedWith(kclass: KClass<T>): AstClass? = null
+    override fun typeAnnotatedWith(className: String): AstClass? = null
 }
 
 private class KSAstFunction(provider: KSAstProvider, override val declaration: KSFunctionDeclaration) : AstFunction(),
diff --git a/kotlin-inject-compiler-ksp/src/main/kotlin/me/tatarka/inject/compiler/ksp/Util.kt b/kotlin-inject-compiler-ksp/src/main/kotlin/me/tatarka/inject/compiler/ksp/Util.kt
index a97b789..616d341 100644
--- a/kotlin-inject-compiler-ksp/src/main/kotlin/me/tatarka/inject/compiler/ksp/Util.kt
+++ b/kotlin-inject-compiler-ksp/src/main/kotlin/me/tatarka/inject/compiler/ksp/Util.kt
@@ -10,22 +10,18 @@ import org.jetbrains.kotlin.ksp.symbol.*
 import org.jetbrains.kotlin.ksp.visitor.KSDefaultVisitor
 import kotlin.reflect.KClass
 
-
-fun <T : Annotation> KSAnnotated.typeAnnotatedWith(type: KClass<T>): KSType? {
+fun KSAnnotated.typeAnnotatedWith(className: String): KSType? {
     for (annotation in annotations) {
         val t = annotation.annotationType.resolve()
-        val a = t?.declaration?.getAnnotation(type)
-        if (a != null) {
+        if (t?.declaration?.hasAnnotation(className) == true) {
             return t
         }
     }
     return null
 }
 
-inline fun <reified T : Annotation> KSDeclaration.typeAnnotatedWith() = typeAnnotatedWith(T::class)
-
-fun KSAnnotated.getAnnotation(type: KClass<out Annotation>): KSAnnotation? {
-    return annotations.find { it.annotationType.resolve()?.declaration?.qualifiedName?.asString() == type.qualifiedName }
+fun KSAnnotated.hasAnnotation(className: String): Boolean {
+    return annotations.any { it.annotationType.resolve()?.declaration?.qualifiedName?.asString() == className }
 }
 
 fun KSDeclaration.asClassName(): ClassName {


Test patch:
diff --git a/integration-tests-kapt/build.gradle b/integration-tests-kapt/build.gradle
index 7b0cc29..059a053 100644
--- a/integration-tests-kapt/build.gradle
+++ b/integration-tests-kapt/build.gradle
@@ -14,6 +14,7 @@ dependencies {
     testImplementation "org.jetbrains.kotlin:kotlin-test"
     testImplementation "org.jetbrains.kotlin:kotlin-test-junit"
     testImplementation 'org.jetbrains.kotlin:kotlin-reflect'
+    testImplementation 'javax.inject:javax.inject:1'
 
     testImplementation 'com.willowtreeapps.assertk:assertk-jvm:0.22'
 }
@@ -24,6 +25,12 @@ sourceSets {
     }
 }
 
+kapt {
+    arguments {
+        arg("me.tatarka.inject.enableJavaxAnnotations", "true")
+    }
+}
+
 sourceCompatibility = 1.8
 targetCompatibility = 1.8
 
diff --git a/integration-tests-kapt/src/test/kotlin/me/tatarka/inject/test/JavaxAnnotationTest.kt b/integration-tests-kapt/src/test/kotlin/me/tatarka/inject/test/JavaxAnnotationTest.kt
new file mode 100644
index 0000000..f9ae181
--- /dev/null
+++ b/integration-tests-kapt/src/test/kotlin/me/tatarka/inject/test/JavaxAnnotationTest.kt
@@ -0,0 +1,30 @@
+package me.tatarka.inject.test
+
+import assertk.assertThat
+import assertk.assertions.isNotNull
+import me.tatarka.inject.annotations.Component
+import javax.inject.Inject
+import javax.inject.Scope
+import kotlin.test.Test
+
+@Scope
+annotation class JavaxScope
+
+@JavaxScope
+class JavaxFoo @Inject constructor()
+
+@JavaxScope
+@Component
+abstract class JavaxComponent {
+    abstract val foo: JavaxFoo
+}
+
+class JavaxAnnotationTest {
+
+    @Test
+    fun generates_a_component_that_provides_a_dep_using_javax_annotations() {
+        val component = JavaxComponent::class.create()
+
+        assertThat(component.foo).isNotNull()
+    }
+}
\ No newline at end of file
diff --git a/integration-tests-ksp/build.gradle b/integration-tests-ksp/build.gradle
index f62da74..2090292 100644
--- a/integration-tests-ksp/build.gradle
+++ b/integration-tests-ksp/build.gradle
@@ -12,6 +12,7 @@ dependencies {
     testImplementation "org.jetbrains.kotlin:kotlin-test"
     testImplementation "org.jetbrains.kotlin:kotlin-test-junit"
     testImplementation 'org.jetbrains.kotlin:kotlin-reflect'
+    testImplementation 'javax.inject:javax.inject:1'
 
     testImplementation 'com.willowtreeapps.assertk:assertk-jvm:0.22'
 }