Java 中的 Kotlin 内部 类 公开可见
Kotlin internal classes in Java visible publicly
我正在文档中开发 Android crypto library in Kotlin. I have a couple of internal
classes which become publicly visible in a Java app. Found this。
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;
有办法解决这个问题吗?
你的internal classes are all about encrypt & decrypt我都看过了。
您可以通过定义一个顶级函数并将其标记为 @JvmSynthetic
,然后将 ECryptSymmetricDecrypt and ECryptSymmetricEncrypt 类 设为 private防止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)
}
但是,它解决了你的问题,但我仍然想说你的代码可以进一步分解成小块。例如,加密和解密算法有很多重复,也许你可以在你的加密库中应用 Template Method Pattern 并引入接口来明确地使你的库和隐藏 Cipher
实现下的操作 类 .理想情况下,客户端代码无法通过 Encrypt
或 Decrypt
接口看到任何 java.security.*
类。例如:
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 创建实例并在 init
块 here 中计算结果是一件坏事。
AND 你可以使用 Factory Method Pattern to avoid the type checking both in ECryptSymmetricDecrypt and ECryptSymmetricEncrypt 类。
除了 @JvmSynthetic
之外,您还可以将 @JvmName
与非法的 Java 标识符一起使用,例如添加 space.
例如,我在 @JvmName
参数中添加了一个 space,因此除 Kotlin 之外的任何语言都无法调用您的方法:
@JvmName(" example")
internal fun example() {
}
根据我在 主题中对这个问题的回答:
不是完美的解决方案,但我发现了两个 hacky 解决方案
用空格或特殊符号注释 internal class
的每个 public 方法 @JvmName
,这些方法会在 Java.[=29 中产生语法错误=]
例如
internal class LibClass {
@JvmName(" ") // Blank Space will generate error in Java
fun foo() {}
@JvmName(" $#") // These characters will cause error in Java
fun bar() {}
}
由于上述解决方案不适合管理大型项目或似乎不是很好的做法,因此以下解决方案可能会有所帮助。
通过 @JvmSynthetic
注释 internal class
的每个 public 方法,其中 Java 无法访问 public 方法。
例如
internal class LibClass {
@JvmSynthetic
fun foo() {}
@JvmSynthetic
fun bar() {}
}
注:
此解决方案保护了函数的 methods/fields。根据问题,它不会隐藏 Java 中 class 的可见性。所以还是期待完美的解决方案吧
利用私有构造函数 + 包含方法的伴随对象实例化 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
}
}
我正在文档中开发 Android crypto library in Kotlin. I have a couple of internal
classes which become publicly visible in a Java app. Found this。
internal
declarations becomepublic
in Java. Members ofinternal
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 classes are all about encrypt & decrypt我都看过了。
您可以通过定义一个顶级函数并将其标记为 @JvmSynthetic
,然后将 ECryptSymmetricDecrypt and ECryptSymmetricEncrypt 类 设为 private防止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)
}
但是,它解决了你的问题,但我仍然想说你的代码可以进一步分解成小块。例如,加密和解密算法有很多重复,也许你可以在你的加密库中应用 Template Method Pattern 并引入接口来明确地使你的库和隐藏 Cipher
实现下的操作 类 .理想情况下,客户端代码无法通过 Encrypt
或 Decrypt
接口看到任何 java.security.*
类。例如:
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 创建实例并在 init
块 here 中计算结果是一件坏事。
AND 你可以使用 Factory Method Pattern to avoid the type checking both in ECryptSymmetricDecrypt and ECryptSymmetricEncrypt 类。
除了 @JvmSynthetic
之外,您还可以将 @JvmName
与非法的 Java 标识符一起使用,例如添加 space.
例如,我在 @JvmName
参数中添加了一个 space,因此除 Kotlin 之外的任何语言都无法调用您的方法:
@JvmName(" example")
internal fun example() {
}
根据我在
不是完美的解决方案,但我发现了两个 hacky 解决方案
用空格或特殊符号注释 internal class
的每个 public 方法 @JvmName
,这些方法会在 Java.[=29 中产生语法错误=]
例如
internal class LibClass {
@JvmName(" ") // Blank Space will generate error in Java
fun foo() {}
@JvmName(" $#") // These characters will cause error in Java
fun bar() {}
}
由于上述解决方案不适合管理大型项目或似乎不是很好的做法,因此以下解决方案可能会有所帮助。
通过 @JvmSynthetic
注释 internal class
的每个 public 方法,其中 Java 无法访问 public 方法。
例如
internal class LibClass {
@JvmSynthetic
fun foo() {}
@JvmSynthetic
fun bar() {}
}
注:
此解决方案保护了函数的 methods/fields。根据问题,它不会隐藏 Java 中 class 的可见性。所以还是期待完美的解决方案吧
利用私有构造函数 + 包含方法的伴随对象实例化 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
}
}