Top-level packageName

Not wanting to resurrect a 6-year old topic I have a similar requirement but not just for logging. Has the ability to retrieve the packageName at the top-level in a file been added since then? I haven’t been able to find anything.

Given my more varied requirements the most succinct thing I could come up with was this (keeping it in the ‘logger’ vein for this example):

private val packageName: String = (object {}).javaClass.packageName
private val logger = LoggerFactory.getLogger(packageName)

This still feels somewhat contorted to get what should be a readily available attribute.

TIA.

I believe you could use inline functions here

inline fun packageName() = (object {}).javaClass.packageName

and then I think you can use it anywhere

This will create new object in the heap every time it is called. Not good for GC.

You have to do that though. The point of the inline function here is to create a new anonymous class where it’s called, so that the class has that package. What you can do is have a private val packageName = packageName() at the file level

That’s why I think we need special function in Kotlin JVM library, what will return synthetic class (like SomeFileKt.class) for top-level functions.

1 Like

Thanks @kyay10 for the inline fun. I was close on that but didn’t quite get there. And yes, I’d replace the existing code to set the val because the value is used in a lot of places so the object creation would need to be minimized.

Hopefully we’ll see a language/lib-provided mechanism in the (near?) future.

Thanks again.

1 Like

Another hack:

inline fun packageName(noinline block: () -> Unit): String = block.javaClass.packageName

val pkg = packageName{}

It doesn’t allocate anything per use and should be generally quick enough to be used directly in the code, but a huge drawback is its non-standard calling style. Implementation can’t be easily replaced in the future if needed. Also, it creates a separate class and its instance per each call-site.

Are you sure that this doesn’t create instance block every time it’s called?

Kotlin compiler is smart enough to recognize if it needs a closure or just a static function and in the latter case it uses a singleton:

fun test1() {
    println(packageName{})
}

fun test2(x: String) {
    println(packageName{ x })
}
  public static final void test1();
    Code:
       0: getstatic     #23                 // Field Test1Kt$test1$1.INSTANCE:LTest1Kt$test1$1;
       3: checkcast     #25                 // class kotlin/jvm/functions/Function0
       6: astore_0
       7: iconst_0
       8: istore_1
       9: aload_0
      10: invokevirtual #29                 // Method java/lang/Object.getClass:()Ljava/lang/Class;
      13: invokevirtual #34                 // Method java/lang/Class.getPackageName:()Ljava/lang/String;
      16: dup
      17: ldc           #36                 // String getPackageName(...)
      19: invokestatic  #42                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullExpressionValue:(Ljava/lang/Object;Ljava/lang/String;)V
      22: astore_0
      ...

  public static final void test2(java.lang.String);
    Code:
       0: aload_0
       1: ldc           #62                 // String x
       3: invokestatic  #65                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: new           #67                 // class Test1Kt$test2$1
       9: dup
      10: aload_0
      11: invokespecial #70                 // Method Test1Kt$test2$1."<init>":(Ljava/lang/String;)V
      14: checkcast     #25                 // class kotlin/jvm/functions/Function0
      17: astore_1
      18: iconst_0
      19: istore_2
      20: aload_1
      21: invokevirtual #29                 // Method java/lang/Object.getClass:()Ljava/lang/Class;
      24: invokevirtual #34                 // Method java/lang/Class.getPackageName:()Ljava/lang/String;
      27: dup
      28: ldc           #36                 // String getPackageName(...)
      30: invokestatic  #42                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullExpressionValue:(Ljava/lang/Object;Ljava/lang/String;)V
      33: astore_1
      ...
2 Likes