Kotlin reflection returns incorrect type - reflection

I have an activity that implements a listener with a generic type that requires me to implement the onResponse function.
The listener is defined in the following format:
public interface ListenerClass<T> {
onResponse(T type)
}
And my activity implements it using T == ModelClass.
class MyActivity : ListenerClass<ModelClass> {
(...)
override fun onResponse(response: ModelClass) {
(...)
}
}
The listener is part of an SDK so I cannot change any code in there. They use a piece of reflection to get the type of my 'ModelClass' using the following code:
listener.getClass().getDeclaredMethods()[onResponseIndex].getParameterTypes()[0]
The result of this code should be Class<ModelClass> but I get Class<Object>. I found out that when I call the code above on a Java class, I get the correct result, but my activity is written in Kotlin.
1) How can I get the parameter type of a kotlin function using reflection?
2) If I have an answer to question 1 I still won't be able to change the SDK's code. Is there anything I can write in my Kotlin code that makes the piece of code above find the correct parameter class type?

Related

ActivatorUtilities.CreateInstance giving "A suitable constructor not found" for simple examples

So I am building a complex case here with inheritance and IOC, need to use ActivatorUtilities to inject instances and pass parameters... no matter what I do I get the following error:
System.InvalidOperationException: 'A suitable constructor for type
'blabla.ISimpleTest' could not
be located. Ensure the type is concrete and all parameters of a public
constructor are either registered as services or passed as arguments.
Also ensure no extraneous arguments are provided.'
So in order to discard what could be the problem and ensure there is no constructor issues, I created a very very simple scenario that gives me the same error.
startup.cs
services.AddScoped<ISimpleTest, SimpleTest>();
the class and the interface, very simple here:
public interface ISimpleTest
{
}
public class SimpleTest : ISimpleTest
{
public SimpleTest()
{
}
}
test
var theInstance = ActivatorUtilities.CreateInstance<ISimpleTest>(ServiceProvider);
Additional notes
The ServiceProvider instance is fine (the rest/entire application depends on it).
Tried with and without adding the public constructor(empty params)
Tried also constructor with params, same error.
Tried to specify the params[] parameter, by sending null or empty array, same issue.
Extra test:
Just to confirm it's properly registered, I tried to get the instance using the Service provider, and works without issues:
//No issues this way:
var yyy = ServiceProvider.GetService<ISimpleTest>();
What am I doing here wrong? According to documentations, this should be enough to work

Dart - Casting List<SuperType> to List<SubType> using generics

I am new to Flutter and Dart, coming from native Android.
Android has a very nice database abstraction architecture called the Room Persistence Library. As far as I am aware, no such database abstraction architecture exists for Flutter using the MVVM / MVC design patterns.
My solution was to create a Dart version of it myself. I got it pretty much done after a few headaches, but I cannot seem to get LiveData to work properly using generics.
I set up my class like this:
class LiveData<T> {
...
}
Now when I want to return some data, it can either be an Object or List<Object>. I found a neat hack for differentiating the two from T:
...
// Parse response
// This checks if the type is an instance of a single entity or a list.
if (entity is T) {
cachedData = rawData.isEmpty ? null : entity.fromMap(rawData.first) as T;
} else {
cachedData = rawData.map((e) => entity.fromMap(e)).toList() as T;
}
...
The problem lies in the second block:
cachedData = rawData.map((e) => entity.fromMap(e)).toList() as T;
With the error:
- Unhandled Exception: type 'List<Entity>' is not a subtype of type 'List<Vehicle>' in type cast
The question then becomes: How can I cast Entity to Vehicle when I do not have access to the Vehicle class. Only an instance of it is assigned to an Entity entity variable.
Here's a snippet to demonstrate my access to Vehicle:
final Entity entity;
...assign Vehicle instance to entity...
print(entity is Vehicle) // True
I've tried using .runtimeType to no avail. I have also thought about splitting LiveData into two classes, the second one being LiveDataList. Although this seems to be the easiest solution to not bug the code- it would bug me (bad pun is intentional) and break the otherwise pretty direct port of Room.
As a temporary solution, I have abstracted out the build logic into a generic function to be passed to the LiveData in the constructor.
final T Function(List<Map<String, dynamic>> rawData) builder;
And now I call that instead of the previous code to build the cachedData.
// Parse response
cachedData = builder(rawData);
With the constructor for the LiveData<List<Vehicle>> called when accessing all vehicles in the Dao<Vehicle> being:
class VehicleDao implements Dao<Vehicle> {
...
static LiveData<List<Vehicle>> get() {
return LiveData<List<Vehicle>>(
...
(rawData) => rawData.map((e) => Vehicle.fromMap(e)).toList(),
...
);
}
}
In Dart (and indeed in many languages) generics screws with the concept of inheritance. You would think that if Bar inherits from Foo, that List<Bar> would also be castable to List<Foo>.
This is not actually going to be the case because of how generics work. When you have a generic class, every time you use that class with a different type, that type is treated as a completely separate class. This is because when the compiler compiles those types, class MyGenericType<Foo> extends BaseClass and class MyGenericType<Bar> extends BaseClass are basically converted to something like class MyGenericType_Foo extends BaseClass and class MyGenericType_Bar extends BaseClass.
Do you see the problem? MyGenericType_Foo and MyGenericType_Bar are not descendants of one another. They are siblings of each other, both extending from BaseClass. This is why when you try to convert a List<Entity> to List<Vehicle>, the cast doesn't work because they are sibling types, not a supertype and subtype.
With all this being said, while you cannot directly cast one generic type to another based on the relationship of the generic type parameter, in the case of List there is a way to convert one List type to another: the cast method.
List<Entity> entityList = <Entity>[...];
List<Vehicle> vehicleList = entityList.cast<Vehicle>(); // This cast will work
One thing to note though, if you are casting from a supertype generic to a sub-type generic and not all the elements of the list are that new type, this cast will throw an error.

Kotlin reflection on object instance

I've been trying some stuff from kotlin.reflection during my project, and got stuck on something what occurs to me as hard to understand, I have declared object as follows:
object WebsiteMapping
{
const val ADMIN = "/admin"
}
once I call:
Arrays
.stream(WebsiteMapping::class.java.declaredFields)
.forEach { field -> println(field.type) }
what I get is:
class java.lang.String
class mapping.WebsiteMapping
When I looked a little bit into what is behind declaredFields invocation I grasped why it works as it is, but is there any convenient way of taking only declared consts within that object without getting also root of the whole structure?
The field with the type class mapping.WebsiteMapping is, basically, not the root of the structure but a special field generated in the object type that holds the reference to the singleton object.
In Kotlin, this field is named INSTANCE by convention. You can therefore filter the fields that you get from the class as follows:
WebsiteMapping::class.java.declaredFields
.filter { it.name != "INSTANCE" }
.forEach { println(it.type) }
Another solution is to switch from java.reflect.* to the Kotlin reflection API kotlin.reflect (needs a dependency on the kotlin-reflect module), which automatically filters the property:
WebsiteMapping::class.memberProperties
.forEach { println(it.returnType) }

Creating a new instance of a KClass

I have a Kotlin class whose primary (and only) constructor is empty.
I have a reference to this class:
val kClass: KClass<MyClass> = MyClass::class
How do I create an instance of this class using reflection?
In Java I would do myClass.newInstance() but it seems in Kotlin I need to find the constructor first:
kClass.constructors.first().call()
I have seen mention of primaryConstructor in some bug reports but it's not showing up in my IDE.
In your case, Java reflection might be enough: you can use MyClass::class.java and create a new instance in the same way as you would with Java reflection (see #IngoKegel's answer).
But in case there's more than one constructor and you really need to get the primary one (not the default no-arg one), use the primaryConstructor extension function of a KClass<T>. It is a part of Kotlin reflection, which is not shipped within kotlin-stdlib.
To use it, you have to add kotlin-reflect as a dependency, e.g. a in Gradle project:
dependencies {
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
}
Assuming that there is ext.kotlin_version, otherwise replace $kotlin_version with the version you use.
Then you will be able to use primaryConstructor, for example:
fun <T : Any> construct(kClass: KClass<T>): T? {
val ctor = kClass.primaryConstructor
return if (ctor != null && ctor.parameters.isEmpty())
ctor.call() else
null
}
You can use the Java class to create new instance:
MyClass::class.java.newInstance()
For those checking this question now, since Kotlin 1.1 there's also createInstance() extension method on KClass
Much like the accepted answer, this function works only in case class has an empty constructor or constructor with all default arguments.
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect.full/create-instance.html
Expanding on Alexeys Answer, to include a primary constructor call with parameters:
/* Example class with no-args constructor */
class MyClass
/* Example class requiring parameters */
class MyClassWithParams(parameter1: String, parameter2: MyClass)
val myKClass: KClass<MyClass> = MyClass::class
val myKClassWithParameters: KClass<MyClassWithParams> = MyClassWithParams::class
/* We can create an object by calling createInstance when no constructor parameters are required as explained in other answers. */
val myObject: MyClass = myKClass.createInstance()
/* To create an object with parameters, we need to get the constructor first, and call it with the parameters instead, similarly to how we would do in Java. */
val myObjectWithParameters: MyClassWithParams? =
myKClassWithParameters.primaryConstructor?.call(
"StringParameter", myObject
)

I can't dispatch custom event from one module to another as it gives TypeError: Error #1034: Type Coercion failed:

I am trying to dispatch a custom event from one flex module to another.
The code which dispatch the event is as below
Application.application.Destination.child.dispatchEvent(
new AlgoEvent(AlgoEvent.GETFROMPARENT_LOCAL_EVENT));
here AlgoEvent is a custom event
on the other side the module which catches and handles the event has this code:
public function sendParametersToChild(e:AlgoEvent):void
{
//some codes
}
but when the statement Application.application.Destination.child.dispatchEvent(new AlgoEvent(AlgoEvent.GETFROMPARENT_LOCAL_EVENT)); is executed the debugger give the following run time exception:
TypeError: Error #1034: Type Coercion failed: cannot convert resources.events::AlgoEvent#4182239 to resources.events.AlgoEvent.
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at mx.core::UIComponent/dispatchEvent()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\UIComponent.as:9298]
at components::Destination/sendTimeToChild()[E:\FlexProjects\MyApp\src\components\Destination.mxml:99]
at components::Destination/updateParameters()[E:\FlexProjects\MyApp\src\components\Destination.mxml:206]
at components::Destination/__CreateBasketButton_click()[E:\FlexProjects\MyApp\src\components\Destination.mxml:558]
I am not able to identify what is going wrong here.
Please help to solve this problem
This is my Event class
public class AlgoEvent extends Event
{
public static const GETFROMPARENT_LOCAL_EVENT:String = "getfromparent_local";
private var eventType:String;
public function AlgoEvent(eventType:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(eventType,bubbles,cancelable);
this.eventType=eventType;
}
}
While debugging am getting error in this funcion of UIComponent class
override public function dispatchEvent(event:Event):Boolean
{
if (dispatchEventHook != null)
dispatchEventHook(event, this);
return super.dispatchEvent(event);
}
Excaxtly this line gives the error: dispatchEventHook(event, this);
Import the AlgoEvent class in the main application and create a reference to it.
import resources.events.AlgoEvent;
private var dummyEvent: AlgoEvent;
Some explanations for this could be found here: Module domains
If your custom event doesn't carry any special event properties you could workaround your problem by using the standard Event class.
dispatchEvent(new Event(AlgoEvent.GETFROMPARENT_LOCAL_EVENT));
I had the same problem when dispatching, solved overriding two functions:
override public function clone():Event
{
return new AlgoEvent(type, bubbles, cancelable);
}
override public function toString():String
{
return formatToString("AlgoEvent","type"","bubbles","cancelable","eventPhase");
}
hope it helps out :)
Mr. splash suggested a solution which worked fro me:
Try to make the Custum Event (Algo Event in my case) class known to the main application.
I.e import it in the main application and create a variable of it..
And it works for a main reason>>when we try to communicate betwwen the modules using event dispatching what happens is :the modules are loaded at the run time but the classes like event classes are linked to the modules at the run time..
But the Event class is compiled before the modules are loaded..
application defines a Custum Event Class at compile time, and the module defines its own Custum Event Class when it is published. Then when the application is run, the Custum Event Class dispatched in the application doesn't match the one in the module
swf.
For the problem which is causing this error one can check the link:
http://www.kirupa.com/forum/showthread.php?t=320390
and also
http://www.jeffdepascale.com/index.php/flash/custom-events-in-loaded-swf-files/
Mate framework takes care of all this.
It gives you a global event bus, for all modules in your app.
http://mate.asfusion.com/
Try to override the clone() method in your customized Event,AlgoEvent.
Add the following code to your AlgoEvent.as class and try:
override public function clone():Event{
return new AlgoEvent(eventType,bubbles,cancelable);
}
HTH.
Your custom Event class should look like this:
public class AlgoEvent extends Event
{
public static const GETFROMPARENT_LOCAL_EVENT:String = "getfromparent_local";
public function AlgoEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
};
override public function clone():AlgoEvent
{
return new AlgoEvent(type, bubbles, cancelable);
};
};
You should use the Event's inherited type property instead of creating a new one.
Also, the UIComponent has it's own dispatchEvent method, so you don't have to create your own - only if it works differently to the inherited one.
Regards,
Rob
Okay, it must be said that what you're doing, from an architectural standpoint, is wrong. Calling Application.application is bad for so many reason, especially if you're then starting to go down the display tree. The second any of the children changes, your build is now broke, and you won't know that until runtime because it's a module.
What you need is an application framework. A way to increase complexity without decreasing maintainability. There are many out there, but my personal favorite is Parsley. I've used it on many very large projects with much success. The problem you're trying to solve right now, dispatching one event where the other module listens for it, is extremely trivial (can be done in about 3 lines of code).
I recommend you look it over as well as my presentation on an introduction to parsley.

Resources