so, I had this <issue> because my class extending ...
# community-support
g
so, I had this issue because my class extending
ComponentMetadataRule
was capturing variables from the outer scope, now I switched the variables to (injected) constructor parameters in this way
Copy code
open class ConflictCapability(val group: String,
                              val artifact: String = group,
                              val modules: List<String>,
                              val reason: String? = null) {
    val ga get() = "$group:$artifact"
}
class ResolutionCapability(group: String, artifact: String = group, modules: List<String>, reason: String? = null) : ConflictCapability(group, artifact, modules, reason)
class ScijavaCapability @Inject constructor(val conflicts: List<ConflictCapability>) : ComponentMetadataRule {
    override
    fun execute(context: ComponentMetadataContext) = context.details.run {
        for (res in conflicts) {
            if (id.module.toString() in res.modules)
                allVariants {
                    withCapabilities {
                        // Declare that all of them provide the same capability
                        addCapability(res.group, res.artifact, id.version)
                    }
                }
        }
    }
}
dependencies {
    // Activate the "ScijavaCapability" rule
    components.all<ScijavaCapability> { params(resolutions + conflicts) }
}
but now I get > • Could not serialize value of type Build_gradle.ResolutionCapability How can I solve that?
@Serializable
on
ResolutionCapability
? I don't see that available, shall I bring in the whole kotlinx.serialization stuff via plugin?
to give additional background,
ConflictCapability
are supposed to fail the build,
ResolutionCapability
shall not, the last item in the
modules
list will be selected Maybe shall I switch
ConflictCapability
to a data class and add a boolean field
resolvable
in order to distinguish a plain conflict from a resolution? Example
a
shall I bring in the whole kotlinx.serialization stuff via plugin
Gradle uses some custom serialization (but sometimes uses Java Serialization), so it's not related to Kotlinx Serialization
how and where are the
resolutions
and
conflicts
values defined?
ScijavaCapability instances are created by Gradle (see managed types) so it should be
open
or
abstract
👍 1
g
top level in
build.gradle.kts
a
ahh I see yes, they're defined your linked example
g
yep
open
unfortunately didn't solve the issue (probably this is another one on top to that) > Could not isolate value [[Build_gradle$ResolutionCapability@42c9e774, Build_gradle$ResolutionCapability@4dec063, Build_gradle$ResolutionCapability@2b9603a0, Build_gradle$ResolutionCapability@78015032, Build_gradle$ConflictCapability@757efa01, Build_gradle$ConflictCapability@7d1f115, Build_gradle$ConflictCapability@1cc1794c, Build_gradle$ConflictCapability@6eb32a26, Build_gradle$ConflictCapability@6c9f7b03, Build_gradle$ConflictCapability@644e66dc, Build_gradle$ConflictCapability@73d27800, Build_gradle$ConflictCapability@4c79e46, Build_gradle$ConflictCapability@1397babe]] of type Object[] > > Could not serialize value of type Build_gradle.ResolutionCapability
switching
ConflictCapability
to
data class
or
open class
didn't solve neither
v
Make
ResolutionCapability
and
ConflictCapability
managed types?
g
you mean something like this?
v
yes
g
so, something like this, then?
Copy code
interface ConflictCapability_{

    @get:Input
    val group: Property<String>
    @get:Input
    val artifact: Property<String> //= group
    @get:Input
    val modules: Property<List<String>>
    @get:Input
    val reason: Property<String>//? = null)

    val ga get() = "$group:$artifact"
}
and how shall I create the
resolutions
and
conflicts
later on? I guess via
objects
, but I have no idea how
also, shall I implement the interface somehow in order to declare some conventional value for some properties? How this will play with
objects
?
Copy code
class A: ConflictCapability_ {
    init {
        artifact.convention(group)
    }
}
v
You can make it an abstract class instead of an interface if you really need to set conventional values from within the implementation, will still be a managed type.
And I don't think you need input annotations there
And
ListProperty<String>
And then you can for example do
Copy code
objects.newInstance<ConflictCapability_>().apply {
    group = "..."
    artifact = "..."
    modules.addAll("...", "...")
    reason = "..."
}
👍 1
g
ok, then something like this
Copy code
abstract class ConflictCapability_(val group: Property<String>,
                                   val artifact: Property<String> = objects.property<String>().convention(group),
                                   val modules: ListProperty<String>,
                                   val reason: Property<String> = objects.property<String>().convention(null)) {
    val ga get() = "$group:$artifact"
}
objects.newInstance<ConflictCapability_>().apply {
is gonna be verbose 😕
what about extending
ConflictCapability_
?
Copy code
abstract class ResolutionCapability @Inject constructor(group: Property<String>,
                                                        artifact: Property<String>,
                                                        modules: ListProperty<String>,
                                                        reason: Property<String>) : ConflictCapability(group, artifact, modules, reason)
v
ok, then something like this
```abstract class ConflictCapability_(val group: Property<String>,
val artifact: Property<String> = objects.property<String>().convention(group),
val modules: ListProperty<String>,
val reason: Property<String> = objects.property<String>().convention(null)) {
val ga get() = "$group:$artifact"
}```
More like
Copy code
abstract class ConflictCapability_ {
    abstract val group: Property<String>
    abstract val artifact: Property<String>
    abstract val modules: ListProperty<String>
    abstract val reason: Property<String>
    val ga get() = "$group:$artifact"

    init {
        artifact.convention(group)
    }
}
Also, setting
convention(null)
is useless unless you set a different convention before. With
null
it will simply be unset which also is the default.
g
ok, thanks, and is it possible to extends it?
v
Sure, why not
Copy code
abstract class ResolutionCapability: ConflictCapability_() {
    ...
}
I think should work just fine
g
so, I went with this for constructing multiple class of that
Copy code
abstract class ConflictCapability @Inject constructor(group: String, artifact: String = group, modules: List<String>, reason: String? = null) {
    abstract val group: Property<String>
    abstract val artifact: Property<String>
    abstract val modules: ListProperty<String>
    abstract val reason: Property<String>
    val ga get() = "$group:$artifact"

    init {
        this.group = group
        this.artifact = artifact
        this.modules = modules
        if (reason?.isNotEmpty() == true)
            this.reason = reason
    }
}

fun conflictOf(group: String, artifact: String = group, modules: List<String>, reason: String? = null) =
    objects.newInstance<ConflictCapability>(group, artifact, modules, reason ?: "")