I must be misunderstanding something about the com...
# plugin-development
s
I must be misunderstanding something about the combo of
Property#convention
and
Property#map
... (I think I may have a general misunderstanding of convention and atempting to access its value). I have this:
Copy code
hibernateVersionProperty = project.getObjects().property( String.class );
hibernateVersionProperty.convention( "N/A" );

...

project.getDependencies().add(
        "implementation",
        ormDsl.getHibernateVersionProperty().map( (ormVersion) -> Character.isDigit( ormVersion.charAt( 0 ) )
                ? "org.hibernate.orm:hibernate-core:" + ormVersion
                : null
        )
);
But this continually gives me a complaint when the build does not explicitly set this hibernate-version :
Copy code
Caused by: org.gradle.api.internal.provider.MissingValueException: Cannot query the value of this provider because it has no value available.
Isn't the whole point of convention to define a value to be used if one is not set?
c
It may be that
add()
is eagerly evaluating that provider. See if
addLater
works.
s
I don't see addLater. There is addProvider, but that gave me the same
Copy code
project.getDependencies().addProvider(
				"implementation",
				ormDsl.getHibernateVersionProperty().map( (ormVersion) -> Character.isDigit( ormVersion.charAt( 0 ) )
						? "org.hibernate.orm:hibernate-core:" + ormVersion
						: null
				)
		);
maybe because I return the null? I saw that onine, but maybe that just does not work...
Really I'd prefer to invert that, bu not sure how to in a deferred fashion
c
addLater
is on the configuration:
Copy code
implenentation.dependencies.addLater
…unsure how that relates to addProvider. Yea, have seen the
null
as well
s
Ahhh... ok, i'll try that
hm not there either according to IJ
You mean this right?
project.getConfigurations().getByName( "implementation" ).addLater()
c
odd. using it:
Copy code
// lazy initialize dependencies from packaging extension
        packagingScripts.dependencies.addLater(packaging.packagingScript.map { dependencies.create("${it}@zip") })
Try with a `.get()`:
Copy code
project.getConfigurations().getByName( "implementation" ).get().addLater()
s
getByName returns a Configuration though, not a Provider
it does not understand get
maybe something Groovy specific?
missingMethod magic?
c
ah yea it’s
named
that has a provider. ok, that looks like it should work. addLater is documented on DomainObjectCollection as being there since 4.8. Not seeing any kotlin magic in there. This is the full context:
Copy code
val packagingScripts: Configuration by configurations.creating

        // lazy initialize dependencies from packaging extension
        packagingScripts.dependencies.addLater(packaging.packagingScript.map { dependencies.create("${it}@zip") })
ah - need to reference dependencies:
Copy code
project.getConfigurations().getByName( "implementation" ).dependencies.addLater()
s
ahh
ok, i'll try tat
Copy code
project.getConfigurations().getByName( "implementation" ).getDependencies().addLater(
				ormDsl.getHibernateVersionProperty().map( (ormVersion) -> Character.isDigit( ormVersion.charAt( 0 ) )
						? project.getDependencies().create( "org.hibernate.orm:hibernate-core:" + ormVersion )
						: null
				)
		);
Same 😞
c
huh. seeing the same thing:
Copy code
val prop = objects.property<String>()
prop.convention("N/A")

// this fails with expected error: Supplied String module notation 'N/A' is invalid. Example notations: 'org.gradle:gradle-core:2.2', 'org.mockito:mockito-core:1.9.5:javadoc'.
// dependencies.addProvider("implementation", prop.map { it })

// this fails with: Cannot query the value of this provider because it has no value available.
dependencies.addProvider("implementation", prop.map { null })
Has seen somewhere using
null
to indicate a no-op.
i think the convention part is working - that is passed into the map closure, which then returns
null
for
N/A
input. It that null on the derived provider that is problematic…
s
Perhaps. Like I said, I would much prefer to invert tht, but afaik that is not possible
c
is the goal to not add the dependency if no version (or an invalid version) is specified?
this reference shows conditionally adding deps. perhaps what you’ve already seen.
s
the plugin is published along with the rest of Hibernate. we generally expect (and only really support) the same versions be used for performing the bytecode enhancement and consuming the enhanced classes
cross version bytecode enhancement suport gets to be way too tricky for what I want to do 😉
yeah i try to avoid afterEval
ah, should have scrolled down 😉
c
yea, definitely not that. this:
Copy code
implementation micronautExtension.runtime.map { r ->
        switch(r) {
            case 'netty':                                                   (1)
                return "io.netty:netty-buffer:4.1.75.Final"
            case 'tomcat':
                return "org.apache.tomcat.embed:tomcat-embed-core:10.0.18"  (2)
            default:
                return null                                                 (3)
        }
    }
…but it doesn’t seem to work, trying it now.
s
but no, this is not the one i saw. i'll read through it. thanks!
he uses the Groovy DSL to accomplish this. i wonder if that comes in to play here
c
perhaps. not having any luck with Kotlin DSL, though it should be equivalent in this case:
Copy code
dependencies {

    // fails with: Cannot query the value of this provider because it has no value available.
    implementation( prop.map {
        null
    })
}
s
not quite as user friendly, but maybe i'll just drop this for now and focre the user to add the dependency manuallyand keep the versions in sync
btw, is there any real different between
#set
and `#value`here?
(not totally related, but...)
c
no. from what I’ve seen, #value was added more recently to help clarify setting the value vs setting a provider.
s
but they both have the same overloads
anyway, just a curiosity
c
yea. looks like the only diff is that
value
allows chaining. I’ve used extension functions to provide this for clarity: prop.value = something // assignment of a value prop.from(otherProp) // from a provider of some sort
s
ah, you're right they do define diff return types
having developed chaining apis... hate them 😆
they get super fugly to implement when you introduce inheritance
Actually I guess that was the resource was the one I saw since I left a reply 😄
c
couldn’t get a single dependency to be conditionally added via
null
- but you can use
addAllLater
to add a list of deps (empty list for no deps).
Copy code
configurations.implementation.get().dependencies.addAllLater(prop.map {
    if( it == "N/Addd") { listOf(dependencies.create("io.foo:default-dep:1.2.3")) }
    else { emptyList() }
})
s
Thanks @Chris Lee I think I am going to drop this though and either : 1. drop this setting and force the user to add the dependency 2. never use null and always use the version of the plugin or an explicitly set version
👍 1
@Chris Lee out of (yes even more) curiosity, what contributes
#listOf
here?
Also, how about
#emptyList
? Gradle seems to expect certain List impls.
Collections#emptyList
/
Collections#singletonLit
e.g. give me
Copy code
> class org.gradle.api.internal.provider.TransformBackedProvider cannot be cast to class org.gradle.api.internal.provider.CollectionProviderInternal (org.gradle.api.internal.provider.TransformBackedProvider and org.gradle.api.internal.provider.CollectionProviderInternal are in unnamed module of loader org.gradle.internal.classloader.VisitableURLClassLoader @29e235a1)
c
ah. listOf() is Kotlin syntax. iirc for Groovy it would be a list literal
["a", "b"]
. emptyList() is also Kotlin, would be
[]
iirc.
s
i use Java
c
ah. odd that Collections.emptyList() doesn’t work. all it wants is something that is
Iterable
.
s
so it says 😉
anyway, no worries
c
that cast exception looks like perhaps map() isn’t returning a Provider<Iterable> but a Provider<Something> that ends up going into addAllLater.
s
Ah, yes, ofc. silly mistake. It is returning
Provider<List<?>>
. It does not know because of the emptyList
c
ah yea. generics….
s
I'm surprised though
Anyway, I'll cast and see if that helps
c
s/b able to do
Collections.<String>emptyList()
for get the right type.
s
Dependency, but yeah
thats a cast to me
c
that’s valid Java syntax
s
yep
actually, if i set a var you don't even need that
c
nice
s
since emptyList is generic
anyway, still fails. it is for sure the map call and attempting to use that here
c
let me check, had some challenges with that before…
hmmm. this (Kotlin) syntax works:
Copy code
configurations.implementation.get().dependencies.addAllLater(prop.map {
    if( it == "N/Addd") { listOf(dependencies.create("io.foo:default-dep:1.2.3")) }
    else { emptyList() }
})
s
🤷🏼 not the first time i'd have seen diffs in groovy v java v kotlin
c
what does your code calling map() look like?
s
this is just one of those cases where Gradle is not going to make sense 😄 I'm back to this working now -
Copy code
project.getDependencies().add(
				"implementation",
				ormDsl.getUseSameVersion().map( (use) -> use
						? "org.hibernate.orm:hibernate-core:" + HibernateVersion.version
						: null
				)
		);
as for the code... its just a plugin
I'm going to push soon, i cann link it after
c
that… works? wasn’t able to get a provider that returns null to work.
s
yep, it worked fine now
c
even when it hits the false path and returns null?
s
i did change the setup a bit
maybe that was part of it
i now have a
Property<Boolean
just indicating whether the users wants tis
so ether i'll inject this, or they can set up the dep manually in their build
Can't imagine why
Property<String>
v.
Property<Boolean>
would make any difference though
But like I said, I think I am missing some nuance to convention
c
huh. still not getting that work, looks like the Provider layer doesn’t accept null return values.
Copy code
val prop = objects.property<Boolean>()
prop.convention(false)

// fails with: Cannot query the value of this provider because it has no value available.
dependencies.add("implementation", prop.map { null })
…at least in this repro (Kotlin DSL, Gradle 7.4.2).
s
yeah, don't know. it works here now
but then it did not before
so...
anyway, thanks a ton for the help
c
no worries