Kotlin: Type inference failed. The value of the type parameter T should be mentioned in input types - kotlin

I'm new to Kotlin, for the piece of the below code:
fun a(stcd: String) {
val res = mutableSetOf<String>()
val aaa = mutableListOf<Map<String, Set<String>>>()
aaa.stream().filter { x: Map<String, Set<String>> -> x.isNotEmpty() }
.filter { x: Map<String, Set<String>> ->
x.values.contains(stcd) // throws error
}.forEach { x: Map<String, Set<String>> ->
x.forEach { (k: String, v: Set<String>?) ->
res.add(k)
}
}
}
Could anyone point out why contains throws error:Type inference failed. The value of the type parameter T should be mentioned in input types (argument types, receiver type or expected type). Try to specify it explicitly.?

This is because x.values is not a Set<String>, as you probably think it is. In fact, it's aCollection<Set<String>> as per the definition of values. So, such a collection can't contain a String type.

Related

Kotlin - output type from type parameter

I am parsing multiple CSV files and would like to provide my application with some generic parsers with logging capabilities. Is it possible to give some generic solution for it?
My try to do that is:
interface Converter<out T> {
fun convert(fieldName: String, value: String): T?
}
object DoubleMapper : Converter<Double> {
private val log = LoggerFactory.getLogger(this::class.java)
override fun convert(fieldName: String, value: String): Double {
log.info("Converting $fieldName: $value to Double")
return 123.3
}
}
object ConverterProvider {
private val log = LoggerFactory.getLogger(ConverterProvider::class.java)
inline fun <reified T : Any> getConverter(): (String, String) -> T {
return when (T::class) {
Double::class -> DoubleMapper::convert
Int::class -> IntMapper::convert
else -> {
throw java.lang.RuntimeException("We do not have mapper")
}
}
}
}
However, this does not compile, does kotlin provide such capabilities to have function return type depend on type parameter?
Your solution is almost correct one. The only problem is that the compiler is not smart enough to understand that you verified the type of T and you return the right type of the converter. You just need to cast the converter to T:
return when (T::class) {
...
} as (String, String) -> T
This cast is unchecked, meaning that the compiler can't guarantee at runtime that the cast is safe. However, as long as you return correct converter for the T, such cast should be safe and you can just suppress the warning:
#Suppress("UNCHECKED_CAST")
return when (T::class) {
...
} as (String, String) -> T

Kotlin - TypeReference<T> Cannot obtain Class<*> For Type Arguments

I've created a Kotlin equivalent of TypeReference<T> like so:
abstract class TypeReference<T> : Comparable<T> {
val type: Type get() = getGenericType()
val arguments: List<Type> get() = getTypeArguments()
final override fun compareTo(other: T): Int {
return 0
}
private fun getGenericType(): Type {
val superClass = javaClass.genericSuperclass
check(superClass !is Class<*>) {
"TypeReference constructed without actual type information."
}
return (superClass as ParameterizedType).actualTypeArguments[0]
}
private fun getTypeArguments(): List<Type> {
val type = getGenericType()
return if (type is ParameterizedType) {
type.actualTypeArguments.toList()
} else emptyList()
}
}
In order to obtain Class<*> of the generic type and its arguments, I've also created the following extension function (and this is where I believe the problem lies, since this is where the stack trace fails).
fun Type.toClass(): Class<*> = when (this) {
is ParameterizedType -> rawType.toClass()
is Class<*> -> this
else -> Class.forName(typeName)
}
I'm unit testing this like so:
#Test
fun `TypeReference should correctly identify the List of BigDecimal type`() {
// Arrange
val expected = List::class.java
val expectedParameter1 = BigDecimal::class.java
val typeReference = object : TypeReference<List<BigDecimal>>() {}
// Act
val actual = typeReference.type.toClass()
val actualParameter1 = typeReference.arguments[0].toClass()
// Assert
assertEquals(expected, actual)
assertEquals(expectedParameter1, actualParameter1)
}
The problem I think, lies in the extension function else -> Class.forName(typeName) as it throws:
java.lang.ClassNotFoundException: ? extends java.math.BigDecimal
Is there a better way to obtain the Class<*> of a Type, even when they're generic type parameters?
You need to add is WildcardType -> ... branch to your when-expression to handle types like ? extends java.math.BigDecimal (Kotlin equivalent is out java.math.BigDecimal), ?(Kotlin equivalent is *), ? super Integer(Kotlin equivalent is in java.math.Integer):
fun Type.toClass(): Class<*> = when (this) {
is ParameterizedType -> rawType.toClass()
is Class<*> -> this
is WildcardType -> upperBounds.singleOrNull()?.toClass() ?: Any::class.java
else -> Class.forName(typeName)
}
Note that in this implementation single upper bound types will be resolved as its upper bound, but all other wildcard types (including multiple upper bounds types) will be resolved as Class<Object>
https://github.com/pluses/ktypes
val typeReference = object : TypeReference<List<BigDecimal>>() {}
val superType = typeReference::class.createType().findSuperType(TypeReference::class)!!
println(superType.arguments.first())// List<java.math.BigDecimal>
println(superType.arguments.first().type?.arguments?.first())// java.math.BigDecimal

Map Key Values to Dataclass in Kotlin

how can I set properties of a dataclass by its name. For example, I have a raw HTTP GET response
propA=valueA
propB=valueB
and a data class in Kotlin
data class Test(var propA: String = "", var propB: String = ""){}
in my code i have an function that splits the response to a key value array
val test: Test = Test()
rawResp?.split('\n')?.forEach { item: String ->
run {
val keyValue = item.split('=')
TODO
}
}
In JavaScript I can do the following
response.split('\n').forEach(item => {
let keyValue = item.split('=');
this.test[keyValue[0]] = keyValue[1];
});
Is there a similar way in Kotlin?
You cannot readily do this in Kotlin the same way you would in JavaScript (unless you are prepared to handle reflection yourself), but there is a possibility of using a Kotlin feature called Delegated Properties (particularly, a use case Storing Properties in a Map of that feature).
Here is an example specific to code in your original question:
class Test(private val map: Map<String, String>) {
val propA: String by map
val propB: String by map
override fun toString() = "${javaClass.simpleName}(propA=$propA,propB=$propB)"
}
fun main() {
val rawResp: String? = """
propA=valueA
propB=valueB
""".trimIndent()
val props = rawResp?.split('\n')?.map { item ->
val (key, value) = item.split('=')
key to value
}?.toMap() ?: emptyMap()
val test = Test(props)
println("Property 'propA' of test is: ${test.propA}")
println("Or using toString: $test")
}
This outputs:
Property 'propA' of test is: valueA
Or using toString: Test(propA=valueA,propB=valueB)
Unfortunately, you cannot use data classes with property delegation the way you would expect, so you have to 'pay the price' and define the overridden methods (toString, equals, hashCode) on your own if you need them.
By the question, it was not clear for me if each line represents a Test instance or not. So
If not.
fun parse(rawResp: String): Test = rawResp.split("\n").flatMap { it.split("=") }.let { Test(it[0], it[1]) }
If yes.
fun parse(rawResp: String): List<Test> = rawResp.split("\n").map { it.split("=") }.map { Test(it[0], it[1]) }
For null safe alternative you can use nullableString.orEmpty()...

Receive transformation map function to send into `List<>.mapNotNull()`

Im trying to write a function like transform that receives a function that will be used inside of mapNotNull but I cant find a way to do it.
Example
val items: List<String?> = listOf(null, "cosa")
fun transform(transformer: (String) -> String?) {
items.mapNotNull(transformer) // <-------------------------------------- THIS DOES NOT COMPILE
}
fun main() {
val items: List<String?> = listOf(null, "cosa")
val transformer: (String) -> String? = {
null
}
val map = transform(transformer)
print(map)
}
You can check how this works here: play.kotlinlang
How can I declare the parameter of fun transform to be able to pass it inside of the mapNotNull ?
The mapNotNull function is defined as:
public inline fun <T, R : Any> Iterable<T>.mapNotNull(transform: (T) -> R?): List<R>
in other words, the type of the parameter to the transform lambda is T, where T is the type of the Iterable being operated on. In your case, your iterable is a List of type String?.
Therefore, you need to declare your transformer as type (String?) -> String?, and only the non-null results of that transform will be included in the result.
To update the code you supplied on play.kotlinlang, with a few additional modifications to make the type declarations a bit more idiomatic -- note, I've left the code mostly as-is, despite the odd use of the additional transform function:
val items = listOf<String?>(null, "cosa")
fun transform (transformer: (String?) -> String?): List<String> {
return items.mapNotNull(transformer)
}
fun main() {
val items = listOf<String?>(null, "cosa")
val transformer: (String?) -> String? = {
// this of course means the output of transform will always be empty
null
}
val map = transform(transformer)
print(map)
}
You have a list of nullable strings.
mapNotNull applies the transform function to an each element in a list and then checks if the result of this functions is null. So in this case, it passes a nullable string in the transformer function, and that function definitely cannot be of (String) -> String? type because the parameter here is a non-nullable string.
You should either declare the transformer function as (String?) -> String?, or remove nulls from list before calling mapNotNull:
items.filterNotNull().mapNotNull(transformer)
Another option is to wrap transformer into a lambda function before passing it to mapNotNull and handle null elements there, for example:
items.mapNotNull { e -> e?.let(transformer) }
this applies transformer function to an element only if it is not null.

in kotlin how to change to Array<CharSequence> from Array<String>

From one library module it returns some Array<Array<String>>, like below:
private val BASIC_ESCAPE_RULE = arrayOf(arrayOf("\"", """), // "
arrayOf("&", "&"),
arrayOf("<", "<"),
arrayOf(">", ">"))
fun getBasicEscapeRule(): Array<Array<String>> {
return BASIC_ESCAPE_RULE.clone()
}
In the project it has dependency on that library and it also uses another library module to do lookup/translation, which only takes Array<CharSequence>.
class translator (vararg lookup: Array<CharSequence>) {
... ...
fun translate(content: String) : String {}
}
When trying to call into a the second library's routing with the data getting from the first library,
the making of the translator translator(*getBasicEscapeRule()) got error:
Type mismatch: inferred type is Array<Array<String>> but Array<out Array<CharSequence>> was expected
In the second library it needs to use CharSequence for char manipulation.
How to convert the Array into Array?
To transform an Array<Array<String>> into an Array<Array<CharSequence>>, you can use the following code:
val src: Array<Array<String>> = TODO()
val result: Array<Array<CharSequence>> =
src.map { array -> array.map { s -> s as CharSequence }.toTypedArray() }.toTypedArray()