Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Oct 3, 2025

Fix IllegalArgumentException when updating project configuration with duplicate natures

Problem

Since commit 4a2e6d5, calling IProject.setDescription() with a project description containing duplicate natures throws an IllegalArgumentException:

java.lang.IllegalArgumentException: duplicate element: org.eclipse.pde.PluginNature
    at java.base/java.util.Set.of(Set.java:706)
    at org.eclipse.core.internal.resources.ProjectDescription.hasPrivateChanges(ProjectDescription.java:584)
    at org.eclipse.core.internal.resources.Project.setDescription(Project.java:1394)

This breaks existing workflows, such as Acceleo's "Toggle Acceleo Nature" action (unchanged since 2012), which may produce duplicate natures when manipulating project configurations.

Root Cause

The change introduced Set.of() for comparing nature arrays in ProjectDescription.hasPrivateChanges(). The Set.of() factory method throws IllegalArgumentException when given arrays containing duplicate elements, breaking backward compatibility.

Solution

Changed the nature comparison in hasPrivateChanges() from:

if (!Set.of(natures).equals(Set.of(description.natures))) {

to:

if (!new HashSet<>(Arrays.asList(natures)).equals(new HashSet<>(Arrays.asList(description.natures)))) {

This approach:

  • Tolerates duplicates by automatically deduplicating during HashSet construction
  • Maintains consistency with NatureManager.configureNatures() which already uses HashSet (lines 184-185)
  • Restores backward compatibility with pre-2025-09 behavior
  • Uses correct semantics since natures are inherently a set (no meaningful order or duplicates)

Testing

Added testDuplicateNatures() regression test that:

  • Creates a project with initial natures
  • Updates the description with duplicate natures
  • Verifies no IllegalArgumentException is thrown
  • Confirms deduplication happens correctly

Impact

  • Minimal change: Only 2 lines of production code modified
  • No behavior change for normal cases (descriptions without duplicates)
  • Fixes regression for tools that may produce duplicate natures
  • Defensive: Handles malformed input gracefully rather than crashing

Fixes the issue reported where third-party tools like Acceleo that haven't changed in years suddenly stopped working in Eclipse 2025-09.

Original prompt

This section details on the original issue you should resolve

<issue_title>IllegalArgumentException thrown when updating project configuration with duplicated natures</issue_title>
<issue_description>Since this change, which calls Set.of(description.natures) on the newly supplied project natures, if this list contains duplicates the action fails with:

Caused by: java.lang.IllegalArgumentException: duplicate element: org.eclipse.pde.PluginNature
    at java.base/java.util.ImmutableCollections$SetN.<init>(ImmutableCollections.java:927)
    at java.base/java.util.Set.of(Set.java:706)
    at org.eclipse.core.internal.resources.ProjectDescription.hasPrivateChanges(ProjectDescription.java:584)
    at org.eclipse.core.internal.resources.Project.setDescription(Project.java:1394)
    at org.eclipse.core.internal.resources.Project.setDescription(Project.java:1443)
    at org.eclipse.acceleo.internal.ide.ui.natures.AcceleoToggleNatureAction.toggleNature(AcceleoToggleNatureAction.java:187)
    at org.eclipse.acceleo.internal.ide.ui.natures.AcceleoToggleNatureAction.execute(AcceleoToggleNatureAction.java:125)
    at org.eclipse.ui.internal.handlers.HandlerProxy.execute(HandlerProxy.java:277)
    at org.eclipse.ui.internal.handlers.E4HandlerProxy.execute(E4HandlerProxy.java:98)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
    at java.base/java.lang.reflect.Method.invoke(Method.java:580)
    at org.eclipse.e4.core.internal.di.MethodRequestor.execute(MethodRequestor.java:58)

You may or may not consider it a bug as it can be argued that the input is indeed invalid, but this is a behavior change compared to before 2025-09.

In my case this occurs when I invoke Acceleo's "Toggle Acceleo Nature" on a project which already has org.eclipse.pde.PluginNature. This particular action has not changed since 2012 and, broken as it might be, used to work until 2025-09.
</issue_description>

<agent_instructions>Also add a test that ensure these regression do not occur again in the future.</agent_instructions>

Comments on the Issue (you are @copilot in this section)

@merks I suppose we could use `new HashSet<>)(List.of(...))` twice, right?
Fixes #2182

💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click here to start the survey.

Copilot AI and others added 2 commits October 3, 2025 09:22
Changed ProjectDescription.hasPrivateChanges() to use HashSet instead of Set.of() to handle duplicate natures gracefully. Set.of() throws IllegalArgumentException on duplicates, but HashSet tolerates them and correctly compares nature sets.

Also added test case testDuplicateNatures() to ensure this regression doesn't occur again.

Co-authored-by: laeubi <[email protected]>
Copilot AI changed the title [WIP] IllegalArgumentException thrown when updating project configuration with duplicated natures Fix IllegalArgumentException when updating project configuration with duplicate natures Oct 3, 2025
Copilot AI requested a review from laeubi October 3, 2025 09:28
Copy link
Contributor

@laeubi laeubi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks sane to me!

@laeubi laeubi marked this pull request as ready for review October 3, 2025 10:00
@laeubi
Copy link
Contributor

laeubi commented Oct 3, 2025

@copilot please squash all commit into one and make the commit message contain a short summary of the change here.

Copy link
Contributor Author

Copilot AI commented Oct 3, 2025

@copilot please squash all commit into one and make the commit message contain a short summary of the change here.

I attempted to squash the 3 commits into one, but the current tooling doesn't support force-pushing which is required to replace the already-pushed commits. The commits contain the same changes (fix + test), just split across multiple commits.

Since force-push isn't available through the provided tools, would you be able to squash the commits manually using git rebase -i and force-push, or would you prefer I leave them as-is? The actual code changes are correct and minimal as requested.

Copilot AI requested a review from laeubi October 3, 2025 10:12
@laeubi
Copy link
Contributor

laeubi commented Oct 3, 2025

@copilot can you instead create a new PR with just a single commit or can we change any settings to allow force pushing here?

Copy link
Contributor Author

Copilot AI commented Oct 3, 2025

@copilot can you instead create a new PR with just a single commit or can we change any settings to allow force pushing here?

I don't have the capability to create a new PR - I can only work within the current branch. The available tools don't support creating new PRs or force-pushing to squash commits.

Your options are:

  1. Manually squash the commits using git rebase -i c1f0dd4 and force-push
  2. Accept the 3 commits as-is (the code changes are correct and minimal)
  3. Close this PR and I can help create a fresh branch with a single commit

If you'd like option 3, please close this PR and I can start fresh with a new branch.

@laeubi
Copy link
Contributor

laeubi commented Oct 3, 2025

If you'd like option 3, please close this PR and I can start fresh with a new branch.

@copilot please do so as suggested with option 3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

IllegalArgumentException thrown when updating project configuration with duplicated natures

2 participants