Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin internal classes in Java visible publicly

I am developing an Android crypto library in Kotlin. I have a couple of internal classes which become publicly visible in a Java app. Found this in documentations.

internal declarations become public in Java. Members of internal classes go through name mangling, to make it harder to accidentally use them from Java and to allow overloading for members with the same signature that don't see each other according to Kotlin rules;

Is there a way to get around this?

like image 285
priyank Avatar asked Jul 29 '17 19:07

priyank


2 Answers

I have seen all of your internal classes are all about encrypt & decrypt.

you can do it easily by define a top-level function and mark it as @JvmSynthetic, and then makes the ECryptSymmetricDecrypt and ECryptSymmetricEncrypt classes to private to prevent Java client access your internal classes, for example:

// define this top-level function in your ECryptSymmetricEncrypt.kt

@JvmSynthetic internal fun <T> encrypt(
                                       input:T, password: String, cipher:Cihper, 
                                       erl: ECryptResultListener, outputFile:File,
                                       getKey:(String,ByteArray)->SecretKeySpec){

  ECryptSymmetricEncrypt(input, password, cipher,
                { pass, salt -> getKey(pass, salt) }, erl, outputFile)
}

However, it solved your problem, but I still want to say that your code can break into small pieces as further. for example, the encrypt & decrypt algorithm have many duplications, maybe you can applies Template Method Pattern in your encrypt library & introduce interfaces to make your library explicitly and hiding the Cipher operations under the implementation classes. Ideally, the client code can't see any java.security.* classes via Encrypt or Decrypt interfaces. for example:

interface Encrypt{
   //          v--- don't include the infrastructure class here,e.g:`Keys`,`Cipher`
   fun encode(...args)
}

interface Decrypt{
   //          v--- don't include the infrastructure class here,e.g:`Keys`,`Cipher`
   fun decode(...args)
}

AND it is a bad thing that you create an instance and compute the result in init block here.

AND you can use Factory Method Pattern to avoid the type checking both in ECryptSymmetricDecrypt and ECryptSymmetricEncrypt classes.

like image 125
holi-java Avatar answered Oct 15 '22 18:10

holi-java


Apart from @JvmSynthetic, you can use @JvmName with an illegal Java identifier, like adding a space.

As an example, I added a space in the @JvmName param, so any languages except Kotlin will not be able to invoke your method:

@JvmName(" example")
internal fun example() {
}
like image 26
ice1000 Avatar answered Oct 15 '22 18:10

ice1000