Reputation: 403
I want to extend an API in a way that's useful for Kotlin callers, but not Java callers. Therefore I'd like to encourage Kotlin users to switch to a new method, without bothering Java users. We have a large codebase that's a mix of Java and Kotlin, and won't be 100% Kotlin any time soon.
Is there a way to add a @Deprecate
tag or similar that only shows up in Kotlin, not Java?
If you're interested in the specific details, we have a Log
interface that takes a formatted string, something like this:
Log.get().info("Log message with some $expensive $things to $format")
That string is created on every call, even if logging is disabled. Fixing the logger API to take the format string and arguments separately would be a big and disruptive change. However, Kotlin's nullable types could give us a very cheap solution:
Log.getNullable()?.info("This $expensive $format should be skipped if there's no logger")
Just a case of replacing get().
with getNullable()?.
in all the Kotlin code. But I wouldn't want to use getNullable()
in Java code because there's a risk of NullPointerException
. So the old Log.get
method should ideally be deprecated in Kotlin, but not in Java.
Upvotes: 2
Views: 1309
Reputation: 463
There are two parts for this
For hiding a method from Java Caller, @JvmSynthetic
can be used; more on it here.
For hiding a method from Kotlin Caller I could not find a direct way of doing it but as suggested here you can use @JvmName
to provide a good name for the method and add a deprecation message in the actual fun
name
So now the Class will look like
class Log {
companion object {
@JvmStatic
@JvmName("get")
fun dont_dare_using_this_from_kotlin_use_getNullable_instead(): String = TODO()
@JvmSynthetic
fun getNullable(): String = TODO()
}
}
Upvotes: 1
Reputation: 23292
Assuming a class Log
whose methods are defined in the companion object
, e.g.:
class Log {
companion object {
@JvmStatic
fun get() : String = TODO()
@JvmStatic
fun getNullable() : String? = TODO()
}
}
What about just removing the @JvmStatic
? or creating an extension function instead?
fun Log.Companion.getNullable() : String? = TODO()
class Log {
companion object {
@JvmStatic
fun get() : String = TODO()
}
}
Extension functions are usually not that easily accessible in Java as they are in Kotlin. Both, removing @JvmStatic
or the extension function would require the following in the Java code: Log.Companion.getNullable
instead of Log.getNullable
... Maybe that's also ok for you instead of deprecating it.
Even if my guess is off, an extension function may suit your needs here.
Regarding deprecating a method only for Kotlin... I don't think that works, but here is another workaround for that. Just rename the method and use @JvmName("get")
on the method, e.g.:
@JvmStatic
@JvmName("get")
fun dont_ever_use_this_method_again_in_Kotlin() : String = TODO()
That will allow Log.get
from Java but doesn't from Kotlin. And I think we can agree that no one will call Log.dont_ever_use_this_method_again_in_Kotlin
in Kotlin, right?
Upvotes: 1