HashMap errors - containsKey, get - kotlin

Can anyone shed some light?
Problem code:
protected var table = HashMap<Class<*>, Double>()
if (table.containsKey(object)) {
value = table.get(object)
}
containsKey(K):Boolean is deprecated. Map and Key have incompatible
types. upcast to Any? if you're sure
so I changed it to this:
if (table.containsKey(object as Any?)
which fixes the error, but is this what I should have done to fix it? or is there a better way?
also .get(object) has an error:
Type inference failed. required: kotlin.Double found kotlin.Double?
same error message for this too:
val c = someObject.javaClass // pre j2k code: final Class<? extends SomeClass> c = someObject.getClass();
weight = weightingTable[c] <-- error here
I don't know what to do here

The containsKey call is reported as an error because the type of the argument you pass to it does not match the type of the map key. Your map contains classes as keys, and you're trying to pass an object instance to it. Changing this to object as Any? is not a useful fix, because this call will compile but will always return false. What you need to do instead is to use object.javaClass to get the class of the object.
The weightingTable[c] call is reported as an error because the map does not necessarily contain a value for the key you're passing to it, so the result of the [] operation is nullable. You cannot assign a nullable value to a non-null variable without somehow handling the null case (using a check, an explicit non-null cast or some other option covered in the documentation).

When doing:
myHashMap.get(object)
and getting:
Type inference failed. required: kotlin.Double found kotlin.Double?
even when you already checked with containsKey. You can solve it by using:
myHashMap.getOrElse(key) { defaultValue }

Related

Getters cannot be used to identify return type properly in Kotlin

I have a data class that has the following form:
data class ContentElementField(val type: String) {
val text: String? = null
get() = requireNotNull(field)
val style: String? = null
get() = requireNotNull(field)
val path: String? = null
get() = requireNotNull(field)
val caption: String? = null
get() = requireNotNull(field)
}
The problem arises when I want to perform the following operation:
when (it.type) {
"text" -> TextElement(Text(it.text), Style(it.style))
"image" -> ImageElement(Path(it.path), Caption(it.caption))
}
The compiler warns me about that You cannot send a nullable type to a function that does not accept nullable arguments.
Even if the field is signed to be nullable, its getter is signed to be not nullable, though.
The compiler should use getters to resolve whether to give this warning.
What would you offer to get around this problem?
It doesn't matter if your getter happens to crash if the current value is null - the type is still nullable, the getter's return type is still String?.
Why are you doing this anyway? Why not just make the fields non-null as normal and let a null assignment throw the exception instead? That way you won't have to fight the type system.
If what you have in mind is different and this was just meant to be a simple example, then you have a few options:
Use !! at the call site since you're guaranteeing it's not null
"text" -> TextElement(Text(it.text!!), Style(it.style))
Expose the private nullable property through a non-null one:
// I see people do this a lot in Activities and Fragments even though
// they should probably just be making the one property lateinit instead
private val _text: String? = whatever
val text: String get() = requireNotNull(_text)
Maybe look at Kotlin contracts which allow you to make guarantees to the compiler about values (no example because I've never used it)
It's not really clear what you actually want to do though, or why this is useful. Your example is even using vals and assigning null to them. Whatever your real use case is, there's probably a better way.
(Also in case you're not aware, properties that aren't constructor parameters aren't included in the basic data class behaviour, i.e. its equals/hashCode/toString implementations. Another reason just making the types non-null helps, you can stick them in the constructor instead of having to do this logic)

mockkStatic for extension method with generic parameter: "Not enough information to infer type variable T"

FYI: I'm currently using Mockk-1.12.4 and Kotlin-1.6
I've got an extension method that returns an object of type T:
fun <T> Entity.selectReferenceAsSingleObject(referenceName: String): T {
return this.selectReferencesByName(referenceName).single().asObjet() as T
}
This is defined as top level function in an Extentions.kt file (so not a class). I'm wanting to mock this with MockK by using mockkStatic
mockkStatic(Entity::selectReferenceAsOptionalSingleObject)
However I'm getting the error:
Not enough information to infer type variable T
because it cannot work out what type I should be mocking. I've tried adding my type parameter in a bunch of places
mockkStatic<KFunction<MyType>>(Entity::selectReferenceAsSingleObject)
mockkStatic<MyType>(Entity::selectReferenceAsSingleObject)
mockkStatic(Entity<KFunction<MyType>>::selectReferenceAsSingleObject)
mockkStatic(Entity<MyType>::selectReferenceAsSingleObject)
mockkStatic(Entity::<KFunction<MyType>>selectReferenceAsSingleObject)
mockkStatic(Entity::<MyType>selectReferenceAsSingleObject)
mockkStatic(Entity::selectReferenceAsSingleObject<KFunction<MyType>>)
mockkStatic(Entity::selectReferenceAsSingleObject<MyType>)
mockkStatic(Entity::selectReferenceAsSingleObject as KFunction<MyType>)
mockkStatic(Entity::selectReferenceAsSingleObject as MyType)
But nothing works and it either tells me the same error or tells me that type arguments are not allowed there. I'm not sure what I need to do to fix my syntax as IntelliJ isn't giving me any hints so I feel kind of stuck. Any help would be appreciated.
Try this:
mockkStatic("your.package.YourFileExtensionKt")
you can also give the file a nice name:
#file:JvmName("Extension")
would look like this:
mockkStatic("your.package.Extension")
anyway for the test to work you must use a mock in the extended class, in this case Entity, it would look like this:
#Test
fun test() {
val entity : Entity = mockk(relaxed = true)
every { entity.selectReferenceAsSingleObject<Any>(any()) } returns "whatever"
val result = entity.selectReferenceAsSingleObject<Any>("test")
assertEquals("whatever", result)
}

Collection<KProperty1<I,*>> How to get the property instance

I'm currently using Reflection to inspect an element at runtime using the class.memberProperties function. The type of properties is collection<KProperty1<I, *>> so I run through each of the KProperty objects to find the one that I want by checking if the name is equal to "nameIWant", though I would much rather be able to get the instance of the property from the KProperty by using the .get() method on the property, so that then I could do a check such as:
if (property.get(receiver) is ClassIWant) {
//Do something
}
My code looks like this:
val properties = request.payload::class.memberProperties
properties.forEach { property ->
run {
if (property.name.equals("nameIWant")) {
}
}
}
So far I've been trying to use the .get() method on the KProperty1 type but it takes an argument receiver of type Nothing. I'm not able to work out what I need to pass in order to call the .get() method and get the particular instance of the property. I've also checked the documentation here: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect/-k-property1/index.html but it hasn't really helped at all.
justPassingBy is right. but the more simple way is to use:
myObj.javaClass.kotlin.memberProperties.foreach { property ->
property.get(myObj)
}
If you want to get the value of the property, cast the class into invariant type.
instance::class.memberProperties.first() // returns KProperty1<out Instance, *>
(instance::class as KClass<Instance>).memberProperties.first() // returns KProperty1<Instance, *>
If your KClass<Instance> is KClass<*>, use Any as Instance.
Why did the KProperty.call take Nothing as receiver?
Because instance::class returns KClass<out Instance>, which propagates the covariant type argument down to the property, which it becomes KProperty<out Instance, *>, which narrows down the possible method receiver to any subtype of Instance, but because we do not know which, we can not safely supply any instance of Instance, as show by the rules of variance, which here limit the generic type argument to Nothing, which means it is impossible to call the method at all.
Why is ::class designed to be covariant?
To guarantee safety. This has been an issue of great debates as it seems somewhat illogical.
If you want to know the type of the value that the property can return, use
property.returnType
It returns a KType, wich is Kotlin's version of Java's Type, which is a more generic concept of a Class (which is one of the implementations of Type).
If you need to 'convert' the KType to a KClass, you need to do the same as if you needed to convert Type to a Class, which is get the raw type of the type. Raw type is type stripped of the any generic information, yes, an erased type. The way to do this is (seemingly) more complicated (involves handling each possible KType/Type implementation) and I recommend checking for answer to this problem separately.
You will be able to reuse Java implementation (that you will surely find on your own) using:
kType.javaType.covertJavaTypeToJavaClass().kotlin // returns KClass<*>
Corrections in your question. I recommend using the proper terms if you wish to receive proper answers:
* I in your question is type of the method receiver, not the value of the property
* collection is not a type, Collection is
* property is ClassIWantis ambiguous as property.type is type of the value in the property and property::class is simply the property implementation, is is also an instanceof check, but in reflection, you need to use KClass.isSubclassOf, or what is known in Java as type.isAssignableFrom (watch the call order), which then makes your condition to be ClassIWant.isSuperclassOf(property.type.getRawType())
* instance of the property properties have values, not instances. Only classes have instances. Instances are values and values are instances (of some class), but you must still say instance representing the value of the property
You can create a KType for your ClassIWant and then check the property's returnType. It will be something like this:
val properties = request.payload::class.memberProperties
val desiredType = ClassIWant::class.createType()
properties.forEach { property ->
if (property.name == "nameIWant" && property.returnType == desiredType) {
//todo
}
}
btw you can cast your property variable to correct type and use get
val properties = request.payload::class.memberProperties
properties.forEach { property ->
val value = (property as KProperty1<Payload, *>).get(request.payload)
if (property.name == "nameIWant" && value is ClassIWant) {
//todo
}
}
prop.getter.call(obj) as String?

kotlin: wrong inference of nullability in function reference?

i want to choose a validation function for a nullable string:
val aString: String? = ...
val validation
// : KFunction1<CharSequence?, Boolean>
= if (...) Objects::isNull else StringUtils::isNotBlank
isNotBlank is from apache commons. it takes string and returns bool.
when i uncomment explicit type declaration all is good. but when there is no explicit type declared, it infers KFunction1<CharSequence, Boolean> so parameter cannot be null. why?
This is intended behavior. The type to the left of :: is actually the type of the instance you're going to pass to the reference as the first argument, so type inference uses it as the first argument to KFunction1.
If you'd like a reference to be callable on StringUtils? objects, use StringUtils?::isNotBlank, but the StringUtils::isNotBlank reference will only accept non-null StringUtils objects.
Reference

swift closure stored and access as a variable

I want to implement a callback in a swift project just like I used to do in Objective-C
I need a variable of type closure. That closure should take as a parameter an object and return nothing.
var downloadCompleted: (MLBook) -> (Void)!
When I need to trigger the callback I do this:
if self.downloadCompleted {
self.downloadCompleted(book)
}
The compiler complains with this error message:
Type '(MLBook) -> (Void)!' does not conform to protocol 'BooleanType'
If I remove the if statement the compiler says:
Property 'self.downloadCompleted' not initialized
even though it's implicitly unwrapped.
When I try to get the callback:
BookStore.sharedInstance.downloadCompleted{(book: MLBook) -> () in
println("Print if you got the callback")
}
I get this error message:
'(MLBook) -> ()' is not convertible to 'MLBook'
I'm more worried about the last error message as I'm not quite sure what it is trying to tell me.
Any help would be appreciated. Thanks
Here is your working example. You have a number of mistakes which the attached illustrates. Note
I had the download() method return Bool so that the result can be see in this screen shot.
But, your use of an implicitly unwrapped optional (aka '!') is incorrect. Such an optional is used when the value may be nil but will be assigned at a known time and not changed (see Apple documentation for a description). Your downloadCompleted is a true optional (at least in your example use). Thus, better code, which turns out to be slightly simpler is:
2 mistakes. 1st, The whole type should be wrapped in (), then followed a ? or ! as a optional or implicit unwrapped optional. 2nd, you should check with nil, in swift, no implicit boolean conversion.
In your use case, you should use Optional instead of Implicit unwrapped. Because there is big chance that your property has a nil value. With IUO(Implicit unwrapped optional), you skip compiler warning and will get a runtime error.
import Foundation
class MLBook {
var name = "name"
}
class A {
var downloadCompleted: ((MLBook) -> Void)?
func down(){
var book = MLBook()
if let cb = self.downloadCompleted {
cb(book)
}
}
}
var a = A()
a.downloadCompleted = {
(book: MLBook) -> Void in
println(book.name)
}
a.down()