Scala: How to know if a class is an enumeration; isInstanceOf[Enumeration] doesn't work - reflection

I'm in scala writing a serializer that saves an object (or Model) to the database (for app engine), and I need to treat some fields as special cases. For example, if the field is of type Array[Byte], I Save it as a blob. And I need to treat Enumerations as special cases too, but I can't find out how to know if a type is an enumeration.
For example:
object UserType extends Enumeration {
val Anonym, Registered, Admin, Super = Value
}
var value = UserType.Admin
value.isInstanceOf[Enumeration] // this returns false
Neither I can do value.isInstanceOf[Enumeration.Value] since Value is private... anyway I think that would return false too.
Any idea?
Thanks!

value.isInstanceOf[Enumeration$Value]

You could figure this out using these methods:
scala> value.getClass
res102: java.lang.Class[_] = class scala.Enumeration$Val
scala> value.getClass.getSuperclass
res103: java.lang.Class[_ >: ?0] = class scala.Enumeration$Value
scala> value.getClass.getSuperclass.getSuperclass
res104: java.lang.Class[_ >: ?0] = class java.lang.Object

Related

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.

How to set type of a class using local variable that holds that type?

I've got a method that does the following:
val type = AClass::class.java.methods[0].parameters[0].type
val toDeserialise = SecondClass<type>()
My SecondClass is:
class SecondClass<T : Any> {
lateinit var p1: T
}
But this doesn't work. Basically, I want to take a type of a method's parameter and pass it into a SecondClass. Do you know how to implement this?
The AClass is:
class AClass{
fun myMethod(param1: String, param2: UUID)
}
So, I want the
val type
to be String, which I pass into SecondClass.
Reflection is resolved at runtime, and generic types are resolved at compile time.
The SecondClass is subject to type erasure, so what you want to do is essentially impossible.
Even if you try to work around it with a switch:
val type = AClass::class.java.methods[0].parameters[0].type
val toDeserialize = when(type){
String::class.java -> SecondClass<String>()
else -> SecondClass<Any>()
}
This will bring you no benefit since you won't be able to check the actual type of SecondClass.

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
)

Scala 2.10 Pass field as argument

Think of a case class like this:
case class User(firstname: String, lastname: String)
now think of calling a method check with the firstname
check(User.firstname)
The Problem is, that the method check must have the name of the field too. It must have fieldname and fieldvalue -> "firstname" and "John"
The Question is, is it possible to pass the field of a class instead of its value in the style check(User.firstname)?
I thought check could look like this (preudocode):
def check(fieldName: String, fieldValue: Any) = {
println(fieldName + ": " + fieldValue)
}
or this
def check(field: Field) = {
println(field.getName)
}
I could pass the fieldname as String by hand but the problem is, the String would not change if I refactor the fieldname and it must match.
Maybe a macro could help? Is there any other solution?
enter link description herefirst I assume check method is always return same type(Unit\String) else you need to use generics.
second, you can use Enums for mapping
myEnum match {
case MyEnum.firstname => myObj.firstname
case MyEnum.lastname =>myObj.lastname
case _ => ....
}
if you dont want to use Enums, you will have to use scala reflection.
Scala 2.10 reflection, how do I extract the field values from a case class
If the fieldname is known at compile time you can use macros. Otherwise you can use runtime reflection. So runtime reflection gives you more flexibility, while macros give you better performance and compile time safety.

How to access a field's value via reflection (Scala 2.8)

Consider the following code:
class Foo(var name: String = "bar")
Now i try to get the value and the correct type of it via reflection:
val foo = new Foo
val field = foo.getClass.getDeclaredField("name")
field.setAccessible(true)
//This is where it doesn't work
val value = field.get(????)
I tried things like field.get(foo), but that just returns an java.lang.Object but no String. Basically I need the correct type, because I want to invoke a method on it (e. g. toCharArray).
What is the suggested way to do that?
As others have mentioned, the reflection methods return Object so you have to cast. You may be better using the method that the Scala compiler creates for field access rather than having to change the visibility of the private field. (I'm not even sure if the name private field is guaranteed to be the same as that of the accessor methods.)
val foo = new Foo
val method = foo.getClass.getDeclaredMethod("name")
val value = method.get(foo).asInstanceOf[String]
getDeclaredField is a method of java.lang.Class.
You have to change foo.getDeclaredField("name") to foo.getClass.getDeclaredField("name") (or classOf[Foo].getDeclaredField("name")) to get the field.
You can get the type with getType method in class Field but it won't help you because it returns Class[_]. Given than you know that the type is a String you can always cast the value returned using field.get(foo).asInstanceOf[String]
AFAIK, reflection always work with Object, and you have to cast the results yourself.
This is how one can get list of fieldnames and its value of a case class:
First, using reflection, get fields info as follows -
val TUPLE2_OF_FIELDNAME_TO_GETTERS = typeOf[<CLASS>].members
.filter(!_.isMethod)
.map(x => (x.name.toString, classOf[<CLASS>].getDeclaredMethod(x.name.toString.trim)))
How to use it?
getFieldNameAndValue(obj: <CLASS>): Seq[(String, String)] {
var output = Seq[(String, String)]()
for(fieldToGetter <- TUPLE2_OF_FIELDNAME_TO_GETTERS) {
val fieldNameAsString = fieldToGetter._1
val getter = fieldToGetter._2
val fieldValue = getter.invoke(obj).toString
output += (fieldName, fieldValue)
}
}
foo.getClass.getDeclaredField("name").getString(foo)
should work if you want to avoid asInstanceOf. get* is available for various types

Resources