https://kotlinlang.org logo
Channels
100daysofcode
100daysofkotlin
100daysofkotlin-2021
advent-of-code
aem
ai
alexa
algeria
algolialibraries
amsterdam
android
android-architecture
android-databinding
android-studio
androidgithubprojects
androidthings
androidx
androidx-xprocessing
anime
anko
announcements
apollo-kotlin
appintro
arabic
argentina
arkenv
arksemdevteam
armenia
arrow
arrow-contributors
arrow-meta
ass
atlanta
atm17
atrium
austin
australia
austria
awesome-kotlin
ballast
bangladesh
barcelona
bayarea
bazel
beepiz-libraries
belgium
benchmarks
berlin
big-data
books
boston
brazil
brikk
budapest
build
build-tools
bulgaria
bydgoszcz
cambodia
canada
carrat
carrat-dev
carrat-feed
chicago
chile
china
chucker
cincinnati-user-group
cli
clikt
cloudfoundry
cn
cobalt
code-coverage
codeforces
codemash-precompiler
codereview
codingame
codingconventions
coimbatore
collaborations
colombia
colorado
communities
competitive-programming
competitivecoding
compiler
compose
compose-android
compose-desktop
compose-hiring
compose-ios
compose-mp
compose-ui-showcase
compose-wear
compose-web
confetti
connect-audit-events
corda
cork
coroutines
couchbase
coursera
croatia
cryptography
cscenter-course-2016
cucumber-bdd
cyprus
czech
dagger
data2viz
databinding
datascience
dckotlin
debugging
decompose
decouple
denmark
deprecated
detekt
detekt-hint
dev-core
dfw
docs-revamped
dokka
domain-driven-design
doodle
dsl
dublin
dutch
eap
eclipse
ecuador
edinburgh
education
effective-kotlin
effectivekotlin
emacs
embedded-kotlin
estatik
event21-community-content
events
exposed
failgood
fb-internal-demo
feed
firebase
flow
fluid-libraries
forkhandles
forum
fosdem
fp-in-kotlin
framework-elide
freenode
french
fritz2
fuchsia
functional
funktionale
gamedev
ge-kotlin
general-advice
georgia
geospatial
german-lang
getting-started
github-workflows-kt
glance
godot-kotlin
google-io
gradle
graphic
graphkool
graphql
graphql-kotlin
graviton-browser
greece
grpc
gsoc
gui
hackathons
hacktoberfest
hamburg
hamkrest
helios
helsinki
hexagon
hibernate
hikari-cp
hire-me
hiring
hongkong
hoplite
http4k
hungary
hyderabad
image-processing
india
indonesia
inkremental
intellij
intellij-plugins
intellij-tricks
internships
introduce-yourself
io
ios
iran
israel
istanbulcoders
italian
jackson-kotlin
jadx
japanese
jasync-sql
java-to-kotlin-refactoring
javadevelopers
javafx
javalin
javascript
jdbi
jhipster-kotlin
jobsworldwide
jpa
jshdq
juul-libraries
jvm-ir-backend-feedback
jxadapter
k2-early-adopters
kaal
kafka
kakao
kalasim
kapt
karachi
karg
karlsruhe
kash_shell
kaskade
kbuild
kdbc
kgen-doc-tools
kgraphql
kinta
klaxon
klock
kloudformation
kmdc
kmm-español
kmongo
knbt
knote
koalaql
koans
kobalt
kobweb
kodein
kodex
kohesive
koin
koin-dev
komapper
kondor-json
kong
kontent
kontributors
korau
korean
korge
korim
korio
korlibs
korte
kotest
kotest-contributors
kotless
kotlick
kotlin-asia
kotlin-beam
kotlin-by-example
kotlin-csv
kotlin-data-storage
kotlin-foundation
kotlin-fuel
kotlin-in-action
kotlin-inject
kotlin-latam
kotlin-logging
kotlin-multiplatform-contest
kotlin-mumbai
kotlin-native
kotlin-pakistan
kotlin-plugin
kotlin-pune
kotlin-roadmap
kotlin-samples
kotlin-sap
kotlin-serbia
kotlin-spark
kotlin-szeged
kotlin-website
kotlinacademy
kotlinbot
kotlinconf
kotlindl
kotlinforbeginners
kotlingforbeginners
kotlinlondon
kotlinmad
kotlinprogrammers
kotlinsu
kotlintest
kotlintest-devs
kotlintlv
kotlinultimatechallenge
kotlinx-datetime
kotlinx-files
kotlinx-html
kotrix
kotson
kovenant
kprompt
kraph
krawler
kroto-plus
ksp
ktcc
ktfmt
ktlint
ktor
ktp
kubed
kug-leads
kug-torino
kvision
kweb
lambdaworld_cadiz
lanark
language-evolution
language-proposals
latvia
leakcanary
leedskotlinusergroup
lets-have-fun
libgdx
libkgd
library-development
lincheck
linkeddata
lithuania
london
losangeles
lottie
love
lychee
macedonia
machinelearningbawas
madrid
malaysia
mathematics
meetkotlin
memes
meta
metro-detroit
mexico
miami
micronaut
minnesota
minutest
mirror
mockk
moko
moldova
monsterpuzzle
montreal
moonbean
morocco
motionlayout
mpapt
mu
multiplatform
mumbai
munich
mvikotlin
mvrx
myndocs-oauth2-server
naming
navigation-architecture-component
nepal
new-mexico
new-zealand
newname
nigeria
nodejs
norway
npm-publish
nyc
oceania
ohio-kotlin-users
oldenburg
oolong
opensource
orbit-mvi
osgi
otpisani
package-search
pakistan
panamá
pattern-matching
pbandk
pdx
peru
philippines
phoenix
pinoy
pocketgitclient
polish
popkorn
portugal
practical-functional-programming
proguard
prozis-android-backup
pyhsikal
python
python-contributors
quasar
random
re
react
reaktive
realm
realworldkotlin
reductor
reduks
redux
redux-kotlin
refactoring-to-kotlin
reflect
refreshversions
reports
result
rethink
revolver
rhein-main
rocksdb
romania
room
rpi-pico
rsocket
russian
russian_feed
russian-kotlinasfirst
rx
rxjava
san-diego
science
scotland
scrcast
scrimage
script
scripting
seattle
serialization
server
sg-user-group
singapore
skia-wasm-interop-temp
skrape-it
slovak
snake
sofl-user-group
southafrica
spacemacs
spain
spanish
speaking
spek
spin
splitties
spotify-mobius
spring
spring-security
squarelibraries
stackoverflow
stacks
stayhungrystayfoolish
stdlib
stlouis
strife-discord-lib
strikt
students
stuttgart
sudan
swagger-gradle-codegen
swarm
sweden
swing
swiss-user-group
switzerland
talking-kotlin
tallinn
tampa
teamcity
tegal
tempe
tensorflow
terminal
test
testing
testtestest
texas
tgbotapi
thailand
tornadofx
touchlab-tools
training
tricity-kotlin-user-group
trójmiasto
truth
tunisia
turkey
turkiye
twitter-feed
uae
udacityindia
uk
ukrainian
uniflow
unkonf
uruguay
utah
uuid
vancouver
vankotlin
vertx
videos
vienna
vietnam
vim
vkug
vuejs
web-mpp
webassembly
webrtc
wimix_sentry
wwdc
zircon
Powered by
Title
j

jrgonzalez

01/12/2019, 10:37 PM
Hi, I am trying to migrate a Gradle Groovy DSL to Kotlin DSL and I am trying to declare dependencies in buildSrc in a way similar to this: https://proandroiddev.com/gradle-dependency-management-with-kotlin-94eed4df9a28). The problem is that I have some dependencies that are not just the simple artifact and version and need some extra configuration. On the Groovy DSL I used code like this:
dep = dependencies.create('com.squareup.retrofit2:converter-simplexml:' + constants.versions.retrofit) {
    // We need to exclude dependencies which are already provided by the Android platform
    exclude module: 'stax-api'
    exclude module: 'stax'
    exclude module: 'xpp3'
  }
But I can't figure out how to convert that to Kotlin DSL and I don't even have access to the "dependencies.create" method on the buildSrc object where I am declaring the dependencies. Is it possible to define a dependency with exclusions like that outside a DependencyHandler scope? Is there a standalone constructor / builder for dependencies that is not an extension method only available at specific places?
g

gildor

01/12/2019, 10:52 PM
In this case you have not just version, but config snippet also you need dependencies object to do that So possible way just extract it to extension function for dependencies and apply where you need this
But I believe you need this only if you use it multiple times in different modules, otherwise easier just define in it on place
j

jrgonzalez

01/12/2019, 10:56 PM
Yes, I want it for multi-module projects to declare dependencies with its configuration only once. The problem with the extension function would be that I can not declare it on a big Dependencies object and access it like:
Dependencies.retrofit2ConverterSimpleXML
as the ones that I have with no configuration. Also, don't know how to do the configuration like in Groovy.
g

gildor

01/12/2019, 10:57 PM
Problem that you need project instance to create dependency
So or it should be extension function, or retrofit2ConverterSimpleXML must be function, not a property
And you pass DependencyHandler or Project instance, you just cannot resolve it statically, you need instance of DependencyHandler to create dependency
j

jrgonzalez

01/12/2019, 10:58 PM
it does not seem to work if a declare it as
fun DependencyHandler.retrofit2ConverterSimpleXML()
inside the Dependencies object
g

gildor

01/12/2019, 10:59 PM
Why?
j

jrgonzalez

01/12/2019, 11:02 PM
If I try to autocomplete in a line like:
implementation(Dependencies.)
I don't get the function appearing at all
neither it works as
implementation(Dependencies.retrofit2ConverterSimpleXML())
or offers anything to import as
implementation(retrofit2ConverterSimpleXML())
g

gildor

01/12/2019, 11:06 PM
Maybe just some tooling problem, if you have function in buildSrc it must be available on you build.gradle
j

jrgonzalez

01/12/2019, 11:08 PM
yeah, after several tries now I got the last one
implementation(retrofit2ConverterSimpleXML())
to offer to import it as
import Dependencies.retrofit2ConverterSimpleXML
but that is not ideal either cause I lose autocompletion, so I have to look them up on the object manually and also to add imports, which the other dependencies do not need
Why is a project / DependencyHandler needed for creating a dependency when it is not used on creation?
shouldn't it just be a simple object / model?
g

gildor

01/12/2019, 11:10 PM
Apparently it used. create is method of DependencyHandler
You shouldn't import Dependencies, not sure what is exactly you problem. If your Dependencies object uses default package it just should work, same for any top level extension
j

jrgonzalez

01/12/2019, 11:12 PM
yeah, I saw that, but it may be just a convenience extension and it could be possible to create it in some other way that is not scoped to DependencyHandler, but I haven't found any doc about that
Also the config does not work easily, it expects a Closure<Any>
g

gildor

01/12/2019, 11:12 PM
If you have:
object Dependencies {
  fun retrofitSimpleXml(dep: DependencyHandler)
}
Than I don't see any problem
j

jrgonzalez

01/12/2019, 11:13 PM
maybe doing:
closureOf<ExternalModuleDependency> { }
? 😅
oh, so no extension function but a function receiving the dependency handler?
How that would be called?:
Dependencies.retrofitSimpleXml(this)
?
g

gildor

01/12/2019, 11:14 PM
Yes
Extension function is just an option, it's easier to use, but you right, it's not related anymore to your Dependencies object
Also the config does not work easily, it expects a Closure<Any>
Just create dependency, cast it to ExternalDependency and use apply to configure
j

jrgonzalez

01/12/2019, 11:19 PM
This seems to compile:
fun retrofit2ConverterSimpleXML(dependencyHandler: DependencyHandler): Dependency =
    dependencyHandler.create(
        "com.squareup.retrofit2:converter:-simplexml${Versions.retrofit}", closureOf<ExternalModuleDependency> {
      exclude(module = "stax-api")
      exclude(module = "stax")
      exclude(module = "xpp3")
    })
but not on usage 😅
does not accept this later:
implementation(Dependencies.retrofitConverterSimplexml(this))
` ^ Type mismatch: inferred type is Dependency? but Any was expected``
g

gildor

01/12/2019, 11:21 PM
Your dependency is nullable
Not sure why
Looks that your code explicitly defines it as non nullable
j

jrgonzalez

01/12/2019, 11:23 PM
also tried this based on what you said:
fun retrofit2ConverterSimpleXML(dependencyHandler: DependencyHandler): Dependency =
    (dependencyHandler.create(
        "com.squareup.retrofit2:converter:-simplexml${Versions.retrofit}"
    ) as ExternalDependency).apply {
      exclude(module = "stax-api")
      exclude(module = "stax")
      exclude(module = "xpp3")
    }
g

gildor

01/12/2019, 11:23 PM
It's the same
j

jrgonzalez

01/12/2019, 11:23 PM
it also compiles that part, but fails with same error on implementation reference
g

gildor

01/12/2019, 11:23 PM
Check why dependency is nullable
It just doesn't allow to pass nullable
But I don't see the reason
Just for test add !! To usage
j

jrgonzalez

01/12/2019, 11:24 PM
it seems not that, but that implementation expects either any or 2 parameters one of which is a Dependency?
so it is going to
fun DependencyHandler.`implementation`(dependencyNotation: Any): Dependency?
instead of:
fun <T : ModuleDependency> DependencyHandler.`implementation`(
    dependency: T,
    dependencyConfiguration: T.() -> Unit
): T
g

gildor

01/12/2019, 11:25 PM
Ah, I see
Yeah, type safe accessor generated oy for string
You have to use
add("implementation", dependency)
Maybe you can solve this in another way and just globally exclude those dependencies for all modules instead attaching this to your dependency definition
j

jrgonzalez

01/12/2019, 11:27 PM
same complain 😅
g

gildor

01/12/2019, 11:28 PM
Sorry, I confused
Where is type mismatch?
j

jrgonzalez

01/12/2019, 11:29 PM
that one also expects a Any
not a Dependency
g

gildor

01/12/2019, 11:30 PM
Any is super type of Dependency
So it's fine
Your problem with nullability
Not with class
j

jrgonzalez

01/12/2019, 11:30 PM
I don't know how to get it to use this one:
fun <T : ModuleDependency> DependencyHandler.`implementation`(
    dependency: T,
    dependencyConfiguration: T.() -> Unit
): T
seem that is the one that allows to pass a Dependency as the created one
g

gildor

01/12/2019, 11:31 PM
Pass empty lambda
j

jrgonzalez

01/12/2019, 11:31 PM
but since it expects a second parameter
g

gildor

01/12/2019, 11:31 PM
Second param just an empty lambda
implementation(dependency, {})
j

jrgonzalez

01/12/2019, 11:32 PM
like this?:
implementation(Dependencies.retrofitConverterSimplexml(this), {})
also tried, but it then gives this different error:
implementation(Dependencies.retrofitConverterSimplexml(this), {})
              ^ None of the following functions can be called with the arguments supplied: 
                  public fun <T : Dependency> DependencyHandler.implementation(dependency: TypeVariable(T), action: Action<TypeVariable(T)>): TypeVariable(T) defined in org.gradle.kotlin.dsl
                  public fun DependencyHandler.implementation(group: String, name: String, version: String? = ..., configuration: String? = ..., classifier: String? = ..., ext: String? = ..., dependencyConfiguration: Action<ExternalModuleDependency>? = ...): ExternalModuleDependency defined in org.gradle.kotlin.dsl
                  public fun DependencyHandler.implementation(dependencyNotation: String, dependencyConfiguration: Action<ExternalModuleDependency>): ExternalModuleDependency defined in org.gradle.kotlin.dsl
g

gildor

01/12/2019, 11:35 PM
I'm away from my PC and IDE, just check types that possible to pass to type safe accessors and to dynamic add setters, one of them should allow pass Dependency
Probably your method should return ExternalDependency, not sure
j

jrgonzalez

01/12/2019, 11:36 PM
ok, thanks!, it has been really helpful, at least looks there is some path this way 🙂. I will keep tinkering..
g

gildor

01/12/2019, 11:36 PM
Ahh, correct, I see it now in generic, function that you showed above, only for module dependencies, not for external dependency
I still think that global configuration resolution is just better solution
j

jrgonzalez

01/12/2019, 11:36 PM
but the odd thing is that with Groovy it works
g

gildor

01/12/2019, 11:37 PM
Exclude those dependencies from all modules in allproject block
This also will work
j

jrgonzalez

01/12/2019, 11:37 PM
I mean, I can pass a dependency created with the create() method to implementation() and it just takes it
g

gildor

01/12/2019, 11:37 PM
Because groovy dynamic, try to use
add()
, it probably also will work
It should have compatible overload for this case
But usage of not type safe
add
Imo just destroying all the idea of type safe dependency definition
So global configuration resolution strategy imo the best, keeps your dependency definition and usage simple and obvious
Also solves problem of transitive dependencies which also can bring excluded dependencies
j

jrgonzalez

01/12/2019, 11:41 PM
yes, it kinda also feels like if somehow the Groovy variant of implementation method allowing what I did before is not accesible through the Kotlin DSL
there are some calls of add with an ExternalModuleDependency but it requires like 3 parameters 😅
oh, not even that, is not an ExternalModuleDependency but its configuration
so I guess, yes, I should go the global route
this also seems to work:
implementation(Dependencies.retrofitConverterSimplexml) {
    exclude(module = "stax-api")
    exclude(module = "stax")
    exclude(module = "xpp3")
  }
which would mean basic unconfigured dependency declaration and duplicated config block per usage
g

gildor

01/12/2019, 11:53 PM
add("implementation", ...) is the same as "implementation"(...), But in both cases you lose type safety
j

jrgonzalez

01/12/2019, 11:56 PM
yes, deleted cause I think it was wrong, was trying to trick it to use the groovy version of implementation that supports a dependency as single parameter 😅
it seems to accept several things, but I can not fully compile the project yet to be sure they are valid and doing what I intend. This compiles too:
withGroovyBuilder {   "implementation(${Dependencies.retrofit2ConverterSimpleXML(this@dependencies)})"
  }
but I am only guessing there and it is type unsafe as soon as you add groovy in
The global exclude is also a bit tricky, may work for this one, but on others I am excluding for different reasons, not all versions of a module but only those coming transitively on a specific dependency due to conflicts. The duplicated config section may be better for now to not have several different ways to do the same
Also, luckily I don't have many that need configuration
and it even seems some of those issues are fixed since last time I checked, so maybe I can remove a few more customizations
Thanks for all your help, 1am here, time to sleep 😄
g

gildor

01/13/2019, 1:19 AM
You don't need groovy builder for this, I will check later today
I agree, global exclude may be not so straight forward, but usually it's more stable and clean solution. To solve version conflict you also can use global configuration resolution, I would still take a look on this solution
j

jrgonzalez

01/13/2019, 9:36 AM
Also, there is another type of configuration I have on some dependencies, that require
isTransitive = true
which I am not sure if it has a global way.
g

gildor

01/13/2019, 9:59 AM
Why is your use case for isTransitive = true? This is default behavior of any dependency
j

jrgonzalez

01/13/2019, 10:30 AM
It fails without it on an old Twitter dependency I have not had time to remove since they discontinued it. I will post when I'm back at home in a bit, I have no idea why it fails without the
isTransitive
either.
I have also seen instructions for several libs that say to include it like that so there may be some differences. Others like glide had it and then seemingly removed the requirement but I'm not sure what changed.
g

gildor

01/13/2019, 10:38 AM
Could you show this dependency?
j

jrgonzalez

01/13/2019, 11:06 AM
This is it on "normal" syntax:
implementation("com.twitter.sdk.android:tweet-composer:3.3.0@aar") {
    isTransitive = true
  }
without the isTransitive my build fails with unknown
com.twitter.sdk.android.core
package
g

gildor

01/13/2019, 11:17 AM
Just remove
<@U27HSU2U9>
and isTransitive
Those guys from Twitter don't know how to use dependencies probably. Because explicit declaration of resources extension obviously disables transitive dependencies (because you cannot get transitive dependencies without pom file)
👌 1
j

jrgonzalez

01/13/2019, 11:40 AM
Oh, ok, so maybe the others I have with
@aar
also should get rid of it. I thought it was something to distinguish aar vs jar or something like that.
seems to compile now with just
implementation(Dependencies.twitterSdkTweetComposer)
🎉
g

gildor

01/14/2019, 5:49 AM
👍
Really not sure how they decided to use such config, maybe some super old legacy when they don't have pom, only raw aar. Funny, that Crashlytics used the same strange config in their docs when they owned by Twitter, now Google acquired them and this thing moved also to Firebase docs for Crashlytics 😬