This deals with delegates and how they are used to...
# gradle
c
This deals with delegates and how they are used to grab Property File values in Gradle projects. I have seen it described very similarly before in an article that we can use a simple convention such as
Copy code
val pluginGroup: String by project
This will search for .property files for the key
pluginGroup
and return it's value as a
String
. I am impressed by that, but how the heck does this magic work? This will only return
String
values, so even if we have the following in the .properties file...
Copy code
platformDownloadSources = true
It will still only return
"true"
as a
String
. I am curious of how this mechanism works and why it is limited to only
String
and why it is limited to the specific name I have for the variable. Meaning I must name my variable the same as is in the .properties file.
This is something that I know works, but I just can't comprehend it. For background: To see this in usage, head over to GitHub: JetBrains/intellij-platform-plugin-template Here is gradle.properties and here is build.gradle.kts
I have been told that
Properties
are implemented as a
Map
: https://kotlinlang.org/docs/reference/delegated-properties.html#storing-properties-in-a-map Also, that ExtensionContainerExtensions.kt defines
getValue()
on
ExtensionContainer
from which
Project
is. I am trying to understand all of this (including the above), but this only seems to explain why
by project
is valid and doesn't address the other points
c
Thanks for the extra info, I have seen the 2nd link several time. In fact, the point I was looking at specifically was down further at https://docs.gradle.org/current/userguide/kotlin_dsl.html#kotdsl:properties While class and property delegates are still something I have to step back each time I look at them, I understand that Property Delegates work by overriding
getValue(...)
. Again, this is still a little fuzzy, but I can follow that to a degree. But where I cannot follow at all is when it comes to
by project
and I assume the respectful
by settings
and
by gradle
approach. I was trying to follow the code via the IDE, and the ExtensionContainerExtensions.kt file I was told to look at, but I don't see the connection.
I guess an end goal that I am trying to understand is being able to understand why it is limited to
String
/
String?
and why it is tied to the name of the property key.
I became interested when I found this bug in JetBrains' IntelliJ Platform Plugin Template at #29 JetBrains/intellij-platform-plugin-template Basically, I am trying to delve deeper than the basic docs to understand this more fundamentally
e
The link to the variable name is in the Kotlin language support for delegated properties. That's how they work
c
interesting. Thank you for pointing to this code. It is very helpful with part of my inquiry!
My uses cases have been mostly String and Boolean. And I guess not being able to get it to work on Boolean out of the box was why I thought that. Seems like the tests indicate
String
and
Int
are fully supported. While it does allow
Any
those all appear to expect failures (unless I am overlooking it). But
Boolean
is not supported at all??
build.gradle.kts
Copy code
val platformDownloadSources: Boolean by project
gradle.properties
Copy code
platformDownloadSources = true
This is something that is currently impossible
But also, there is a possibility for variable name conflicts as seen in issue #29 of the link above That means the name of my gradle.properties keys are highly linked to the code in build.gradle.kts.
pluginName
is already used by the
intellij {}
block for the IntelliJ Gradle Plugin. Is this a pure Kotlin issue, or can it be at least partially solved with the Gradle codebase?
e
To solve name clashes you should use direct APIs. Like
val someName = project.findProperty("name")
c
OK, that is great to know. This info is really helpful
I understand the current code doesn't allow anything like this, but is there anything in Kotlin that prevents Gradle from implementing something like (focus on the idea not syntax)...
Copy code
val name: String by project("pluginName")

// instead of 
val name = project.findProperty("pluginName")
The syntax is probably wrong, but the fundamental idea is to allow developers one generic way
by project
whether there is a name conflict or not. Rather than
by project
for one way and
project.findProperty(...)
for the other way. Basically, I am wondering can Gradle implement something like this (whether they will or won't isn't the question) or is this a limitation of Kotlin? Again, syntax is probably wrong
e
That looks perfectly doable yes
👍 1
c
You provided a lot of great info. I will look at the code more to see if I can understand that better as it is so interesting. Maybe another day I will continue the original conversation again. Thanks
@eskatos Hmmm, am I missing something fundamental? This is about the return types for
by project
. Just something I seem to have stumbled on ... while the mechanism should allow for any return type, as you have shown in the tests (including the missing Boolean), in practice it seems to only return the
String
type. It appears the tests never lose the passed in Kotlin type, where as, real world use cases of grabbing the values from .properties files will never return
Int
,
Boolean
, or any value type besides
String
. Basically, it seems to just assume the values are all
String
. I have been trying out the IntelliJ Platform Plugin Template (to make sure there aren't any other issues). Created a new .properties key-value with a value that should be converted to an
Int
.
Copy code
// gradle.properties
integer = 1

// build.gradle.kts
val integer: Any by project  // Using Int will cause an error

println("Integer: ${integer}\tType: ${integer.javaClass.name}")

// Result >> Integer: 1	Type: java.lang.String
I found a lot of the code you wrote that allows for retrieving of values from properties files via property delegation here ... https://github.com/gradle/gradle/commit/27e7819c2ddd11d38b06b33cb7c22bec8f509294 (Side Note: Where is the code that actually pulls the values from properties files? I assume there is more to it than the above commit. It seems like
import org.gradle.kotlin.dsl.support.getPropertyValue
is needed for understanding and is key here, but I can't seem to find it. )
e
Hi Christopher. Sorry for the confusion, I was wrong, properties are only read as
String
Kotlin delegated properties can't be used to parse them directly
Of you need some conversion you need to do it yourself
c
Got it. Yep, reading directly from .properties files will do that. Understand. But just one clarification with what you said before about my idea being doable... Is that still the case now that we know this? Or does this prevent that? https://kotlinlang.slack.com/archives/C19FD9681/p1602859068127600?thread_ts=1602852663.123600&cid=C19FD9681
e
Your API idea still sounds doable
👍 1