diff --git a/compiler/container/container.iml b/compiler/container/container.iml
index b530e6a1ccb..27d4bcddea0 100644
--- a/compiler/container/container.iml
+++ b/compiler/container/container.iml
@@ -15,5 +15,6 @@
+
\ No newline at end of file
diff --git a/compiler/container/src/org/jetbrains/kotlin/container/Cache.kt b/compiler/container/src/org/jetbrains/kotlin/container/Cache.kt
index a634e9070c6..978eb36c077 100644
--- a/compiler/container/src/org/jetbrains/kotlin/container/Cache.kt
+++ b/compiler/container/src/org/jetbrains/kotlin/container/Cache.kt
@@ -42,7 +42,8 @@ fun Class<*>.getInfo(): ClassInfo {
data class ClassInfo(
val constructorInfo: ConstructorInfo?,
val setterInfos: List,
- val registrations: List
+ val registrations: List,
+ val defaultImplementation: Class<*>?
)
data class ConstructorInfo(
@@ -56,7 +57,7 @@ data class SetterInfo(
)
private fun traverseClass(c: Class<*>): ClassInfo {
- return ClassInfo(getConstructorInfo(c), getSetterInfos(c), getRegistrations(c))
+ return ClassInfo(getConstructorInfo(c), getSetterInfos(c), getRegistrations(c), getDefaultImplementation(c))
}
private fun getSetterInfos(c: Class<*>): List {
@@ -99,6 +100,10 @@ private fun collectInterfacesRecursive(type: Type, result: MutableSet) {
}
}
+private fun getDefaultImplementation(klass: Class<*>): Class<*>? {
+ return klass.getAnnotation(DefaultImplementation::class.java)?.impl?.java
+}
+
private fun getRegistrations(klass: Class<*>): List {
val registrations = ArrayList()
diff --git a/compiler/container/src/org/jetbrains/kotlin/container/Components.kt b/compiler/container/src/org/jetbrains/kotlin/container/Components.kt
index 0f431005938..3013a80baf1 100644
--- a/compiler/container/src/org/jetbrains/kotlin/container/Components.kt
+++ b/compiler/container/src/org/jetbrains/kotlin/container/Components.kt
@@ -18,7 +18,7 @@ package org.jetbrains.kotlin.container
import java.lang.reflect.*
-class InstanceComponentDescriptor(val instance: Any) : ComponentDescriptor {
+open class InstanceComponentDescriptor(val instance: Any) : ComponentDescriptor {
override fun getValue(): Any = instance
override fun getRegistrations(): Iterable = instance::class.java.getInfo().registrations
@@ -28,4 +28,8 @@ class InstanceComponentDescriptor(val instance: Any) : ComponentDescriptor {
override fun toString(): String {
return "Instance: ${instance::class.java.simpleName}"
}
+}
+
+class DefaultInstanceComponentDescriptor(instance: Any): InstanceComponentDescriptor(instance) {
+ override fun toString() = "Default instance: ${instance.javaClass.simpleName}"
}
\ No newline at end of file
diff --git a/compiler/container/src/org/jetbrains/kotlin/container/Singletons.kt b/compiler/container/src/org/jetbrains/kotlin/container/Singletons.kt
index d5ec9b63190..0561875cd41 100644
--- a/compiler/container/src/org/jetbrains/kotlin/container/Singletons.kt
+++ b/compiler/container/src/org/jetbrains/kotlin/container/Singletons.kt
@@ -148,4 +148,10 @@ class ImplicitSingletonTypeComponentDescriptor(container: ComponentContainer, kl
override fun toString(): String {
return "Implicit: ${klass.simpleName}"
}
+}
+
+class DefaultSingletonTypeComponentDescriptor(container: ComponentContainer, klass: Class<*>) : SingletonTypeComponentDescriptor(container, klass) {
+ override fun toString(): String {
+ return "Default: ${klass.simpleName}"
+ }
}
\ No newline at end of file
diff --git a/compiler/container/src/org/jetbrains/kotlin/container/Storage.kt b/compiler/container/src/org/jetbrains/kotlin/container/Storage.kt
index 99d85c859a5..7f88e8bcfbd 100644
--- a/compiler/container/src/org/jetbrains/kotlin/container/Storage.kt
+++ b/compiler/container/src/org/jetbrains/kotlin/container/Storage.kt
@@ -161,18 +161,32 @@ class ComponentStorage(val myId: String, parent: ComponentStorage?) : ValueResol
is ParameterizedType -> type.rawType as? Class<*>
else -> null
}
- if (rawType == null)
- continue
- if (!Modifier.isAbstract(rawType.modifiers) && !rawType.isPrimitive) {
- val implicitDescriptor = ImplicitSingletonTypeComponentDescriptor(context.container, rawType)
- adhocDescriptors.add(implicitDescriptor)
- collectAdhocComponents(context, implicitDescriptor, visitedTypes, adhocDescriptors)
- }
+ val implicitDependency = rawType?.let { getImplicitlyDefinedDependency(context, it) } ?: continue
+
+ adhocDescriptors.add(implicitDependency)
+ collectAdhocComponents(context, implicitDependency, visitedTypes, adhocDescriptors)
}
}
}
+ private fun getImplicitlyDefinedDependency(context: ComponentResolveContext, rawType: Class<*>): ComponentDescriptor? {
+ if (!Modifier.isAbstract(rawType.modifiers) && !rawType.isPrimitive) {
+ return ImplicitSingletonTypeComponentDescriptor(context.container, rawType)
+ }
+
+ val defaultImplementation = rawType.getInfo().defaultImplementation
+ if (defaultImplementation != null && defaultImplementation.getInfo().constructorInfo != null) {
+ return DefaultSingletonTypeComponentDescriptor(context.container, defaultImplementation)
+ }
+
+ if (defaultImplementation != null) {
+ return defaultImplementation.getField("INSTANCE")?.get(null)?.let(::DefaultInstanceComponentDescriptor)
+ }
+
+ return null
+ }
+
private fun injectProperties(instance: Any, context: ValueResolveContext) {
val classInfo = instance::class.java.getInfo()
diff --git a/compiler/container/tests/org/jetbrains/kotlin/container/tests/ComponentContainerTest.kt b/compiler/container/tests/org/jetbrains/kotlin/container/tests/ComponentContainerTest.kt
index 67ba115a351..07c292da753 100644
--- a/compiler/container/tests/org/jetbrains/kotlin/container/tests/ComponentContainerTest.kt
+++ b/compiler/container/tests/org/jetbrains/kotlin/container/tests/ComponentContainerTest.kt
@@ -311,4 +311,51 @@ class ComponentContainerTest {
assertTrue(a === bc1.get().a)
assertTrue(a === bc1.get())
}
+
+ @DefaultImplementation(impl = Impl::class)
+ abstract class I
+
+ class Impl : I()
+
+ class Impl2: I()
+
+ class Use(val i: I)
+
+ @Test
+ fun default_implementation() {
+ class Use(val i: I)
+
+ val u = composeContainer("a") {
+ useImpl