What is the proper way to repackage/shade Kotlin dependencies

I wonder if Kotlin can be used to create “zero-dependency” library for Java consumers (e.g. JDBC driver).

Of course I can just use maven-shade-plugin (or alternative) to repackage kotlin.* classes, however I wonder if Metadata - Kotlin Programming Language requires some special treatment.

The question is a good one, and I am curious too, but this is a bad example as the practice of shading the Kotlin runtime for a library like this leads to unnecessary duplication since it’s a runtime that may often be shared by end user code anyways. If there were backwards compat problems w/ Kotlin runtime or you had to have a single-JAR-but-scared-of-classpath situation it might be different, but in general I would avoid it.

I wonder this too. From my naive reading of the link you have, the metadata lib mutation readme, and the metadata protobuf they embed I would guess there is some non-trivial work to refactor and change the compiled package name. Things get even more complicated w/ JvmPackageName attributes and what not.

I’d say if you don’t end up getting a satisfactory answer, do some tests and make sure some of those test cases exercise Kotlin-only reflection too (e.g. KClass.qualifiedName). I would guess that, unless you use Kotlin reflection specifically (i.e. no reflection or Java-only reflection is fine), you could probably use maven-shade, shadow, or whatever. Worst case scenario, you may end up doing source-level refactorings which sounds like a nightmare.

  1. JDBC drivers are often used in public static void main environment, especially when developers use no dependency management
  2. You can’t predict the environment, so end-user might use various runtime versions. This will cause conflicts

Is Kotlin team saying it can’t be done? Whether is should or shouldn’t is up to the author.

@tj.rothwell Your question is unclear. The fatjar could be created via gradle shadow plugin. It works perfectly fine with kotlin. Also, you should probably know that jpackage also works perfectly well with kotlin.

@darksnake , does shadow plugin update kotlin metadata annotation to account the repackage?

The class path does not change during repackaging so I do not see why it should affect anything. I usually prefer application instead of shadow, but I used shadow multiple times in kotlin and I have not seen any problems. From the java side metadata looks like an annotation with string content, so it is just moved together with class.

The shadow plugin is usually used for an application, so the metadata is not even used anymore (save for very specific reflection cases).

My use case is for shading stdlib for a libarary rather than application.

The better questions probably: “is the metadata relocatable?” In other words, does it need to be changed when class name/method name changes?

From the java side metadata looks like an annotation with string content

For instance, if the contents includes references to other classes, then the annotation must be adjusted if classes are repackaged.

I do not see why it should be changed. The metadata points to java class files and their paths are not changed during repackaging (otherwise standard java programs would stop working). It is possible that there are some corner cases for that, but I have not seen them. If you do encounter something like this, please file an issue.

1 Like

Also probably you should not shade a library…

I see your suggestions, yet they do not help to clarify if “kotlin metadata annotations” or “META-INF/*.kotlin_module” contains non-relocatable data.

For instance, I just checked META-INF/stage-vote-release-plugin.kotlin_module from one of my projects, and the file does contain fully qualified class references, so I assume .kotlin_module breaks if I relocate the classes.

The question is: do you really plan to relocate your code (so rename a package name) or do you only need to shade/create a fatjar, which does not really relocate classes? You are right that you didn’t get an answer to your question. People are just concerned, because you asked specifically about shading, but it shouldn’t introduce the problem that you try to avoid.

It is in the question title, and I want both: relocate and shade

In other words, I want to write a zero-dependency JVM library in Kotlin and use libraries like kotlin-stdlib. I want to make sure it won’t conflict with other kotlin-stdlib on the users’ classpath, and I have no way to control the classpath of the users. They might have their Kotlin versions.

Is it possible?

4 Likes