Use any Kotlin annotation as annotation member - kotlin

I want to create an annotation that accepts any annotations as parameter, like:
#TestAnnotation(annotations = [#AnotherAnnotation(value = "test")])
I tried the following, but that does not work:
annotation class TestAnnotation(
annotations: Array<Annotation> = []
)

Related

Jackson annotation not visible via Kotlin Reflect

For some reason Kotlin Reflect does see my custom annotation on member property but doesn't see Jackson one. Though Jackson annotation is detected and used by Jackson itself. Minimum snippet (run in REPL thus Line_5$A classname):
annotation class A
class C {
#A
#com.fasterxml.jackson.annotation.JsonProperty
var x: Int = 0
}
C::class.memberProperties.forEach { println(it.annotations.map{it.annotationClass}) }
Output: [class Line_5$A]
Expected: [class Line_5$A, class com.fasterxml.jackson.annotation.JsonProperty]
How could I have access to Jackson annotation here?
Ok, found out that Jackson annotation was attached to Java field, not Kotlin property. So this workaround works:
println(C::class.memberProperties.first().javaField!!.declaredAnnotations.get(0).annotationClass)
Output: class com.fasterxml.jackson.annotation.JsonProperty
UPD:
And if data class is used then this:
import kotlin.reflect.full.primaryConstructor
data class C (
#com.fasterxml.jackson.annotation.JsonProperty
var x: Int = 0
)
val prop = C::x
println(C::class.primaryConstructor
?.parameters
?.find { it.name == prop.name }
?.annotations
?.first()
?.annotationClass
)
Output: class com.fasterxml.jackson.annotation.JsonProperty

Kotlin, mapstruct and generated DTO error "does not have an accessible parameterless constructor."

I am trying to use mapstruct to convert my complex dtos on my kotlin project.
mapstruct : 1.3.1.final
kotlin: 1.3.71
openapi generator: 4.2.3
For example, i want to convert from a simple object to TestObjectDTO
#Mapping(source = "mydescription", target = "description")
fun convertToDto(dto: TestObject): TestObjectDTO
I use OpenApi to generate my DTO :
yaml
components:
schemas:
TestObject:
title: TestObject
description: ''
type: object
properties:
mode:
type: string
description:
type: string
required:
- mode
- description
generated DTO
/**
*
* #param mode
* #param description
*/
data class TestObjectDTO (
#get:NotNull
#JsonProperty("mode") var mode: kotlin.String,
#get:NotNull
#JsonProperty("description") var description: kotlin.String
) {
}
A always have an error, because my constructor does not permit parameterless.
Did you have any idea how to fix this?
You can instantiate the DTO class manually using #ObjectFactory. The problem is that TestObjectDTO does not accept nulls, so you will need to use dummy values, which is not that pretty:
#Mapper
interface TestObjectMapper {
#ObjectFactory
fun createDto() = TestObjectDto("", "")
#Mapping(source = "mydescription", target = "description")
fun convertToDto(dto: TestObject): TestObjectDto
}
1.3.1.Final does not support using constructors to create your objects. You will have to define a parameter less constructor as the error message says.
However, you can try 1.4.0.Beta3 that adde support for mapping using constructors. And this works with Kotlin data classes
In Java
A possible solution for this is to annotate the dto class with #NoArgsConstructor, for example:
#NoArgsConstructor
public class MyClass {
private String myString;
private Int myInt;
}

Can you define alternative shorthands for Kotlin Annotations?

I am using annotations and reflection to create a parser for some custom made files used in the project I work with
I have this annotation that will be used to annotate most data class constructor parameters
annotation class Element(val name: String = "",val type: ElementType = ElementType.Value)
the enum ElementType has these values
enum class XElementType {
Value,
Attribute,
Ignore
}
is there a way to create a shorthand or alternate so that instead of using
#Element(type=ElementType.Ignore)
val ignoredVariable:String
I can use something like
#IgnoreElement
val ignoredVariable:String
which will resolve to Element("",ElementType.Ignore) ?

How to add annotation on main constructor parameters in kotlin

Having the following class:
data class TestMsg(
#Parse(";")
val someArray: Array<String>
)
And trying to get the annotation with
TestMsg::class.primaryConstructor!!.parameters.forEach{
println(it.findAnnotation<Parse>())
}
There is no annotation found. I had to move the annotation front of the parameter for make it working
data class TestMsg(
#Parse(";") val someArray: Array<String>
)
is it a parsing error of jetbrains or is it the normal behavior?
EDIT
You can find the annotation right here:
#Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY, AnnotationTarget.TYPE_PARAMETER)
#Retention(AnnotationRetention.RUNTIME)
annotation class Parse(
val delimiter: String
)
change AnnotationTarget.PROPERTY to AnnotationTarget.VALUE_PARAMETER
#Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.TYPE_PARAMETER)
#Retention(AnnotationRetention.RUNTIME)
annotation class Parse(
val delimiter: String
)

Acquire annotation parameters (or annotation instance) from Kotlin PSI

I have a Kotlin annotation:
#Retention(AnnotationRetention.SOURCE)
#Target(AnnotationTarget.CLASS)
annotation class Type(
val type: String
)
It can be used on the Kotlin classes in two ways: using the named parameter syntax, or using the positional parameter syntax:
#Type(type = "named")
data class Named(
…
)
#Type("positional")
data class Positional
…
)
I use this annotation in my custom detekt rules for some extra checks. I need to extract the value of the type parameter to perform some check based on it. I do that like:
private fun getType(klass: KtClass): String? {
val annotation = klass
.annotationEntries
.find {
"Type" == it?.shortName?.asString()
}
val type = (annotation
?.valueArguments
?.find {
it.getArgumentName()?.asName?.asString() == "type"
}
?.getArgumentExpression() as? KtStringTemplateExpression)
?.takeUnless { it.hasInterpolation() }
?.plainContent
return type
}
But this code works only with "named" parameters syntax, and fails for the positional one. Is there any way to get the value of an annotation parameter no matter what syntax was used? It would be perfect if I could acquire my Type annotation instance directly from PSI / AST / KtElements and use it like usually. Is it possible to instantiate an annotation from the PSI tree?