Is it safe to call kclass.memberProperties on an unknown (Any) object? - reflection

I assumed that it's OK to just access members field of a KClass object. But I have found a case when it's not. Both tests throw exceptions.
#Test fun mapProperties() {
val map = mapOf("a" to "b")
val cls = map.javaClass.kotlin
cls.members
}
Throws: kotlin.reflect.KotlinReflectionInternalError: Incorrect resolution sequence for Java field public open val values: kotlin.collections.MutableCollection<(V..V?)> defined in java.util.Collections.SingletonMap[JavaPropertyDescriptor#10163d6]
#Test fun mapProperties2() {
val map = mapOf("a" to "b")
val cls = clsByReified(map)
cls.members
}
inline fun <reified T: Any> clsByReified(instance: T): KClass<T> {
return T::class
}
Throws: kotlin.reflect.KotlinReflectionInternalError: No metadata found for public abstract val entries: [Not-computed] defined in kotlin.collections.Map[DeserializedPropertyDescriptor#5c1a8622]
Not sure if I stumbled upon a bug or just missing something.

This is a bug that has been fixed recently and is available in nightly builds. The upcoming Kotlin 1.0.2 release will include the fix. Here's the original issue: KT-11258.

Related

kotlin -- can I rewrite this map access to get rid of the ``!!``?

Let's say I have a
enum class ConceptualPosition{
A1,A2,A3,A4,A5,A6,A7,A8,
B1,B2,B3,B4,B5,B6,B7,B8,
C1,C2,C3,C4,C5,C6,C7,C8
}
And I now want to construct a Graph where every position has a Node.
import [...].domain.model.base.ConceptualPosition
import [...].domain.model.base.ConceptualPosition.*
import [...].domain.model.base.Node
import [...].domain.model.base.Node.MovableDirection.*
class MyGraph:Graph{
private val internalPositions = mutableMapOf<ConceptualPosition, Node>()
override val position by lazy {internalPositions.toMap().withDefault {
throw IllegalArgumentException("position '$it' does not exist")
}}
init{
//create nodes for all positions
ConceptualPosition.values().forEach { internalPositions[it] = Node(it) }
//now build graph
position[A1]!!.connectBothWaysWith(position[A2]!!,RIGHT)
position[A2]!!.connectBothWaysWith(position[A3]!!,RIGHT)
[...]
}
}
since I have a withDefault that immediately throws an exception and since Kotlin correctly infers the type of position to be Map<ConceptualPosition,Node>, I think I can be fairly sure that if a lookup does not fail, I get a non-null value out of it.
Kotlin apparently cannot safely infer that.
Can I refactor this (in a reasonable way) to get rid of the !!?
Use Map.getValue instead of get:
position.getValue(A1).connectBothWaysWith(position.getValue(A2),RIGHT)
Alternately, you could define your own version of withDefault with a more precise return type (the Kotlin standard library makes the equivalent private):
class MapWithDefault<K, V>(val map: Map<K, V>, val default: (K) -> V) : Map<K, V> by map {
override fun get(key: K): V = map[key] ?: default(key)
}
fun <K, V> Map<K, V>.withDefault(default: (K) -> V) = MapWithDefault(this, default)

How to change a member field with Kotlin reflection?

I'm porting a class from Java to Kotlin. This class declares hundreds of objects. Each object has a name property which is identical with the declared variable name of the object. Java reflection allows to use the declared name via reflection to set the object member name. Just saves one parameter in hundreds of constructors.
I try to do the same in Kotlin but can't figure out how to do the property setting. Here is some simplified test code:
import kotlin.reflect.full.companionObject
import kotlin.reflect.full.declaredMemberProperties
class MyTestObject() {
var name: String = "NotInitialized"
companion object {
val Anton = MyTestObject()
val Berta = MyTestObject()
val Caesar = MyTestObject()
}
}
fun main(args : Array<String>) {
println(MyTestObject.Anton.name) // name not yet initialized
// Initialize 'name' with the variable name of the object:
for (member in MyTestObject::class.companionObject!!.declaredMemberProperties) {
if (member.returnType.toString() == "myPackage.MyTestObject") {
println("$member: ${member.name}")
// Set 'name' property to 'member.name':
// ???
}
}
println(MyTestObject.Anton.name) // now with the initialized name
}
The ??? line is where I would like to get access to the name property of MyTestObject to set it to to member.name. I'm looking for a function similar to (member.toObject() as MyTestObject).name = member.name.
While kotlin-reflection strives to be type-safe, sometimes the type system and the inference logic are not enough to allow for the things like what you are trying to do in a type-safe way. So, you have to make unchecked casts, stating that your knowledge about the types is more than the compiler can infer.
In your case, it's enough to cast member so that you can pass the companion object instance into its .get(...) and use the result as a MyTestObject, replace the // ??? line with:
#Suppress("UNCHECKED_CAST")
(member as KProperty1<Any, MyTestObject>)
.get(MyTestObject::class.companionObject!!.objectInstance!!)
.name = member.name
If you can replace MyTestObject::class.companionObject!! with MyTestObject.Companion::class (i.e. your actual use case does not involve getting .companionObject from different classes), the unchecked cast is not needed, and you can replace the statement above with this:
(member.get(MyTestObject.Companion) as MyTestObject).name = member.name
As an alternative that does not require companion object reflection at all, you can do the same binding logic with the delegation. Implementing provideDelegate allows you to customize the logic of initializing the property, and that's where you can assign the names:
operator fun MyTestObject.provideDelegate(
thisRef: MyTestObject.Companion,
property: KProperty<*>
) = apply { name = property.name }
operator fun MyTestObject.getValue(
thisRef: MyTestObject.Companion,
property: KProperty<*>
) = this
Then declare your properties as
val Anton by MyTestObject()
val Berta by MyTestObject()
val Caesar by MyTestObject()
Here is the final test code based on hotkey's solution:
package myPackage
import kotlin.reflect.full.declaredMemberProperties
class MyTestObject() {
lateinit var name: String
companion object {
val Anton = MyTestObject()
val Berta = MyTestObject()
val Caesar = MyTestObject()
init {
for (member in MyTestObject.Companion::class.declaredMemberProperties) {
if (member.returnType.toString() == "myPackage.MyTestObject") {
(member.get(MyTestObject.Companion) as MyTestObject).name = member.name
}
}
}
}
}
fun main(args : Array<String>) {
println(MyTestObject.Anton.name)
println(MyTestObject.Caesar.name)
}

How to implement TornadoFX WebEngine Callback in Kotlin

I am using Kotlin TornadoFX to create a browser. When I implement WebEngine setCreatePopupHandler, I get an error:
e: surfing\src\surfing.kt: (76, 13): Modifier 'override' is not
applicable to 'local function'
e: surfing\src\surfing.kt: (76, 13): Expected a value of type WebEngine!
I referenced this Java code using JavaFX:
webEngine.setCreatePopupHandler(
new Callback<PopupFeatures, WebEngine>() {
#Override
public WebEngine call(PopupFeatures config) {
smallView.setFontScale(0.8);
if (!toolBar.getChildren().contains(smallView)) {
toolBar.getChildren().add(smallView);
}
return smallView.getEngine();
}
});
Translated into Kotlin to use TornadoFX:
var wv = webview()
val br = wv.getEngine()
br.setCreatePopupHandler(Callback<PopupFeatures, WebEngine>() {
override fun call(pf: PopupFeatures): WebEngine {
var smallView = webview()
val stage = Stage(StageStyle.UTILITY)
stage.setScene(Scene(smallView))
stage.show()
val engine = smallView.getEngine()
return engine
}
})
I have been searching for a long time on the internet, but I didn't find anything. Please can somebody help me fix this error.
You're almost there :) To create an anonymous class much the same way you do in Java, you need to use the object keyword in front of the class statement:
br.createPopupHandler = object : Callback<PopupFeatures, WebEngine> {
However, Kotlin allows you to turn SAM types into lambdas. You can also utilize the property access pattern and immutable values to clean up the code a little. Here is a the code rewritten and Kotlinified:
val wv = webview()
val br = wv.engine
br.setCreatePopupHandler {
val smallView = webview()
val stage = Stage(StageStyle.UTILITY)
stage.scene = Scene(smallView)
stage.show()
smallView.engine
}
I haven't really evaluated what you're doing here or if that's a good idea, so only take my advice on the syntax :)

why SomeClass::class is KClass<SomeClass> but this::class is KClass<out SomeClass>

I want to print values of properties of my class.
fun print() {
val cl = this::class
cl.declaredMemberProperties.filter {it.visibility != KVisibility.PRIVATE}.forEach {
println("${it.name} = ${it.get(this)}")
}
}
When I try to build this code I get compiler error:
Error:(34, 40) Kotlin: Out-projected type 'KProperty1<out SomeClass, Any?>' prohibits the use of 'public abstract fun get(receiver: T): R defined in kotlin.reflect.KProperty1'
When I change this to class name SomeClass everything is fine
fun print() {
val cl = SomeClass::class
cl.declaredMemberProperties.filter {it.visibility != KVisibility.PRIVATE}.forEach {
println("${it.name} = ${it.get(this)}")
}
}
So the problem is that compiler changers type of this::class to KClass<out SomeClass> instead of using KClass<SomeClass>. Any idea why does it happen?
The reason for this difference is that, when you use the SomeClass::class reference, it is sure to be the class token representing SomeClass and not one of its possible derived classes, therefore it is KClass<SomeClass> without type projections.
But this::class written in a function of an open or abstract class or an extension function can return a class token of a derived class, therefore, to ensure type safety, the type is out-projected: KClass<out SomeClass> means that the actual type argument can be SomeClass or its subtype.
Example:
open class A {
fun f() {
println(this::class) // KClass<out A> because it can be KClass<B>
}
}
class B : A()
B().f()

Scala: How do I dynamically instantiate an object and invoke a method using reflection?

In Scala, what's the best way to dynamically instantiate an object and invoke a method using reflection?
I would like to do Scala-equivalent of the following Java code:
Class class = Class.forName("Foo");
Object foo = class.newInstance();
Method method = class.getMethod("hello", null);
method.invoke(foo, null);
In the above code, both the class name and the method name are passed in dynamically. The above Java mechanism could probably be used for Foo and hello(), but the Scala types don't match one-to-one with that of Java. For example, a class may be declared implicitly for a singleton object. Also Scala method allows all sorts of symbols to be its name. Both are resolved by name mangling. See Interop Between Java and Scala.
Another issue seems to be the matching of parameters by resolving overloads and autoboxing, described in Reflection from Scala - Heaven and Hell.
There is an easier way to invoke method reflectively without resorting to calling Java reflection methods: use Structural Typing.
Just cast the object reference to a Structural Type which has the necessary method signature then call the method: no reflection necessary (of course, Scala is doing reflection underneath but we don't need to do it).
class Foo {
def hello(name: String): String = "Hello there, %s".format(name)
}
object FooMain {
def main(args: Array[String]) {
val foo = Class.forName("Foo").newInstance.asInstanceOf[{ def hello(name: String): String }]
println(foo.hello("Walter")) // prints "Hello there, Walter"
}
}
The answers by VonC and Walter Chang are quite good, so I'll just complement with one Scala 2.8 Experimental feature. In fact, I won't even bother to dress it up, I'll just copy the scaladoc.
object Invocation
extends AnyRef
A more convenient syntax for reflective
invocation. Example usage:
class Obj { private def foo(x: Int, y: String): Long = x + y.length }
You can call it reflectively one of
two ways:
import scala.reflect.Invocation._
(new Obj) o 'foo(5, "abc") // the 'o' method returns Any
val x: Long = (new Obj) oo 'foo(5, "abc") // the 'oo' method casts to expected type.
If you call the oo
method and do not give the type
inferencer enough help, it will most
likely infer Nothing, which will
result in a ClassCastException.
Author Paul Phillips
The instanciation part could use the Manifest: see this SO answer
experimental feature in Scala called manifests which are a way to get around a Java constraint regarding type erasure
class Test[T](implicit m : Manifest[T]) {
val testVal = m.erasure.newInstance().asInstanceOf[T]
}
With this version you still write
class Foo
val t = new Test[Foo]
However, if there's no no-arg constructor available you get a runtime exception instead of a static type error
scala> new Test[Set[String]]
java.lang.InstantiationException: scala.collection.immutable.Set
at java.lang.Class.newInstance0(Class.java:340)
So the true type safe solution would be using a Factory.
Note: as stated in this thread, Manifest is here to stay, but is for now "only use is to give access to the erasure of the type as a Class instance."
The only thing manifests give you now is the erasure of the static type of a parameter at the call site (contrary to getClass which give you the erasure of the dynamic type).
You can then get a method through reflection:
classOf[ClassName].getMethod("main", classOf[Array[String]])
and invoke it
scala> class A {
| def foo_=(foo: Boolean) = "bar"
| }
defined class A
scala>val a = new A
a: A = A#1f854bd
scala>a.getClass.getMethod(decode("foo_="),
classOf[Boolean]).invoke(a, java.lang.Boolean.TRUE)
res15: java.lang.Object = bar
In case you need to invoke a method of a Scala 2.10 object (not class) and you have the names of the method and object as Strings, you can do it like this:
package com.example.mytest
import scala.reflect.runtime.universe
class MyTest
object MyTest {
def target(i: Int) = println(i)
def invoker(objectName: String, methodName: String, arg: Any) = {
val runtimeMirror = universe.runtimeMirror(getClass.getClassLoader)
val moduleSymbol = runtimeMirror.moduleSymbol(
Class.forName(objectName))
val targetMethod = moduleSymbol.typeSignature
.members
.filter(x => x.isMethod && x.name.toString == methodName)
.head
.asMethod
runtimeMirror.reflect(runtimeMirror.reflectModule(moduleSymbol).instance)
.reflectMethod(targetMethod)(arg)
}
def main(args: Array[String]): Unit = {
invoker("com.example.mytest.MyTest$", "target", 5)
}
}
This prints 5 to standard output.
Further details in Scala Documentation.
Working up from #nedim's answer, here is a basis for a full answer,
main difference being here below we instantiate naive classes. This code does not handle the case of multiple constructors, and is by no means a full answer.
import scala.reflect.runtime.universe
case class Case(foo: Int) {
println("Case Case Instantiated")
}
class Class {
println("Class Instantiated")
}
object Inst {
def apply(className: String, arg: Any) = {
val runtimeMirror: universe.Mirror = universe.runtimeMirror(getClass.getClassLoader)
val classSymbol: universe.ClassSymbol = runtimeMirror.classSymbol(Class.forName(className))
val classMirror: universe.ClassMirror = runtimeMirror.reflectClass(classSymbol)
if (classSymbol.companion.toString() == "<none>") // TODO: use nicer method "hiding" in the api?
{
println(s"Info: $className has no companion object")
val constructors = classSymbol.typeSignature.members.filter(_.isConstructor).toList
if (constructors.length > 1) {
println(s"Info: $className has several constructors")
}
else {
val constructorMirror = classMirror.reflectConstructor(constructors.head.asMethod) // we can reuse it
constructorMirror()
}
}
else
{
val companionSymbol = classSymbol.companion
println(s"Info: $className has companion object $companionSymbol")
// TBD
}
}
}
object app extends App {
val c = Inst("Class", "")
val cc = Inst("Case", "")
}
Here is a build.sbt that would compile it:
lazy val reflection = (project in file("."))
.settings(
scalaVersion := "2.11.7",
libraryDependencies ++= Seq(
"org.scala-lang" % "scala-compiler" % scalaVersion.value % "provided",
"org.scala-lang" % "scala-library" % scalaVersion.value % "provided"
)
)

Resources