Compiler warning while using #Value annotation in Kotlin project - java

Is there any type in Kotlin language that I could use in a late initialization instead of java.lang.Integer so that I do not get a compiler warning?
Let's say I have a class like this one:
class SomeClass {
#Value(#{config['poolCapacity']?:'5000'})
lateinit var somePool: Integer
}
I can't use Int type from Kotlin because it's primitive type and lazeint does not accept it.
If I stick to java.lang.Integer it works just fine but I am getting compiler warning of this sort:
SomeClass.kt: (20, 24): This class shouldn't be used in Kotlin. Use
kotlin.Int instead.
Obviously I might create needed type myself but I simply wonder if there is something out of the box and recommended that we should use in such situation and I simply can't find it? (Annotated constructor is not a solution in this particular case).

The simplest solution is don't to use a late-initialized property since Kotlin late-initialized property don't support for primitive types now, and you can initialize it with the default value of spring expression, for example:
#Value(#{config['poolCapacity']?:'5000'})
var somePool: Int = 5000
A complex example you can write a delegated properties, but you must annotated at setter by #set site-target rather than field/property , for example:
#set:Value(#{config['poolCapacity']?:'5000'})
var value by required<Int>()
inline fun <reified T> required(): ReadWriteProperty<Any, T> {
return object : ReadWriteProperty<Any, T> {
var value: T? = null;
override fun getValue(thisRef: Any, property: KProperty<*>): T = value as T
override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
this.value = value;
}
}
}

Related

Use property getter method reference for functional (SAM) interface variables

I want to pass a property getter method reference as one of the function arguments, and have that argument be of my own functional interface type, but ran into an issue.
Here's a stripped down minimal reproducible case, I changed the variable from an argument into a property, but the issue is the same.
class Foo {
val bar: Bar? = null
}
class Bar
fun interface FooBarSelector {
fun select(foo: Foo): Bar?
}
class KotlinClass() {
val selector: FooBarSelector = Foo::bar
}
This doesn't compile, Foo::bar is underlined and the error is
Type mismatch.
Required: FooBarSelector
Found: KProperty1<Foo, Bar?>
I tried to look this up, found similar questions about SAM conversions, but they were a bit different and I don't think any of them referred specifically to property getters.
I found that the issue can be solved by doing one of the following:
Remove the explicit type, or replace it with the suggested KProperty1. Not an option, I want to preserve my type.
Replace the method reference with FooBarSelector { it.bar }. Far from ideal, but better than the first option.
Why does this happen and are there any other options? I am new to Kotlin, but not Java.
Kotlin version used is 1.7.20
EDIT:
Here's my original goal: accept a FooBarSelector as an argument, and by default point it at a property getter:
fun doSomething(
selector: FooBarSelector = Foo::bar //doesn't compile
) {
}
Your code with the lambda is fine, but you may prefer this syntax for the same thing:
class KotlinClass() {
val selector = FooBarSelector(Foo::bar)
}
Explanation:
Kotlin function references are more explicit about types than in Java, because function references are a first-class object type. When you want to use a function reference as a functional interface instance, you must convert it. This can be done automatically by the compiler using SAM conversion.
SAM conversion only works when passing a function reference as an argument to a function that has a parameter with a functional interface type. So, it doesn't directly work when assigning to a property.
But Kotlin implicitly provides higher order functions for functional interfaces that allow you to pass a function reference that will convert it into an interface instance. The implicit function is named after the interface, so it looks like a constructor call.
In the above code, the implicit functional interface "constructor" is inline, so there is no intermediate functional object allocated in the compiled code. This compiles to the same thing you would get in Java with a direct method reference.
I am not 100% sure what you are expecting but consider this example:
class Foo(
val bar: Bar
)
data class Bar(
val value: String
)
interface FooBarSelector {
fun select(foo: Foo): Bar {
return foo.bar
}
}
class FooBarCustomSelector: FooBarSelector {
override fun select(foo: Foo): Bar {
return Bar("I don't care about which Foo was passed. I'll return my own Bar")
}
}
class KotlinClass(val selector: (Foo) -> Bar = Foo::bar)
fun main(args: Array<String>) {
val kotlinClassWithDefaultSelector = KotlinClass()
val kotlinClassWithCustomSelector = KotlinClass(FooBarCustomSelector()::select)
val foo = Foo(Bar("Bar1"))
println("kotlinClassWithDefaultSelector: ${kotlinClassWithDefaultSelector.selector(foo)}")
println("kotlinClassWithCustomSelector: ${kotlinClassWithCustomSelector.selector(foo)}")
}
This would print:
kotlinClassWithDefaultSelector: Bar(value=Bar1)
kotlinClassWithCustomSelector: Bar(value=I don't care about which Foo was passed. I'll return my own Bar)

How to get KClass from Kproperty? [duplicate]

Let's say i have any class, like this one:
class SomeClass(val aThing: String, val otherThing: Double)
Then I use reflection to analyze the fields of this class:
for(field in SomeClass.declaredMemberProperties){
}
How can I check the type of each field?
Since Kotlin does not have fields but only properties with backing fields, you should check the return type of the property.
Try this:
class SomeClass(val aThing: String, val otherThing: Double)
for(property in SomeClass::class.declaredMemberProperties) {
println("${property.name} ${property.returnType}")
}
UPDATE:
If the class does not use custom getters and/or setters without backing fields, you can get the type of the backing field like this:
property.javaField?.type
As a complete example, here is your class with an additional val property called foo with a custom getter (so no backing field is created). You will see that getJavaField() of that property will return null.
class SomeClass(val aThing: String, val otherThing: Double) {
val foo : String
get() = "foo"
}
for(property in SomeClass::class.declaredMemberProperties) {
println("${property.name} ${property.returnType} ${property.javaField?.type}")
}
UPDATE2:
Using String::class.createType() will return the KType for every KClass, so you can use e.g. property.returnType == String::class.createType() to find out if it's a (kotlin) String.

Getting getters (or methods or properties) list in generic class with Kotlin

I can't figure out how should i deal with generics in kotlin.
I'm writing a history class for changes made on generic objects, which should get any type of class as parameter: after that, I would compare the old object values with the new object values, and if I found a difference, I'll write that in my data class.
I've succedeed doing that with java with bean.getClass().getMethods();, but I want to trying move to Kotlin.
class ChangeHistoryUtils<T> (val originalBean : T, username : String , var modifiedBean: T? = null) {
data class ChangeHistory(val username: String, val fieldName : String,
val oldValue : String , val newValue : String , val date : LocalDate = LocalDate.now())
fun compareBeans(){
//how to get all originalBean getters and its values?
}
}
I'm actually stuck here: how should obtain all the getters in my T object?
Let's guess i'll receive a class which with 10 getters, I want to call all these 10 getters in originalBean, and comparing its value with the ones in modifiedBean. If different, I will write it in my ChangeHistory
Thanks
You need to ensure that T itself is not a nullable type, i.e. use something like where T : Any on the class declaration, e.g.:
class ChangeHistoryUtils<T> (originalBean : T, username : String , modifiedBean: T? = null) where T : Any
If you do that you can afterwards just access the methods as you did in Java, e.g. if you just want to reuse the code you already have:
fun compareBeans(){
originalBean::class.java.methods // this is actually your originalBean.getClass().getMethods() !
// just print the methods for now...
.forEach(::println)
}
But as you are using Kotlin you may rather want to use the Kotlin approach then, e.g. just showing the properties, or similar:
originalBean::class.memberProperties
// again just printing them:
.forEach(::println)
You then need to add kotlin-reflect as dependency. You may also want to check the Kotlin reference regarding reflection.

Kotlin: Equivalent of getClass() for KClass

In Java we can resolve a variable's class through getClass() like something.getClass(). In Kotlin I am aware of something.javaClass which is nice but I want to be able to get the KClass in a similar way. I've seen the Something::class syntax but this is not what I need. I need to get the KClass of a variable. Does such functionality exist?
The easiest way to achieve this since Kotlin 1.1 is the class reference syntax:
something::class
If you use Kotlin 1.0, you can convert the obtained Java class to a KClass instance by calling the .kotlin extension property:
something.javaClass.kotlin
EDIT: See comments, below, and answer from Alexander, above. This advice was originally for Kotlin 1.0 and it seems is now obsolete.
Since the language doesn't support a direct way to get this yet, consider defining an extension method for now.
fun<T: Any> T.getClass(): KClass<T> {
return javaClass.kotlin
}
val test = 0
println("Kotlin type: ${test.getClass()}")
Or, if you prefer a property:
val<T: Any> T.kClass: KClass<T>
get() = javaClass.kotlin
val test = 0
println("Kotlin type: ${test.kClass}")
Here's my solution
val TAG = javaClass.simpleName
With javaClass.simpleName you can obtain your class name. Also the above example is very useful for android developers to declare on top of the class as an instance variable for logging purposes.
Here are different Implementations to get class names. You can utilize it as per your requirements.
import kotlin.reflect.KClass
val <T : Any > T.kClassName: KClass<out T>
get() {
return javaClass.kotlin
}
Here we can get the class name in kotlin
val <T : Any > T.classNameKotlin: String?
get() {
return javaClass.kotlin.simpleName
}
Here we can get the class name in kotlin
val <T : Any > T.classNameJava: String
get() {
return javaClass.simpleName
}
Here are the outputs to the following operations.
fun main(){
val userAge = 0
println(userAge.kClassName)
Output: class java.lang.Integer (Kotlin reflection is not available)
println(userAge.classNameKotlin)
Output: Int
println(userAge.classNameJava)
Output: Integer
}
Since Kotlin 1.5.21 (org.jetbrains.kotlin:kotlin-stdlib:1.5.21)
val TAG = javaClass.simpleName will work no more!
Error "Not enough information to infer type variable T"
/**
* Returns the runtime Java class of this object.
*/
public inline val <T : Any> T.javaClass: Class<T>
#Suppress("UsePropertyAccessSyntax")
get() = (this as java.lang.Object).getClass() as Class<T>
#Deprecated("Use 'java' property to get Java class corresponding to this Kotlin class or cast this instance to Any if you really want to get the runtime Java class of this implementation of KClass.", ReplaceWith("(this as Any).javaClass"), level = DeprecationLevel.ERROR)
public inline val <T : Any> KClass<T>.javaClass: Class<KClass<T>>
#JvmName("getRuntimeClassOfKClassInstance")
#Suppress("UsePropertyAccessSyntax")
get() = (this as java.lang.Object).getClass() as Class<KClass<T>>
You can try now
YourClassName::class.java.simpleName
In Kotlin:
val className = serviceClass.javaClass.name
I think this is the better solution.
Found here https://www.techiedelight.com/determine-class-name-in-kotlin/
fun main() {
val s = "Kotlin"
println(s::class) // class kotlin.String
println(s::class.qualifiedName) // kotlin.String
println(s::class.simpleName) // String
}

Why does scalac take the Java vararg method instead of the single argument

We're using Elasticsearch as database and based upon a definition I'm creating a type mapping.
This mapping is basically a JSON object which gets built with the XContentBuilder of elasticsearch Java-API.
In my scala file I've defined an Enumeration object that holds the possible elasticsearch data-types like this:
object TypeMapping extends Enumeration {
val StringType = DataType("string")
val FloatType = DataType("float")
...
val GeoShapeType = DataType("geo_shape")
val AttachmentType = DataType("attachment")
final case class DataType(esType: String) extends Val {
override def toString: String = esType
}
}
Now when I use this in the creation of the mapping JSON like this:
val builder = jsonBuilder.startObject("name").field("type", StringType).endObject
the scala compiler can nicely resolves all the methods to call; no errors or warnings.
The method field is overloaded, each receiving a String parameter name and a parameter value. These values can be specific (String, int, int[], etc.) or vararg (String..., int..., etc.) but there's also an Object variant for both specific and vararg calls.
Now I would expect that the scala compiler would choose the field(String name, Object value) in the case I'm describing here, but to my suprise I find that the field(String name, Object... value) is being called.
I do not understand why this is happening. Can anybody explain this to me?
Scala picks the varargs version as more specific because (String, Array[Any]) can be applied to the other signature field(name: String, value: Any). (And not vice-versa.)
Given that both methods are in the same class, I'm not sure if there is a canonical workaround besides reflective access:
type Picker = {
def f(name: String, value: Any): Int
}
Console println x.f("hi", "high") // varargs
Console println (x: Picker).f("hi", "high") // not
Disambiguating:
public class JOver {
public int f(String name, Object value) { return 1; }
public int f(String name, Object... values) { return 2; }
}

Categories