Where can artifact transforms be registered, and how do they become available to a project or an entire build?
answer
- registerTransform on DependencyHandler
- dependencies { registerTransform(...) }
- project-scoped, not global
- deliver via plugin / convention plugin
- shared Attribute defs (name+type equality)
basics
~20 sYou register transforms inside a project's dependencies { registerTransform(...) } block, usually from a plugin's apply. The registration is scoped to that project; to share, apply the plugin (or a convention/settings plugin) to every project that needs it.
solid answer
~40 s`registerTransform` lives on the `DependencyHandler`, so it is registered per project via `dependencies { registerTransform(MyTransform::class) { ... } }`. The most common pattern is to do this from within a plugin's `apply(project)` so any project applying the plugin gets the transform. Registration is **project-scoped** — a transform registered in project A is not visible to project B unless B also registers it. To make a transform available build-wide, apply the registering plugin to every subproject (e.g. via a convention plugin in `buildSrc`/an included build, or by iterating `allprojects`/`subprojects`). Because registration is declarative and cheap, applying it everywhere is fine; the transform still only runs when something actually requests its `to` attributes. The transform's `Attribute` instances must be consistent (same name and type) across projects so matching lines up.
code
kotlin · 10 lines// convention plugin applied to every module makes the transform build-wide
class TransformsConventionPlugin : Plugin<Project> {
override fun apply(project: Project) {
val artifactType = Attribute.of("artifactType", String::class.java)
project.dependencies.registerTransform(Unzip::class.java) {
it.from.attribute(artifactType, "jar")
it.to.attribute(artifactType, "classes")
}
}
}go deeper
Know it goes in dependencies { registerTransform(...) }, typically from a plugin.
Explain project-scoping and that plugins/convention plugins deliver the registration to many modules.
Discuss settings/convention-plugin strategies and the need for shared, equal Attribute definitions across modules.
Own a build-wide attribute schema and decide where transform registration lives so it's consistent and maintainable across the org.
## The registration surface `registerTransform` is a method on Gradle's `DependencyHandler`, which is why you call it inside the `dependencies { }` block: ```kotlin dependencies { registerTransform(Unzip::class) { from.attribute(artifactType, "jar") to.attribute(artifactType, "classes") } } ``` It can be called from a build script directly, but in real builds it almost always comes from a **plugin**: ```kotlin class UnzipPlugin : Plugin<Project> { override fun apply(project: Project) { project.dependencies.registerTransform(Unzip::class.java) { spec -> spec.from.attribute(artifactType, "jar") spec.to.attribute(artifactType, "classes") } } } ``` ## Scope: per-project Transforms are registered **per project**. A transform registered in `:app` is not automatically visible in `:lib`. If multiple projects need the same transform, each must register it — which is exactly why plugins are the delivery mechanism: apply the plugin to each project and the registration travels with it. To cover a whole multi-project build, common approaches are: - A **convention plugin** (in `buildSrc` or an included build) applied to every module. - A **settings plugin** that applies the convention plugin to all projects. - Iterating `subprojects { apply(plugin = ...) }` in the root build (older style, less preferred than convention plugins). ## Shared attribute definitions For matching to work across projects, the `Attribute<*>` objects must be **equal** — same name and same type. Two `Attribute.of("artifactType", String::class.java)` calls are equal because attribute equality is name+type. Define custom attributes in one shared place (often the plugin) so producers and consumers agree. ## Cost Registration is declarative and lazy, so registering a transform in many projects is cheap — it adds a rule, nothing runs until a resolution requests the target attributes. There is no harm in a project registering a transform it never ends up triggering.
- Is a transform registered in one subproject visible to its siblings?No. Registration is project-scoped. Each project that needs the transform must register it, which is why convention plugins applied to every module are the usual delivery mechanism.
- Why must Attribute definitions be shared across projects?Attribute equality is name+type. Producers and consumers must use equal Attribute instances for matching to line up, so define custom attributes once in a shared location.
saying these in an interview costs you the question
- Claiming registerTransform makes a transform globally visible across all projects automatically.
- Defining the same custom attribute with different types in different modules (breaks matching).
- Worrying about cost of registering in many projects — it's lazy and cheap.