Hey all, so i'm trying to create local plugin for ...
# community-support
m
Hey all, so i'm trying to create local plugin for some code generation, I'm using a NamedDomainObjectContainer:
Copy code
abstract class StringGeneratorSegment @Inject constructor(
    project: Project,
    objects: ObjectFactory
) {
    abstract val name: String

    val inputDirectory =
        objects.directoryProperty().convention(project.layout.projectDirectory.dir("src/${name}"))

    val outputDirectory =
        objects.directoryProperty().convention(project.layout.buildDirectory.dir("strings/${name}"))

    override fun toString(): String {
        return "StringGeneratorSegment(name=${name}, inputDirectory=${inputDirectory.get()}, outputDirectory=${outputDirectory.get()}"

    }
}

    val segments: NamedDomainObjectContainer<StringGeneratorSegment> =
        project.container(StringGeneratorSegment::class)
I'd like to use the "name" property in the convention for the input and output directories, but those seem to be "null" when the convention is set. Is there any good way to do something like this?
v
I'd say something like this should be fine:
Copy code
abstract class StringGeneratorSegment @Inject constructor(
    layout: ProjectLayout,
    providers: ProviderFactory
) : Named {
    abstract val inputDirectory: DirectoryProperty

    abstract val outputDirectory: DirectoryProperty

    init {
        inputDirectory.convention(layout.projectDirectory.dir(providers.provider { "src/${name}" }))
        outputDirectory.convention(layout.buildDirectory.dir(providers.provider { "strings/${name}" }))
    }

    override fun toString(): String {
        return "StringGeneratorSegment(name=${name}, inputDirectory=${inputDirectory.get()}, outputDirectory=${outputDirectory.get()}"

    }
}
m
Thanks @Vampire. I also discovered i can pass the name as a constructor parameter, and provide my own instance creator:
Copy code
val segments: NamedDomainObjectContainer<StringGeneratorSegment> =
        project.container(StringGeneratorSegment::class) { name ->
            objects.newInstance(StringGeneratorSegment::class.java, project, objects, name)
        }
I'm not sure which one is the more canonical approach though
Though i will say the approach you outlined above comes with some compiler warnings.
I actually ended up with a mix between the two:
Copy code
abstract class StringGeneratorSegment @Inject constructor(
    project: Project,
    objects: ObjectFactory,
    providers: ProviderFactory
): Named {
    val inputDirectory =
        objects.directoryProperty().convention(project.layout.projectDirectory.dir(providers.provider { "src/${name}" }))

    val outputDirectory =
        objects.directoryProperty().convention(project.layout.buildDirectory.dir(providers.provider { "strings/${name}" }))

    override fun toString(): String {
        return "StringGeneratorSegment(name=${name}, inputDirectory=${inputDirectory.get()}, outputDirectory=${outputDirectory.get()}"

    }
}
👌 1
v
The compiler warnings could actually be ignored, as in the case of the Gradle-generated implementations you know it is safe to be used like that (if you mean the "accessing overridable things from constructor" warnings). Additionally the idiomatic approach anyway is to no have opinion in domain objects, but add opinion from the plugin that provides those objects, then you would also not have the warnings. 🙂