Classpath Container update on synchronization

Hello everyone,

at our company, we successfully migrated to the new Buildship 2.0 plugin and we are very happy with it.

But we have the effect, that on each synchronization (“Refresh Gradle Project”) an incremental build is triggered. After debugging, I found out that these builds are caused by project description modifications.

These project description modifications are caused by the GradleClasspathContainerUpdater#updateFromModel() method, which sets the Gradle classpath container on each synchronization, although there are no changes. Eclipse automatically touch the project on which the classpath container is applied.

Is it necessary to set the classpath container again, although there are no changes?

I print out the stacktrace, when the touch happen:

Stacktrace

java.lang.Exception
at org.eclipse.core.internal.resources.Project.touch(Project.java:1297)
at org.eclipse.jdt.internal.core.SetContainerOperation.executeOperation(SetContainerOperation.java:115)
at org.eclipse.jdt.internal.core.JavaModelOperation.run(JavaModelOperation.java:724)
at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:2240)
at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:2267)
at org.eclipse.jdt.internal.core.JavaModelOperation.runOperation(JavaModelOperation.java:795)
at org.eclipse.jdt.core.JavaCore.setClasspathContainer(JavaCore.java:5591)
at org.eclipse.buildship.core.workspace.internal.GradleClasspathContainerUpdater.setClasspathContainer(GradleClasspathContainerUpdater.java:161)
at org.eclipse.buildship.core.workspace.internal.GradleClasspathContainerUpdater.updateClasspathContainer(GradleClasspathContainerUpdater.java:75)
at org.eclipse.buildship.core.workspace.internal.GradleClasspathContainerUpdater.updateFromModel(GradleClasspathContainerUpdater.java:127)
at org.eclipse.buildship.core.workspace.internal.SynchronizeGradleBuildOperation.synchronizeJavaProjectInTransaction(SynchronizeGradleBuildOperation.java:237)
at org.eclipse.buildship.core.workspace.internal.SynchronizeGradleBuildOperation.access$200(SynchronizeGradleBuildOperation.java:106)
at org.eclipse.buildship.core.workspace.internal.SynchronizeGradleBuildOperation$4.run(SynchronizeGradleBuildOperation.java:223)
at org.eclipse.jdt.internal.core.BatchOperation.executeOperation(BatchOperation.java:39)
at org.eclipse.jdt.internal.core.JavaModelOperation.run(JavaModelOperation.java:724)
at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:2240)
at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:2267)
at org.eclipse.jdt.core.JavaCore.run(JavaCore.java:5521)
at org.eclipse.jdt.core.JavaCore.run(JavaCore.java:5478)
at org.eclipse.buildship.core.workspace.internal.SynchronizeGradleBuildOperation.synchronizeJavaProject(SynchronizeGradleBuildOperation.java:219)
at org.eclipse.buildship.core.workspace.internal.SynchronizeGradleBuildOperation.synchronizeOpenWorkspaceProject(SynchronizeGradleBuildOperation.java:214)
at org.eclipse.buildship.core.workspace.internal.SynchronizeGradleBuildOperation.synchronizeWorkspaceProject(SynchronizeGradleBuildOperation.java:189)
at org.eclipse.buildship.core.workspace.internal.SynchronizeGradleBuildOperation.synchronizeGradleProjectWithWorkspaceProject(SynchronizeGradleBuildOperation.java:179)
at org.eclipse.buildship.core.workspace.internal.SynchronizeGradleBuildOperation.access$000(SynchronizeGradleBuildOperation.java:106)
at org.eclipse.buildship.core.workspace.internal.SynchronizeGradleBuildOperation$1.run(SynchronizeGradleBuildOperation.java:141)
at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:2240)
at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:2262)
at org.eclipse.buildship.core.workspace.internal.SynchronizeGradleBuildOperation.synchronizeProjectsWithWorkspace(SynchronizeGradleBuildOperation.java:138)
at org.eclipse.buildship.core.workspace.internal.SynchronizeGradleBuildOperation.run(SynchronizeGradleBuildOperation.java:122)
at org.eclipse.buildship.core.workspace.internal.SynchronizeGradleBuildsJob.synchronizeBuild(SynchronizeGradleBuildsJob.java:77)
at org.eclipse.buildship.core.workspace.internal.SynchronizeGradleBuildsJob.runToolingApiJob(SynchronizeGradleBuildsJob.java:68)
at org.eclipse.buildship.core.util.progress.ToolingApiJob$1.run(ToolingApiJob.java:73)
at org.eclipse.buildship.core.util.progress.ToolingApiInvoker.invoke(ToolingApiInvoker.java:62)
at org.eclipse.buildship.core.util.progress.ToolingApiJob.run(ToolingApiJob.java:70)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:55)

Not strictly, but making a deep comparison is expensive and adds more complexity to the code. JDT detects that nothing has changed and shouldn’t recompile anything. That’s why we didn’t consider this a problem so far.

Is this a performance problem for your project? If yes, could you elaborate what is taking long on the incremental build?

Eclipse internal compares the old classpath container with the new one via equals (see org.eclipse.jdt.internal.core.SetContainerOperation.executeOperation() line 84 in Eclipse Neon).

Therefore the org.eclipse.buildship.core.workspace.internal.DefaultGradleClasspathContainer must override the equals-method, mustn’t it?

Our project has about 300 sub-project and the pain is that the resource delta is calculated on each project and builder when the incremental build is running. Actually, no builder is creating something. So the incremental build is unnecessary and wast 1-2min of time :wink:

It could, though that would only do something if the underlying IClasspathEntry implementations have proper equals/hashCode as well. If they do, then this is an easy win.

Would you accept a contribution via pull request? This would fix two issues for us :slight_smile:

Of course, contributions are welcome :slight_smile:

Pull Request created: https://github.com/eclipse/buildship/pull/369