Kotlin JS - annotations processor

Is it possible to somehow run an annotations processor in Kotlin JS project?

I know Kotlin JS projects can’t rely on any Java dependencies but in theory (as long as generated code does not rely on Java) to process annotations JVM would only be needed at compile time so it should be possible in general.

Is there a way to achieve this at this moment?

2 Likes

How would the JavaScript target compiler know which Java classes are acceptable, and which are not? Java annotations can depend on other Java classes, and this way they (can) drag in a lot of other Java classes.

My guess is that the only way to support this, is to add a TypeScript target, so decorators can be used.

Can someone from the Jetbrains team acknowledge that it is not possible ? Is this something you are working on now or it will not be possible to process annotations from Kotlin classes when compiling to JS in the foreseeable future? I am currently working on a framework to create custom elements in Kotlin so it would be really useful to eliminate some boilerplate :slight_smile:

Thanks a lot !

AFAIK there is no way to process annotations at the moment.

We might introduce a compiler plugin API at some point, which will make it possible. But that’s not near future at all.

Related to that, is the code of the kolinx-serialization plugin open sourced ? I couldn’t find it and GitHub - Kotlin/kotlinx.serialization: Kotlin multiplatform / multi-format serialization only has the runtime library used by the generated code. I was curious how this plugin was written to play a little bit with code generation in Kotlin.

Thanks :slight_smile:

cc @elizarov

The plugin open source. It lives in a separate branch of kotlin compiler: https://github.com/JetBrains/kotlin/tree/rr/kotlinx.serialization

Awesome, thanks ! Is there any doc on how to write compiler plugins like you do ? Or is this something internal that you don’t necessarily want developers to have knowledge of at the moment ?

Edit : I had a quick look at the plugin code and it seems quite involved, I think I will wait that we have tools to easily generate multiplatform code before trying to achieve what I want :slight_smile:

1 Like

AFAIK there is no stable API at the moment. It is just code that is injected into the compiler, so the risks of something going wrong is huge.

There are some plans to expose a solid plugin API after we migrate to IR (basically a huge ongoing refactoring, bringing the JVM, JS, and Native backends closer together). No promises though.

All right, thanks a lot.

Another question related to annotation processing, is there a way to get any information regarding a variable type nullability ? For another project I am manipulating an ExecutableElement, and I’d like to know for each of its parameters and return type if I should consider it as nullable or not, i.e. I would like to differentiate between a String parameter coming from java (always nullable) or a String parameter coming from Kotlin (not nullable by default).
Maybe you added some metadata somewhere to have this kind of information ? I can start a new thread if you think it’s preferable.

Thanks

Maybe you could utilize information, provided by callable references. Those have type KFunction. The type information is provides has isMarkedNullable property.

Beware this API is not supported in Kotlin/JS at the moment.

Unless I’m wrong, I don’t think I will be able to access callable references from my annotation processor, right ? I only have access to TypeElement, ExecutableElement, etc.
Compatibility with JS is not important for that project :slight_smile:

One thing you could do is check the annotations. If I am not mistaken the kotlin compiler automatically adds @Nullable or @NotNull to everything accessible to java. This is not the most elegant solution but you could write a simple function taking an AnnotatedConstruct as a parameter which tells you whether it is nullable or not based on the annotations. Maybe there is a better solution.

Indeed, check for @NotNull works well! :slight_smile: For those interested, here is the code I am using :

private fun isNotNull(element: VariableElement): Boolean {
	val isPrimitive = element.asType().kind.isPrimitive
	return isPrimitive || MoreElements.isAnnotationPresent(element, NotNull::class.java)
}

private fun isReturnTypeNotNull(method: ExecutableElement): Boolean {
	val isPrimitive = method.returnType.kind.isPrimitive
	return isPrimitive || MoreElements.isAnnotationPresent(method, NotNull::class.java)
}

I was however unable to adapt the code for handling nullability inside generic parameters. Is there a way to make a difference between a method that returns a List<String> and one returning a List<String?> inside an annotation processor ?
Thanks :slight_smile:

Don’t know. I used annotation processing only a bit and I never needed to know something like this. I am not sure if there really is a way to do this, as kapt only exposes the information through the java systems and java has no concept of nullabilty. If anyone has a solution I would be interested though.