I have Test class which has written purely with kotlin in the library project.
class Test{
#Deprecated(message = "Use other function")
fun testFunction(id: String): Test {
this.testId = id
return this
}
}
I've deprecated testFunction() with Deprecated annotation. Btw Deprecated class is under the kotlin package. When i test this deprecated function in kotlin project works as expected(ide shows deprecated warning and strikethrough)
Example: Test(). testFunction("test")
But in the java project it doesn't show warning or strikethrough to function bye ide. When I open the declaration of deprecated function it's like below
#Deprecated(
message = "Use other function"
)
#NotNull
public final Test testFunction(#NotNull String var1) {
Intrinsics.checkParameterIsNotNull(var1, "id");
this.testId = var1;
return this;
}
any help would be appreciated
In Kotlin, the functions, properties, and classes marked with kotlin.Deprecated annotation also get the Deprecated attribute in the resulting JVM bytecode. This allows Java compiler to see them as deprecated and emit the corresponding warning.
Take for example this function that is deprecated in Kotlin:
https://github.com/JetBrains/kotlin/blob/v1.3.50/libraries/stdlib/common/src/generated/_Ranges.kt#L171-L175
If you try to call it from java as
kotlin.ranges.RangesKt.intRangeContains(null, 1.0);
javac compiler will report the following warning:
Warning:(55, 31) java: intRangeContains(kotlin.ranges.ClosedRange<java.lang.Integer>,double) in kotlin.ranges.RangesKt___RangesKt has been deprecated
and both IDEA and Android Studio will mark it as deprecated as well:
Related
I have following example Code:
class Test{
#Deprecated
Test(String par){
println(par)
}
Test(int par){
println(par)
}
#Deprecated
void myFunc(){
println("Hello")
}
}
Test test = new Test("Griasdi")
test.myFunc()
Test test2 = new Test(1)
I want the Test(String par) constructor and the myFunc Method be be marked as deprecated, But IntelliJ only marks the Method as Deprecated but not the constructor, see here on the Picture:
Does anybody know why the constructor is not marked as deprecated? Is this a Groovy thing or an IntelliJ issue?
Is this a Groovy thing or an IntelliJ issue?
It is an IntelliJ thing. Groovy isn't creating and annotating the editor in the IDE.
Currently, I'm creating a function, which is available for the dependencies block in Groovy with:
project.dependencies.ext.foo = { String value ->
project.files(extension.getFooDependency(project).jarFiles).asFileTree
}
Thanks to that, I'm able to do:
afterEvaluate {
dependencies {
compileOnly foo('junit')
}
}
I'm converting the Groovy code to Kotlin, and I'm wondering how to rewrite this foo extension.
I've ended up with:
project.dependencies.extensions.extraProperties.set("foo", Action { value: String ->
project.files(extension.getIdeaDependency(project).jarFiles).asFileTree
})
After calling foo('junit'), I get the following exception:
> Could not find method foo() for arguments [junit] on object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.
I do not think that would work the same way in Kotlin DSL. Instead, you may declare a Kotlin extension function somewhere in the project. Then calling it would include all necessary receivers to you.
For multiple projects, I would recommend using a buildSrc project. Declarations there are visible to all project files below.
Speaking about Groovy and Kotlin support, I would do something like that:
private fun getFooImpl(scope: getFooImpl, name: String) { /*here is the implementation */ }
fun DependencyHandlerScope.getFoo(name:String) = getFooImpl(this, name)
//in Groovy
project.dependencies.extensions.extraProperties.set("foo", {getFooImpl(..)})
The same code could fit into a plugin as well. A more generic way could be to register a custom DLS extension, so to allow a custom block-like thisIsMyPlugin { .. } in the Gradle DSL and define all necessary helper functions in the extension class. Here the downside is in forcing users to wrap their code into the thisIsMyPlugin block.
I have the following Kotlin code:
fun isObject(type: KClass<*>) = type.objectInstance != null
fun main() {
println(isObject(emptyMap<Int, Int>()::class))
}
which produces the following errror:
Exception in thread "main" java.lang.IllegalAccessException: class kotlin.reflect.jvm.internal.KClassImpl$Data$objectInstance$2 cannot access a member of class kotlin.collections.EmptyMap with modifiers "public static final"
at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:361)
at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:591)
at java.base/java.lang.reflect.Field.checkAccess(Field.java:1075)
at java.base/java.lang.reflect.Field.get(Field.java:416)
at kotlin.reflect.jvm.internal.KClassImpl$Data$objectInstance$2.invoke(KClassImpl.kt:114)
at kotlin.reflect.jvm.internal.ReflectProperties$LazyVal.invoke(ReflectProperties.java:62)
at kotlin.reflect.jvm.internal.ReflectProperties$Val.getValue(ReflectProperties.java:31)
at kotlin.reflect.jvm.internal.KClassImpl$Data.getObjectInstance(KClassImpl.kt)
at kotlin.reflect.jvm.internal.KClassImpl.getObjectInstance(KClassImpl.kt:239)
I want my isObject function to work for any arbitrary KClass but I don't know how to do it without checking if the object instance is non null. Any suggestions?
If you don't mind some reflection overhead and that it only works with Kotlin/JVM then you can use my library fluid-meta for that:
fun isObject(type: KClass<*>) = Meta.of(type) is MObject
Use version 0.9.16 if you're still on Kotlin 1.3 and the library won't work otherwise.
It uses the hidden Kotlin metadata annotations added to each class generated by Kotlin. If these annotations get stripped in your project at some point (e.g. by an aggressive ProGuard) then you won't have that information at runtime anymore though.
When trying to compile a Java #FunctionalInterface having more than 1 non-abstract method a compilation error is raised.
However, when doing the same in Kotlin, no errors or warnings are raised, i.e. the following Kotlin interface compiles successfully:
#FunctionalInterface
interface Foo {
fun foo()
fun foo(params: Map<String, String>)
}
Is this the intended behaviour or a bug in the Kotlin compiler?
Please note that the generated bytecode for the above Kotlin snippet is equivalent to the following Java snippet (which – correctly – doesn't compile):
#FunctionalInterface
// metadata omitted
public interface Foo {
void foo();
void foo(#NotNull Map var1);
}
Issue KT-25512 has been submitted to JetBrains's issue tracker (by another user) to report the fact that the compiler misbehaves when #FunctionalInterface is applied to a non-SAM interface, and as of 10 Feb 2019 the issue is still open with no activity.
I use the lib jackson-module-kotlin to parse string of json into object.
My issue is when I parse a string into an enum , and when I launch with intellij, I have this stack trace:
Caused by: kotlin.reflect.jvm.internal.KotlinReflectionInternalError:
Reflection on built-in Kotlin types is not yet fully supported. No
metadata found for public final val name: kotlin.String defined in
kotlin.Enum[DeserializedPropertyDescriptor#212b316a]
I don't have this issue when I launch with maven.
I use kotlin 1.1.51, with intellij kotlin plugin 1.2.0-release-IJ2017.3-1, I target a JVM 1.8, and i use jackson-module-kotlin version 2.8.7
what should I do?
enum class CType { DEAL, FILE }
data class Code(val code: String, val type: CType)
fun testDeserialization() {
val mapper = jacksonObjectMapper()
// following line throws an exception:
mapper.readValue("""{"code":"A","type":"DEAL"}""", Code::class.java)
}
The only way I got it working is by adding additional #JvmStatic annotation. I had mapper.registerModule(new KotlinModule()); and all, nothing worked but this:
package nc.features.algo.model
import com.fasterxml.jackson.annotation.JsonCreator
import com.fasterxml.jackson.annotation.JsonValue
enum class LHStatus (
#get:JsonValue val code: Int
) {
LH_POS_OVU_WAITING(1),
LH_NEG_OVU_WAITING(2),
;
companion object {
#JsonCreator
#JvmStatic
fun deser(code: Int?): LHStatus? {
if (code == null) return null
for (i in values()) {
if (i.code == code) return i
}
return null
}
}
}
You have to do a few things.
Update Jackson dependencies to the latest version (right now, 2.9.4).
Update Kotlin version to a version equal or greater than 1.3.0.
Be sure to add the following dependencies to your build.gradle:
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
implementation "com.fasterxml.jackson.module:jackson-module-kotlin:$jackson_version"
... then you call registerKotlinModule() on your Jackson ObjectMapper and the code of your enum should be just like this:
enum class CType(#get:JsonValue val value: String) {
DEAL("deal"),
FILE("file");
companion object {
#JsonCreator
fun fromString(value: String): CType? {
for (type in CType.values()) {
if (type.name.equals(value, true)) {
return gender
}
}
return null
}
}
}
Intellij is most likely using the kotlin compiler version 1.2.0 (from the plugin) and it doesn't seem to support reflection properly.
I suggest you do one of the following:
Upgrade your kotlin version in maven and the intellij kotlin plugin to newer versions (e.g. 1.2.30). If you do that, you also have to update jackson-module-kotlin to >= 1.9, since there is an incompatibility with kotlin 1.2 (see here).
Set the kotlin compiler version to 1.1 in Intellij Idea settings.
It is generally a good idea to use the same version of kotlin in Intellij Idea and maven/gradle.
You need to use the Kotlin module for Jackson that is compatible with Kotlin 1.2.x, this includes minimally these three versions of the module:
2.9.4.1 (works with any 2.9.x of Jackson, but best to use most recent)
2.8.11.1 (for Jackson 2.8.x)
2.7.9.1 (for Jackson 2.7.x)
Otherwise, you will run into a problem with library mismatches.
The jackson-module-kotlin homepage lists these as the current versions, but they are likely to change and you can check the various Maven repository search engines to see which library versions are available and which dependencies they have on Kotlin to find matching versions.
Also note you can import the extensions for the ObjectMapper class and use reified types, so instead of:
val something = mapper.readValue("""{"code":"A","type":"DEAL"}""", Code::class.java)
you would have:
val something: Code = mapper.readValue("""{"code":"A","type":"DEAL"}""")
or alternatively:
val something = mapper.readValue<Code>("""{"code":"A","type":"DEAL"}""")
It is usually bad to use the erased type (i.e. Whatever::class.java) since this does not work for anything with generic type parameters, and using reified types also works nicely when deserializing into collections.