Gradle + Kotlin why don't we assign variables directly - kotlin

In the build.gradle.kts there is the following code:
buildscript {
extra.apply {
set("kotestVersion", "4.6.1")
set("jdbi3Version", "3.21.0")
set("resilience4jVersion", "1.7.1")
}
}
val kotestVersion: String by extra
val jdbi3Version: String by extra
val resilience4jVersion: String? by extra
Why do we need to assign values in such an indirect way? Is there a reason we do not assign a value to a variable directly, such as
val kotestVersion: String = "4.6.1"

Assuming you mean why do you need to use the set method, that’s because these are Gradle Lazy Properties, and not primitive types like string or int. The Groovy syntax makes it possible for direct assignments, but Kotlin doesn’t. There’s an open ticket about it: https://github.com/gradle/gradle/issues/9268

Related

Kotlin - How to set values on ObjectNode?

I'm trying to create a Json object using Jackson but I can't use put because it's deprecated and will fail the pipelines checks in my company so I'm trying to use set:
fun HttpRequest.toJSONString(): String {
val mapper = ObjectMapper()
val root = mapper.createObjectNode()
val headers = mapper.createObjectNode()
this.headers().map().entries.forEach {h ->
headers.put(h.key, mapper.convertValue(h.value, JsonNode::class.java)) // its deprecated
}
root.set("headers", headers) // its failing
root.set("url_path", "https://facebook.com") // fails
return root.toString()
}
I got an error message: Not enough information to infer parameter T in operator fun <T : JsonNode!> set(p0: String!, p1: JsonNode!): T!
Please specify it explicitly.
How can I solve it?
I would advise you to try something more like that:
fun HttpRequest.toJSONString() =
ObjectMapper().writeValueAsString(
this.headers
.put("url_path", listOf("https://facebook.com"))
// put the rest here
)
It is usually inconvenient to deal directly with the Node objects and they are protected. I would strongly advise you to write your whole objects in kotlin and then use writeValueAsString from the ObjectMapper.
Use put when the value is a string (that version of the method is not deprecated). Use replace when the value is a JsonNode, or, if you want to chain the invocations together use set with a type parameter. Code to demonstrate:
val mapper = ObjectMapper()
val root = mapper.createObjectNode()
val headers = mapper.createObjectNode()
headers.put("key", "value") // Use put when the value is a primitive
root.replace("headers", headers) // Use replace for objects
root.set<JsonNode>("headers", headers) // Or use set with a type parameter
root.put("url_path", "https://facebook.com")
return root.toString()

Kotlin (Mutable)List

If you access a Java value of type List<[Some Type]> in Kotlin, you will get the type (Mutable)List<[Some Type]!>!.
e.g.:
Java code:
public class Example {
public static List<String> getList() {
return Arrays.asList("A", "B", "C");
}
}
Kotlin code:
val list = Example.getList()
// list is of type (Mutable)List<String!>!
Here is, how IntelliJ shows it:
However, if you want to make your own variable of this type like so:
val list2: (Mutable)List<String>
Then IntelliJ will correctly highlight the type but will give the error Unexpected Tokens.
What is this (Mutable)List?
There is no type (Mutable)List in Kotlin.
This serves as an indication that the type of list returned by Example.getList()
will not be decided at compile time but it will be decided at run time.
In your case it will be List and not MutableList because Arrays.asList() returns a FixedSizeList.
If you implemented Example.getList() like this:
public static List<String> getList() {
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
return list;
}
then at runtime the type of your list would be MutableList.
It's an IDEA tool tip which shows you that this list might be as MutableList, as List, as Example is Java class and it can return any of type list.
Also, the same happens to String: you don't know anything about list's String nullability, as it is returned from Java, so String looks like String! meaning 'maybe it's null, but or maybe not' without affecting compilation (i.e. you can as invoke methods on it without null-check, as checking it on null: no warnings will appear).
MutableList is a interfece in kotlin.
To declare a variable we need to use class like as
val list2: ArrayList<String>
#Josef Zoller

How to get the name of a variable in Kotlin?

I have a Kotlin class in my application with a lot of attributes, what I want to build is a method that stores the variable name in a dictionary. The dictionary looks like this:
HashMap<String, Pair<Any, Any>>()
The purpose of this is to store the changes made to a certain attribute, I store the name of the variable as the key and in the Pair I store the old value and the new value. To notify a change I use the Observer pattern. So whenever a setter is called from an attribute a change will be notified and stored to the dictionary.
The code below results in the folowing:
var person = Person("Harry", 44)
person.age = 45
HashMap("age", (44, 45))
Right now I am just hardcoding the variable name in as a String, so my question is:
How to dynamicly get the name of a variable in Kotlin?
I saw the same question in Java: Java Reflection: How to get the name of a variable?
Also some other questions about the same topic claiming it is not possible: Get the name property of a variable
I can understand that it is not possible to get the name of a variable, because the compiler simple doesn't have that information, but I am still currious to see if others have any sollution for this problem.
As stated in the Kotlin documentation about Reflection:
val x = 1
fun main() {
println(::x.get())
println(::x.name)
}
The expression ::x evaluates to a property object of type KProperty<Int>, which allows us to read its value using get() or retrieve the property name using the name property.
Use memberProperties to get the names of the class attributes and others properties. For instance:
YourClass::class.memberProperties.map {
println(it.name)
println(it.returnType)
}
I think delegate properties is the solution to my problem:
class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "$thisRef, thank you for delegating '${property.name}' to me!"
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("$value has been assigned to '${property.name}' in $thisRef.")
}
}
Credits go to: Roland
Source: https://kotlinlang.org/docs/reference/delegated-properties.html

Suppressing warnings about an unused Kotlin property in IDEA

Consider I have a parameterized TestNG test:
val parameters: Array<Array<Any>>
#DataProvider
get() {
val parameters = arrayListOf<Array<Any>>()
// ...
return parameters.toTypedArray()
}
#Test(dataProvider = "getParameters")
fun test(p1: Any, pN: Any) {
// ...
}
How do I stop IDEA from complaining that the data provider property (parameters in our case) is unused? Annotating the property with #get:SuppressWarnings("unused") is not helpful.
Add this on top of the declaration of the parameters property: #Suppress("unused")
You might need to re-compile the project to get IntelliJ to stop highlighting it as an unused property.
There turned out to be a workaround. Rewriting the annotation like this:
#get:DataProvider
val parameters: Array<Array<Any>>
makes IDEA treat the property as an entry point.
The corresponding ticket is KT-28031.

final or val function parameter or in Kotlin?

Why does Kotlin removed the final or val function parameter which is very useful in Java?
fun say(val msg: String = "Hello World") {
msg = "Hello To Me" // would give an error here since msg is val
//or final
...
...
...
}
Kotlin function parameters are final. There is no val or final keyword because that's the default (and can't be changed).
After Kotlin M5.1 support of mutable parameters removed, In earlier versions that can be achieve using
fun foo(var x: Int) {
x = 5
}
According to Kotlin developers, main reasons of removing this feature are below -
The main reason is that this was confusing: people tend to think that this means passing a parameter by reference, which we do not support (it is costly at runtime).
Another source of confusion is primary constructors: “val” or “var” in a constructor declaration means something different from the same thing if a function declarations (namely, it creates a property).
Also, we all know that mutating parameters is no good style, so writing “val” or “var” infront of a parameter in a function, catch block of for-loop is no longer allowed.
Summary - All parameter values are val now. You have to introduce separate variable for re-initialising. Example -
fun say(val msg: String) {
var tempMsg = msg
if(yourConditionSatisfy) {
tempMsg = "Hello To Me"
}
}
And another reason is that val and var differ by only one letter. This can be very confusing. So for function parameters they removed the option completely. Thus eliminating the confusion in this one small area (yet keeping it everywhere else--go figure).
This decision was made to avoid fragile base class problem. It happens when a small change in base classes (superclasses) makes subclasses malfunction.