This message was deleted.
# community-support
s
This message was deleted.
v
No, there is no way, except if you control both plugins.
c
where the extension property type is a NamedDomainObjectContainer, one can use `whenObjectAdded`to register a callback.
👍 1
depending on the use case, creating a derived provider can be of use: PluginA.extension.property.map { // do what is needed here, to be executed when this provider is resolved }
z
@Vampire yep I control both plugins!
v
Then don't have a property in extension
A
but have a method that does the configuration and that can then inform interested other parties like plugin B or similar.
👍 1
z
@Chris Lee I can't use a provider/property bc they don't allow notification when the property is set - it still needs to be pulled
c
fair enough, though for a set of use cases it may be possible to avoid the notification and create a derived provider that pulls in values at resolution time.
z
Yep, @Vampire my question is just about what type to use, instead of manually managing callbacks
v
You probably have to do it manually. You can have internally `Property`s that you set from the method call and expose them as `Provider`s so that they can be wired to other properties easily.
z
I need to execute the callbacks before
afterEvaluate
but after the property is set. The property is set once during evaluation, so I need to execute the registered callback immediately once it's set
c
something like
Copy code
fun propertyA(value : String) {
  propertyA.set(value)
  callbacks.forEach {
    it.execute(value)
  }
}
👍 1
z
FTR I went with this solution:
Copy code
abstract class ModuleConfigPluginExtension @Inject constructor(
    project: Project,
    objects: ObjectFactory
) {
    private val projectPath = project.path
    private var module: Module? = null

    private val moduleCollection: DomainObjectCollection<Module> = objects.domainObjectSet(Module::class.java)

    fun setModule(module: Module) {
        if (this.module != null && this.module != module) {
            error("`${projectPath}`: Module has already been set with a different value. Module can only be set once")
        }

        if (this.module == null) {
            this.module = module
            moduleCollection.add(module)
        }
    }

    fun whenAdded(block: Module.() -> Unit) {
        moduleCollection.configureEach {
            block(this)
        }
    }
}
then plugins can use this extension function:
Copy code
fun Project.whenModuleConfigAdded(action: Module.() -> Unit) {
    the<ModuleConfigPluginExtension>().whenAdded(action)
}
c
neat!
z
I think there’s a gap in the gradle APIs because when I line up code with
afterEvaluate { }
- I actually don’t about all evaluation - just evaluation of a specific plugin/extension
c
that’s the premise for the Property/Provider API - allowing them to be resolved as-needed, at execution time, sidestepping the race-condition of afterEvaluate (ordering of listeners, etc). Of course, that presumes that all APIs are using Property/Provider, and a few other gaps.
👍 1
z
yeah. Unfortunately cannot use
Property/Provider
to react to value changes at configuration time
c
you often don’t actually need to do that - chaining providers together and creating derived providers satisfies a swatch of use cases. your use case (a list/set of elements to respond to) isn’t handled by the Property/Provider API, though Gradle does still offer an option.
for example, the below allows propertyY to be chained to propertyX - whenever (at execution time) propertyY is resolved it will use the current value for propertyX.
Copy code
extensionB.propertyY.set(extensionA.propertyX)
…or creating derived providers:
Copy code
extensionB.propertyY.set(extensionA.propertyX.map {
  
  // do some lazy-evaluated stuff here based on propertyX's value
  // invoked when propertyY resolved

})