简体   繁体   English

Java 中的 Kotlin 内部类公开可见

[英]Kotlin internal classes in Java visible publicly

I am developing an Android crypto library in Kotlin.我正在 Kotlin 中开发一个 Android加密库 I have a couple of internal classes which become publicly visible in a Java app.我有几个在 Java 应用程序中公开可见的internal类。 Found this in documentations.在文档中找到这个

internal declarations become public in Java. internal声明在 Java 中变得public 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; internal类的成员经过名称修改,以防止从 Java 中意外使用它们,并允许根据 Kotlin 规则重载具有相同签名但彼此看不到的成员;

Is there a way to get around this?有办法解决这个问题吗?

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:您可以通过定义顶级函数并将其标记为@JvmSynthetic来轻松完成此操作,然后将ECryptSymmetricDecryptECryptSymmetricEncrypt类设为私有以防止 Java 客户端访问您的内部类,例如:

// 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.例如,加密和解密算法有很多重复,也许你可以在你的加密库中应用模板方法模式并引入接口来明确地使你的库并将Cipher操作隐藏在实现类下。 Ideally, the client code can't see any java.security.* classes via Encrypt or Decrypt interfaces.理想情况下,客户端代码无法通过EncryptDecrypt接口看到任何java.security.*类。 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 .并且此处创建实例并在init块中计算结果是一件坏事。

AND you can use Factory Method Pattern to avoid the type checking both in ECryptSymmetricDecrypt and ECryptSymmetricEncrypt classes.并且您可以使用工厂方法模式来避免在ECryptSymmetricDecryptECryptSymmetricEncrypt类中进行类型检查。

Apart from @JvmSynthetic , you can use @JvmName with an illegal Java identifier, like adding a space.除了@JvmSynthetic之外,您还可以将@JvmName与非法 Java 标识符一起使用,例如添加空格。

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参数中添加了一个空格,因此除 Kotlin 之外的任何语言都无法调用您的方法:

@JvmName(" example")
internal fun example() {
}

As per my answer on this question in another thread:根据我在另一个线程中对这个问题的回答:

Not perfect solution but I found two hacky solutions不是完美的解决方案,但我发现了两个 hacky 解决方案

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.@JvmName用空格或特殊符号注释该internal class的每个公共方法,这将在 Java 中产生语法错误。

For eg例如

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.@JvmSynthetic注释该internal class的每个公共方法,Java 无法访问这些公共方法。

For eg例如

internal class LibClass {

    @JvmSynthetic
    fun foo() {}

    @JvmSynthetic
    fun bar() {}
}

Note:笔记:

This solution protects the methods/fields of the function.该解决方案保护函数的方法/字段。 As per the question, it does not hide the visibility of class in Java.根据问题,它不会隐藏类在 Java 中的可见性。 So the perfect solution to this is still awaited.所以这个问题的完美解决方案还在等待中。

Utilizing a private constructor + companion object containing method to instantiate annotated with JvmSynthetic preserves encapsulation.使用私有构造函数 + 包含方法的伴随对象来实例化带有 JvmSynthetic 注释的方法可保留封装。

// Private constructor to inhibit instantiation
internal class SomeInternalClass private constructor() {

    // Use the companion object for your JvmSynthetic method to
    // instantiate as it's not accessible from Java
    companion object {
        @JvmSynthetic
        fun instantiate(): SomeInternalClass =
            SomeInternalClass()
    }

    // This is accessible from Java
    @JvmSynthetic
    internal var someVariable1 = false

    // This is accessible from Java
    @JvmSynthetic
    var someVariable2 = false



    // This is inaccessible, both variable and methods.
    private var someVariable3 = false
    @JvmSynthetic
    fun getSomeVariable3(): Boolean =
        someVariable3
    @JvmSynthetic
    fun setSomeVariable3(boolean: Boolean) {
        someVariable3 = boolean
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM