How to get KClass from Kproperty? [duplicate] - java

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.

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)

Get Class Name for the given String

I have a use case, where I have stored the List of Java Data Types in DB, Like Byte, Character, Integer, Long, BigDecimal, BigInteger, Boolean.
So my use case is like If I read the value Long, I need to create the Long.class, if I read String, then String.class.
Class cls = Class.forName("java.lang.Long);, then I can use the cls for my own purpose.
I can achieve this, by having Enum of the above data types, as soon I read the value from the db, I pass the value to enum to get the class type. But I don't know whether it is efficient or not. Is there any method present in Java which gives like, for the given string,(without fully qualified name), it should return the class type.
Storing a reference to the Class object is efficient but using the Class object for reflection can be expensive. If you're just using the Class for reference then you're fine.
enum Decodable {
BIG_INTEGER(BigInteger.class),
INTEGER(Integer.class)
// etc
private final Class<?> decodableClass;
private Decodable(Class<?> decodableClass) {
this.decodableClass = decodableClass;
}
}
You could also just maintain a Set of Class objects.
private static final Set<Class<?>> DECODABLE_CLASSES = ImmutableSet.of(Integer.class, BigInteger.class); //etc

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.

Compiler warning while using #Value annotation in Kotlin project

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;
}
}
}

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