Fix loadService with fallback implementation

This commit is contained in:
Him188 2021-08-09 23:43:43 +08:00
parent 5950e9e1e8
commit 45cc60c8e9
3 changed files with 13 additions and 8 deletions

View File

@ -47,17 +47,19 @@ public actual inline fun <reified E> Throwable.unwrap(): Throwable {
public actual fun <T : Any> loadService(clazz: KClass<out T>, fallbackImplementation: String?): T { public actual fun <T : Any> loadService(clazz: KClass<out T>, fallbackImplementation: String?): T {
var suppressed: Throwable? = null var suppressed: Throwable? = null
return ServiceLoader.load(clazz.java).firstOrNull() return ServiceLoader.load(clazz.java).firstOrNull()
?: runCatching { findCreateInstance<T>(fallbackImplementation) }.onFailure { suppressed = it }.getOrNull() ?: (if (fallbackImplementation == null) null
else runCatching { findCreateInstance<T>(fallbackImplementation) }.onFailure { suppressed = it }.getOrNull())
?: throw NoSuchElementException("Could not find an implementation for service class ${clazz.qualifiedName}").apply { ?: throw NoSuchElementException("Could not find an implementation for service class ${clazz.qualifiedName}").apply {
if (suppressed != null) addSuppressed(suppressed) if (suppressed != null) addSuppressed(suppressed)
} }
} }
private fun <T : Any> findCreateInstance(fallbackImplementation: String?): T { private fun <T : Any> findCreateInstance(fallbackImplementation: String): T {
return Class.forName(fallbackImplementation).cast<Class<out T>>().kotlin.run { objectInstance ?: createInstance() } return Class.forName(fallbackImplementation).cast<Class<out T>>().kotlin.run { objectInstance ?: createInstance() }
} }
public actual fun <T : Any> loadServiceOrNull(clazz: KClass<out T>, fallbackImplementation: String?): T? { public actual fun <T : Any> loadServiceOrNull(clazz: KClass<out T>, fallbackImplementation: String?): T? {
return ServiceLoader.load(clazz.java).firstOrNull() return ServiceLoader.load(clazz.java).firstOrNull()
?: runCatching { findCreateInstance<T>(fallbackImplementation) }.getOrNull() ?: if (fallbackImplementation == null) return null
else runCatching { findCreateInstance<T>(fallbackImplementation) }.getOrNull()
} }

View File

@ -17,5 +17,6 @@ public expect fun <T : Any> loadService(clazz: KClass<out T>, fallbackImplementa
public inline fun <reified T : Any> loadService(fallbackImplementation: String? = null): T = public inline fun <reified T : Any> loadService(fallbackImplementation: String? = null): T =
loadService(T::class, fallbackImplementation) loadService(T::class, fallbackImplementation)
public inline fun <reified T : Any> loadService(noinline fallbackImplementation: () -> T): T = // do not inline: T will be inferred to returning type of `fallbackImplementation`
loadServiceOrNull(T::class) ?: fallbackImplementation() public fun <T : Any> loadService(clazz: KClass<out T>, fallbackImplementation: () -> T): T =
loadServiceOrNull(clazz) ?: fallbackImplementation()

View File

@ -35,17 +35,19 @@ public actual inline fun <reified E> Throwable.unwrap(): Throwable {
public actual fun <T : Any> loadService(clazz: KClass<out T>, fallbackImplementation: String?): T { public actual fun <T : Any> loadService(clazz: KClass<out T>, fallbackImplementation: String?): T {
var suppressed: Throwable? = null var suppressed: Throwable? = null
return ServiceLoader.load(clazz.java).firstOrNull() return ServiceLoader.load(clazz.java).firstOrNull()
?: runCatching { findCreateInstance<T>(fallbackImplementation) }.onFailure { suppressed = it }.getOrNull() ?: (if (fallbackImplementation == null) null
else runCatching { findCreateInstance<T>(fallbackImplementation) }.onFailure { suppressed = it }.getOrNull())
?: throw NoSuchElementException("Could not find an implementation for service class ${clazz.qualifiedName}").apply { ?: throw NoSuchElementException("Could not find an implementation for service class ${clazz.qualifiedName}").apply {
if (suppressed != null) addSuppressed(suppressed) if (suppressed != null) addSuppressed(suppressed)
} }
} }
private fun <T : Any> findCreateInstance(fallbackImplementation: String?): T { private fun <T : Any> findCreateInstance(fallbackImplementation: String): T {
return Class.forName(fallbackImplementation).cast<Class<out T>>().kotlin.run { objectInstance ?: createInstance() } return Class.forName(fallbackImplementation).cast<Class<out T>>().kotlin.run { objectInstance ?: createInstance() }
} }
public actual fun <T : Any> loadServiceOrNull(clazz: KClass<out T>, fallbackImplementation: String?): T? { public actual fun <T : Any> loadServiceOrNull(clazz: KClass<out T>, fallbackImplementation: String?): T? {
return ServiceLoader.load(clazz.java).firstOrNull() return ServiceLoader.load(clazz.java).firstOrNull()
?: runCatching { findCreateInstance<T>(fallbackImplementation) }.getOrNull() ?: if (fallbackImplementation == null) return null
else runCatching { findCreateInstance<T>(fallbackImplementation) }.getOrNull()
} }