All Downloads are FREE. Search and download functionalities are using the official Maven repository.

name.remal.gradle_plugins.dsl.extensions.kotlin.Any.kt Maven / Gradle / Ivy

There is a newer version: 1.9.2
Show newest version
package name.remal.gradle_plugins.dsl.extensions

import groovy.lang.Closure
import name.remal.filterNotNull
import name.remal.fromUpperCamelToLowerCamel
import name.remal.getCompatibleMethod
import name.remal.lambda.Function0
import name.remal.lambda.Function1
import name.remal.lambda.VoidFunction1
import name.remal.orNull
import name.remal.toList
import name.remal.uncheckedCast
import org.gradle.api.Action
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.artifacts.repositories.ArtifactRepository
import org.gradle.api.artifacts.repositories.MavenArtifactRepository
import org.gradle.api.internal.HasConvention
import org.gradle.api.internal.IConventionAware
import org.gradle.api.plugins.Convention
import org.gradle.api.provider.Provider
import java.util.Enumeration
import java.util.Optional
import java.util.OptionalDouble
import java.util.OptionalInt
import java.util.OptionalLong
import java.util.concurrent.Callable
import java.util.concurrent.CompletionStage
import java.util.concurrent.Future
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.atomic.AtomicLong
import java.util.concurrent.atomic.AtomicReference
import java.util.function.BooleanSupplier
import java.util.function.Consumer
import java.util.function.DoubleSupplier
import java.util.function.IntSupplier
import java.util.function.LongSupplier
import java.util.function.Supplier
import java.util.stream.Stream
import kotlin.DeprecationLevel.HIDDEN
import kotlin.reflect.KFunction0
import kotlin.reflect.KProperty1
import kotlin.reflect.jvm.javaMethod
import java.lang.reflect.Array as ReflectArray
import java.util.function.Function as JFunction
import kotlin.Function1 as KFunction1
import kotlin.reflect.KFunction1 as KReflectFunction1

val Any.convention: Convention
    get() = when (this) {
        is Project -> this.convention
        is Task -> this.convention
        else -> (this as HasConvention).convention
    }

val Any.conventionOrNull: Convention?
    get() = when (this) {
        is Project -> this.convention
        is Task -> this.convention
        is HasConvention -> this.convention
        else -> null
    }


fun Any.addObjectMarker(markerType: Class): Boolean {
    val convention = conventionOrNull ?: return false
    if (markerType in convention) return false
    val marker = markerType.getDeclaredConstructor()
        .apply { isAccessible = true }
        .newInstance()
    convention.addPlugin(marker)
    return true
}

fun Any.hasObjectMarker(markerType: Class) = markerType in conventionOrNull

interface ObjectMarker


data class ConventionWithSelf(val convention: Convention, val self: T)

val  T.conventionWithSelf: ConventionWithSelf get() = ConventionWithSelf(this.convention, this)


fun  T.defaultPropertyValue(property: KProperty1, func: (self: T) -> P) {
    this as IConventionAware
    conventionMapping.map(property.name) { func(this) }
}

fun  T.defaultPropertyValue(property: KReflectFunction1, func: (self: T) -> P) {
    val method = property.javaMethod ?: throw IllegalArgumentException("$property is not a method reference")
    val name: String
    if (method.name.length > 3 && method.name.startsWith("get") && method.name[3].isUpperCase()) {
        name = method.name.substring(3).fromUpperCamelToLowerCamel()
    } else if (method.name.length > 2 && method.name.startsWith("is") && method.name[2].isUpperCase()) {
        name = method.name.substring(2).fromUpperCamelToLowerCamel()
    } else {
        throw IllegalArgumentException("Property name can't be retrieved for $property")
    }
    this as IConventionAware
    conventionMapping.map(name) { func(this) }
}


@Suppress("ComplexMethod")
fun  T.configureWith(configurer: Any?): T = apply {
    if (configurer == null) {
        // do nothing
    } else if (configurer is Action<*>) {
        configurer.uncheckedCast>().execute(this)
    } else if (configurer is Closure<*>) {
        configurer.toConfigureAction().execute(this)
    } else if (configurer is Consumer<*>) {
        configurer.uncheckedCast>().toConfigureAction().execute(this)
    } else if (configurer is JFunction<*, *>) {
        configurer.uncheckedCast>().toConfigureAction().execute(this)
    } else if (configurer is KFunction1<*, *>) {
        configurer.uncheckedCast>().toConfigureAction().execute(this)
    } else if (configurer is KReflectFunction1<*, *>) {
        configurer.uncheckedCast>().toConfigureAction().execute(this)
    } else if (configurer is Function1<*, *>) {
        configurer.uncheckedCast>().toConfigureAction().execute(this)
    } else if (configurer is VoidFunction1<*>) {
        configurer.uncheckedCast>().toConfigureAction().execute(this)
    } else {
        throw IllegalArgumentException("Unsupported configurer: ${configurer.javaClass.name}")
    }
}


fun Any?.flattenAny(): List = unwrapProviders().let {
    if (it == null) {
        return emptyList()

    } else if (it is Array<*>) {
        return it.asSequence().flattenAny()

    } else if (it is Iterable<*>) {
        return it.asSequence().flattenAny()

    } else if (it is Iterator<*>) {
        return it.asSequence().flattenAny()

    } else if (it is Enumeration<*>) {
        return it.asSequence().flattenAny()

    } else if (it is Sequence<*>) {
        return it
            .filterNotNull()
            .flatMap { it.flattenAny().asSequence() }
            .toList()

    } else if (it is Stream<*>) {
        return it
            .filterNotNull()
            .flatMap { it.flattenAny().stream() }
            .toList()

    } else {
        return listOf(it)
    }
}


@Suppress("ComplexMethod")
fun Any?.unwrapProviders(): Any? = when (this) {
    null -> null
    is Optional<*> -> this.orNull.unwrapProviders()
    is OptionalInt -> if (this.isPresent) this.asInt else null
    is OptionalLong -> if (this.isPresent) this.asLong else null
    is OptionalDouble -> if (this.isPresent) this.asDouble else null
    is Callable<*> -> this.call().unwrapProviders()
    is Supplier<*> -> this.get().unwrapProviders()
    is BooleanSupplier -> this.asBoolean
    is IntSupplier -> this.asInt
    is LongSupplier -> this.asLong
    is DoubleSupplier -> this.asDouble
    is Future<*> -> this.get().unwrapProviders()
    is CompletionStage<*> -> this.toCompletableFuture().get().unwrapProviders()
    is AtomicBoolean -> this.get().unwrapProviders()
    is AtomicInteger -> this.get().unwrapProviders()
    is AtomicLong -> this.get().unwrapProviders()
    is AtomicReference<*> -> this.get().unwrapProviders()
    is Lazy<*> -> this.value.unwrapProviders()
    is KFunction0<*> -> this.call().unwrapProviders()
    is Closure<*> -> this.call().unwrapProviders()
    is Provider<*> -> this.orNull.unwrapProviders()
    is Function0<*> -> this.invoke().unwrapProviders()
    else -> this
}


@Suppress("ReturnCount")
fun Any?.toStringSmart(): String {
    if (this == null) return "null"

    if (this.javaClass.isArray) {
        return buildString {
            append("[")
            (0 until ReflectArray.getLength(this@toStringSmart)).joinTo(
                this,
                ", ",
                transform = { ReflectArray.get(this@toStringSmart, it).toStringSmart() }
            )
            append("]")
        }
    }

    if (this is Iterable<*>) {
        return buildString {
            append("[")
            [email protected](this, ", ", transform = { it.toStringSmart() })
            append("]")
        }
    }

    val toStringDeclaringClass = this.javaClass.getMethod("toString").declaringClass
    if (Any::class.java == toStringDeclaringClass || toStringDeclaringClass.isInterface) {
        when (this) {
            is MavenArtifactRepository -> return "$name($url)"
            is ArtifactRepository -> return name
        }
    }

    return toString()
}

fun Any.invokeCompatibleMethod(name: String, vararg params: Any) {
    val method = javaClass.getCompatibleMethod(name, *params.map(Any::javaClass).toTypedArray())
    method.isAccessible = true
    method.invoke(this, *params)
}

fun  Any.invokeCompatibleMethod(returnType: Class, name: String, vararg params: Any): R {
    val method = javaClass.getCompatibleMethod(returnType, name, *params.map(Any::javaClass).toTypedArray())
    method.isAccessible = true
    val result = method.invoke(this, *params)
        ?: throw IllegalStateException("$method returned NULL")
    return result.uncheckedCast()
}

fun  Any.invokeNullableCompatibleMethod(returnType: Class, name: String, vararg params: Any): R? {
    val method = javaClass.getCompatibleMethod(returnType, name, *params.map(Any::javaClass).toTypedArray())
    method.isAccessible = true
    return method.invoke(this, *params)?.uncheckedCast()
}

@Deprecated("invokeCompatibleMethod() can't be called on Unit", level = HIDDEN)
@Suppress("unused", "UNUSED_PARAMETER")
fun Unit.invokeCompatibleMethod(name: String, vararg params: Any) {
    throw UnsupportedOperationException()
}

@Deprecated("invokeCompatibleMethod() can't be called on Unit", level = HIDDEN)
@Suppress("unused", "UNUSED_PARAMETER")
fun  Unit.invokeCompatibleMethod(returnType: Class, name: String, vararg params: Any): R {
    throw UnsupportedOperationException()
}

@Deprecated("invokeNullableCompatibleMethod() can't be called on Unit", level = HIDDEN)
@Suppress("unused", "UNUSED_PARAMETER")
fun  Unit.invokeNullableCompatibleMethod(returnType: Class, name: String, vararg params: Any): R? {
    throw UnsupportedOperationException()
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy