2

I was working on the Android library which I'm developing in Kotlin. I kept access modifier of some classes as internal. Internal classes are only visible in that library module in Kotlin. If I implement that library in the app then it's not visible at all.

But the problem comes when accessing that library from Java code. If I create .java file and type name of that internal class of library then IDE is suggesting name and it's resolved and compiled without any error.

For e.g.

Library Module:

internal class LibClass {
    // Fields and Methods
}

After implementing above library in DemoApp module:

App Module

Kotlin:
fun stuff() {
    val lib = LibClass() // Error.. Not resolving
}
Java:
public void stuff() {
    LibClass lib = new LibClass() // Successfully resolving and compiling
}

So that's the problem. How can I achieve securing that class from Java?

Thank you!

Shreyas Patil
  • 808
  • 6
  • 17
  • This should not be the case, in my IDE I cant compile it. Are you sure you are accessing LibClass in app module? – Minki Jul 16 '20 at 15:53
  • Yes I can access it from app module. It's just showing red error underline below class name but compiling successfully – Shreyas Patil Jul 16 '20 at 15:55
  • Not sure whether it would work, but maybe try annotating your class with `@JvmName` and give it an invalid Java name like containing a space, hyphen or something. – Saurabh Thorat Jul 16 '20 at 16:25
  • Okay. I'll try this and will let you know about it – Shreyas Patil Jul 16 '20 at 16:54
  • @SaurabhThorat I tried using `@JvmName` but it's not working. It only works when top-level functions are created inside `.kt` file. It's not working for the class. – Shreyas Patil Jul 16 '20 at 17:11
  • Checkout this answer... May be useful... Think @JvmSynthetic solves it https://stackoverflow.com/questions/45393423/kotlin-internal-classes-in-java-visible-publicly – Robin Jul 17 '20 at 05:27
  • You could use [`@RestrictTo`](https://developer.android.com/reference/androidx/annotation/RestrictTo.Scope) annotation and set the scope to your library only. – Saurabh Thorat Jul 17 '20 at 06:32
  • `@RestrictTo` annotation only shows a warning. It still compiles successfullt – Shreyas Patil Jul 17 '20 at 07:13
  • @Robin `@JvmSynthetic` annotation is not targetted for class. So we can't do that. – Shreyas Patil Jul 17 '20 at 07:24

3 Answers3

2

Not perfect solution but I found two hacky solutions

Annotate every public method of that internal class by @JvmName with blank spaces or special symbols by which it'll generate syntax error in Java.

For e.g.

internal class LibClass {

    @JvmName(" ") // Blank Space will generate error in Java
    fun foo() {}

    @JvmName(" $#") // These characters will cause error in Java
    fun bar() {}
}

Since this above solution isn't appropriate for managing huge project or not seems good practice, this below solution might help.

Annotate every public method of that internal class by @JvmSynthetic by which public methods aren't accessible by Java.

For e.g.

internal class LibClass {

    @JvmSynthetic
    fun foo() {}

    @JvmSynthetic
    fun bar() {}
}

Note:

This is explained in detail in this article.

Shreyas Patil
  • 808
  • 6
  • 17
  • but what if the library itself has a mix of Kotlin and Java and Java consumes Kotlin code using `@file:JvmName("SomeName")`. Set blank or `#$` makes them inaccessible for library's java classes as well. How to get around this? – Gopal S Akshintala May 26 '21 at 03:47
  • @GopalSAkshintala Then it's not appropriate. Either make it with 100% Kotlin or Java (as far as I know). – Shreyas Patil Jun 03 '21 at 06:08
2

I see you have got class with internal modifier that cannot be instantiated in kotlin class but can be instantiated in Java file. If it’s a standalone class, you can make its constructor private and allow the instantiation using a static method (Companion object).

Mustaqode
  • 453
  • 1
  • 4
  • 14
1

If you want to hide visibility of the class instead of each functions or fields, you can use @file:JvmSynthetic on top of your class.

E.g.

@file:JvmSynthetic
package  com.example.app

internal class LibClass {
    var count: Int = 0

    internal fun exampleFun() {
        
    }
}
Mergim Rama
  • 328
  • 2
  • 11