Skip to content

Broken equals() contract for LifecycleAwareProject #30272

@jhonnen

Description

@jhonnen

Current Behavior

The equals contract of Project::equals is broken when comparing against a LifecycleAwareProject: LifecycleAwareProject is equal to its corresponding DefaultProject but not the other way around.

Expected Behavior

equals() must be symmetric

Context (optional)

We have a plugin applied on the root project with an extension that maintains a Set<Project>.
A plugin applied on subprojects checks if the target project is contained in that set.

As of Gradle 8.10, the set now contains LifecycleAwareProjects and a contains(defaultProject) check always fails.

Also identity equality is not reliably anymore because of LifecycleAwareProject (e.g. in Java code: project.getParent() == project.getRootProject()). This changed behavior is understandable but might be good to document it in the release notes.

Steps to Reproduce

/build.gradle.kts

project.ext["subproject"] = subprojects.toList()[0]

/subproject/build.gradle.kts

val lifecycleAware = rootProject.ext["subproject"]!!
println("$lifecycleAware (${lifecycleAware.javaClass}")
println("$project (${project.javaClass}")

println(lifecycleAware == project)
println(project == lifecycleAware)

This prints

> Configure project :subproject
project ':subproject' (class org.gradle.api.internal.project.LifecycleAwareProject_Decorated
project ':subproject' (class org.gradle.api.internal.project.DefaultProject_Decorated
true
false

Gradle version

8.10

Build scan URL (optional)

No response

Your Environment (optional)

No response

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions