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

org.pkl.thirdparty.kotlin.reflect.full.KAnnotatedElements.kt Maven / Gradle / Ivy

Go to download

Fat Jar containing pkl-cli, pkl-codegen-java, pkl-codegen-kotlin, pkl-config-java, pkl-core, pkl-doc, and their shaded third-party dependencies.

There is a newer version: 0.27.1
Show newest version
/*
 * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
 * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
 */

@file:JvmName("KAnnotatedElements")

package org.pkl.thirdparty.kotlin.reflect.full

import java.lang.reflect.Method
import org.pkl.thirdparty.kotlin.reflect.KAnnotatedElement
import org.pkl.thirdparty.kotlin.reflect.KClass

/**
 * Returns an annotation of the given type on this element.
 */
@SinceKotlin("1.1")
inline fun  KAnnotatedElement.findAnnotation(): T? =
    @Suppress("UNCHECKED_CAST")
    annotations.firstOrNull { it is T } as T?

/**
 * Returns true if this element is annotated with an annotation of type [T].
 */
@SinceKotlin("1.4")
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
@WasExperimental(ExperimentalStdlibApi::class)
inline fun  KAnnotatedElement.hasAnnotation(): Boolean =
    findAnnotation() != null

/**
 * Returns all annotations of the given type on this element, including individually applied annotations
 * as well as repeated annotations.
 *
 * In case the annotation is repeated, instances are extracted from the container annotation class similarly to how it happens
 * in Java reflection ([java.lang.reflect.AnnotatedElement.getAnnotationsByType]). This is supported both for Kotlin-repeatable
 * ([org.pkl.thirdparty.kotlin.annotation.Repeatable]) and Java-repeatable ([java.lang.annotation.Repeatable]) annotation classes.
 */
@SinceKotlin("1.7")
@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
@WasExperimental(ExperimentalStdlibApi::class)
inline fun  KAnnotatedElement.findAnnotations(): List =
    findAnnotations(T::class)

/**
 * Returns all annotations of the given type on this element, including individually applied annotations
 * as well as repeated annotations.
 *
 * In case the annotation is repeated, instances are extracted from the container annotation class similarly to how it happens
 * in Java reflection ([java.lang.reflect.AnnotatedElement.getAnnotationsByType]). This is supported both for Kotlin-repeatable
 * ([org.pkl.thirdparty.kotlin.annotation.Repeatable]) and Java-repeatable ([java.lang.annotation.Repeatable]) annotation classes.
 */
@SinceKotlin("1.7")
@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
@WasExperimental(ExperimentalStdlibApi::class)
fun  KAnnotatedElement.findAnnotations(klass: KClass): List {
    val filtered = annotations.filterIsInstance(klass.java)
    if (filtered.isNotEmpty()) return filtered

    val containerClass = Java8RepeatableContainerLoader.loadRepeatableContainer(klass.java)
    if (containerClass != null) {
        val container = annotations.firstOrNull { it.annotationClass.java == containerClass }
        if (container != null) {
            // A repeatable annotation container must have a method "value" returning the array of repeated annotations.
            val valueMethod = container::class.java.getMethod("value")
            @Suppress("UNCHECKED_CAST")
            return (valueMethod(container) as Array).asList()
        }
    }

    return emptyList()
}

@Suppress("UNCHECKED_CAST")
private object Java8RepeatableContainerLoader {
    class Cache(val repeatableClass: Class?, val valueMethod: Method?)

    var cache: Cache? = null

    private fun buildCache(): Cache {
        val repeatableClass = try {
            Class.forName("java.lang.annotation.Repeatable") as Class
        } catch (e: ClassNotFoundException) {
            return Cache(null, null)
        }

        return Cache(repeatableClass, repeatableClass.getMethod("value"))
    }

    fun loadRepeatableContainer(klass: Class): Class? {
        val cache = cache ?: synchronized(this) {
            cache ?: buildCache().also { cache = it }
        }

        val repeatableClass = cache.repeatableClass ?: return null
        val repeatable = klass.getAnnotation(repeatableClass) ?: return null
        val valueMethod = cache.valueMethod ?: return null

        return valueMethod(repeatable) as Class
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy