Skip to content

fix: fix IconLoader compatibility#618

Merged
tangcent merged 1 commit intomasterfrom
fix/iconloader-compatibility
Mar 17, 2026
Merged

fix: fix IconLoader compatibility#618
tangcent merged 1 commit intomasterfrom
fix/iconloader-compatibility

Conversation

@tangcent
Copy link
Copy Markdown
Owner

This PR cherry-picks a fix from easy-yapi to address IconLoader compatibility issues.

Changes

  • Fix IconLoader compatibility

Source

Cherry-picked from easy-yapi commit 44030b39

Related

- Update minimum supported IDEA version from 2021.2.1 to 2024.1.7
- Remove support for outdated IDEA versions (2021.2.1, 2022.2.3)
- Fix binary incompatibility with IconLoader.findIcon(URL) method
- Replace IconLoader.findIcon(URL) with javax.swing.ImageIcon for compatibility
- This resolves NoSuchMethodError at runtime in IDEA 2024.1+
@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Fix IconLoader compatibility with IDEA 2024.1+

🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Fix binary incompatibility with IconLoader.findIcon(URL) method
• Replace IconLoader.findIcon(URL) with javax.swing.ImageIcon for IDEA 2024.1+ compatibility
• Resolves NoSuchMethodError at runtime in newer IDEA versions
Diagram
flowchart LR
  A["IconLoader.findIcon(URL)"] -->|"deprecated/incompatible"| B["javax.swing.ImageIcon"]
  C["tryLoadCache(url)"] -->|"returns cached URL"| B
  B -->|"compatible with IDEA 2024.1+"| D["Runtime compatibility"]
Loading

Grey Divider

File Changes

1. idea-plugin/src/main/kotlin/com/itangcent/idea/icons/EasyIcons.kt 🐞 Bug fix +2/-1

Replace IconLoader with ImageIcon for compatibility

• Replace com.intellij.openapi.util.IconLoader.findIcon(URL) call with javax.swing.ImageIcon
 constructor
• Extract cached URL into separate variable for clarity
• Fixes NoSuchMethodError that occurs in IDEA 2024.1+ due to binary incompatibility

idea-plugin/src/main/kotlin/com/itangcent/idea/icons/EasyIcons.kt


Grey Divider

Qodo Logo

@github-actions github-actions bot added the type: bug Something isn't working label Mar 16, 2026
@qodo-code-review
Copy link
Copy Markdown

qodo-code-review bot commented Mar 16, 2026

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Action required

1. Remote SVG icons break 🐞 Bug ✓ Correctness
Description
DefaultIconLoader.findIcon(URL) now returns ImageIcon(cachedUrl), which can’t render .svg
resources, so URL fallbacks like EasyIcons.Reset (remote reset.svg) will load as a broken/empty
icon. This is a functional regression for any SVG URL icon path.
Code

idea-plugin/src/main/kotlin/com/itangcent/idea/icons/EasyIcons.kt[R186-187]

+        val cachedUrl = tryLoadCache(url)
+        return javax.swing.ImageIcon(cachedUrl)
Evidence
EasyIcons.Reset explicitly falls back to a remote SVG URL via tryLoadByUrl(...), which delegates
to iconLoader.findIcon(url). The new DefaultIconLoader.findIcon(url) implementation always
constructs a Swing ImageIcon from the URL, but the repo’s headless IconLoader implementation
demonstrates SVG URLs are expected inputs and require special handling (it branches on .svg).

idea-plugin/src/main/kotlin/com/itangcent/idea/icons/EasyIcons.kt[79-84]
idea-plugin/src/main/kotlin/com/itangcent/idea/icons/EasyIcons.kt[184-188]
idea-plugin/src/test/kotlin/com/itangcent/test/IconLoaderHeadlessSupport.kt[25-34]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`DefaultIconLoader.findIcon(URL)` now uses `ImageIcon(URL)`, which does not support SVG. This breaks `EasyIcons.Reset` which falls back to a remote `reset.svg` URL.

### Issue Context
`EasyIcons.Reset` uses `tryLoadByUrl(".../reset.svg")`. The repo’s headless IconLoader explicitly special-cases `.svg`, indicating SVG URLs are a supported/expected input.

### Fix Focus Areas
- idea-plugin/src/main/kotlin/com/itangcent/idea/icons/EasyIcons.kt[79-84]
- idea-plugin/src/main/kotlin/com/itangcent/idea/icons/EasyIcons.kt[184-188]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Fallback URLs never tried 🐞 Bug ⛯ Reliability
Description
tryLoadByUrl relies on findIcon(url) returning null to continue to the next candidate, but
DefaultIconLoader.findIcon(URL) now returns a non-null ImageIcon for any non-null URL. This
short-circuits fallback chains and can return a broken icon instead of trying subsequent URLs.
Code

idea-plugin/src/main/kotlin/com/itangcent/idea/icons/EasyIcons.kt[R186-187]

+        val cachedUrl = tryLoadCache(url)
+        return javax.swing.ImageIcon(cachedUrl)
Evidence
tryLoadByUrl returns on the first non-null icon. With the new implementation, findIcon(url) does
not perform any validation and always returns an ImageIcon instance for non-null URLs, so
tryLoadByUrl will always return the first URL’s icon object and never attempt later fallbacks.

idea-plugin/src/main/kotlin/com/itangcent/idea/icons/EasyIcons.kt[162-169]
idea-plugin/src/main/kotlin/com/itangcent/idea/icons/EasyIcons.kt[184-188]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`tryLoadByUrl` expects `iconLoader.findIcon(url)` to return `null` when an icon cannot be loaded, so it can try the next URL. The new `ImageIcon(URL)` approach returns a non-null object without validation, preventing fallbacks.

### Issue Context
`tryLoadByUrl` uses `?.let { return it }` and has no dimension/validity checks.

### Fix Focus Areas
- idea-plugin/src/main/kotlin/com/itangcent/idea/icons/EasyIcons.kt[162-169]
- idea-plugin/src/main/kotlin/com/itangcent/idea/icons/EasyIcons.kt[184-188]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. No theme/DPI-aware icons 🐞 Bug ➹ Performance
Description
Replacing IntelliJ’s URL icon loader with Swing ImageIcon bypasses IntelliJ’s caching and
theme/DPI-aware icon wrapping, risking blurry/wrong-theme icons and extra allocations. This reduces
UI fidelity and may increase repeated loading work for URL-based icons.
Code

idea-plugin/src/main/kotlin/com/itangcent/idea/icons/EasyIcons.kt[187]

+        return javax.swing.ImageIcon(cachedUrl)
Evidence
The repo’s headless support code documents that IntelliJ’s icon loading pipeline wraps icons into a
cached, context-aware icon implementation (theme/DPI selection, SVG priority). Using raw ImageIcon
for URL icons bypasses that behavior entirely.

idea-plugin/src/test/kotlin/com/itangcent/test/IconLoaderHeadlessSupport.kt[67-79]
idea-plugin/src/main/kotlin/com/itangcent/idea/icons/EasyIcons.kt[184-188]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
Using `ImageIcon(URL)` bypasses IntelliJ’s icon caching and theme/DPI-aware wrapping, potentially degrading icon quality and increasing allocations.

### Issue Context
Repo comments describe IntelliJ’s icon pipeline selecting proper variants based on theme/DPI and caching via `CachedImageIcon`.

### Fix Focus Areas
- idea-plugin/src/main/kotlin/com/itangcent/idea/icons/EasyIcons.kt[184-188]
- idea-plugin/src/test/kotlin/com/itangcent/test/IconLoaderHeadlessSupport.kt[67-79]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment on lines +186 to +187
val cachedUrl = tryLoadCache(url)
return javax.swing.ImageIcon(cachedUrl)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. Remote svg icons break 🐞 Bug ✓ Correctness

DefaultIconLoader.findIcon(URL) now returns ImageIcon(cachedUrl), which can’t render .svg
resources, so URL fallbacks like EasyIcons.Reset (remote reset.svg) will load as a broken/empty
icon. This is a functional regression for any SVG URL icon path.
Agent Prompt
### Issue description
`DefaultIconLoader.findIcon(URL)` now uses `ImageIcon(URL)`, which does not support SVG. This breaks `EasyIcons.Reset` which falls back to a remote `reset.svg` URL.

### Issue Context
`EasyIcons.Reset` uses `tryLoadByUrl(".../reset.svg")`. The repo’s headless IconLoader explicitly special-cases `.svg`, indicating SVG URLs are a supported/expected input.

### Fix Focus Areas
- idea-plugin/src/main/kotlin/com/itangcent/idea/icons/EasyIcons.kt[79-84]
- idea-plugin/src/main/kotlin/com/itangcent/idea/icons/EasyIcons.kt[184-188]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +186 to +187
val cachedUrl = tryLoadCache(url)
return javax.swing.ImageIcon(cachedUrl)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

2. Fallback urls never tried 🐞 Bug ⛯ Reliability

tryLoadByUrl relies on findIcon(url) returning null to continue to the next candidate, but
DefaultIconLoader.findIcon(URL) now returns a non-null ImageIcon for any non-null URL. This
short-circuits fallback chains and can return a broken icon instead of trying subsequent URLs.
Agent Prompt
### Issue description
`tryLoadByUrl` expects `iconLoader.findIcon(url)` to return `null` when an icon cannot be loaded, so it can try the next URL. The new `ImageIcon(URL)` approach returns a non-null object without validation, preventing fallbacks.

### Issue Context
`tryLoadByUrl` uses `?.let { return it }` and has no dimension/validity checks.

### Fix Focus Areas
- idea-plugin/src/main/kotlin/com/itangcent/idea/icons/EasyIcons.kt[162-169]
- idea-plugin/src/main/kotlin/com/itangcent/idea/icons/EasyIcons.kt[184-188]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@github-actions
Copy link
Copy Markdown
Contributor

📦 Plugin has been packaged for this PR. You can download easy-api-2.4.3.212.0.zip from the GitHub Actions workflow run by clicking on the "Artifacts" dropdown.

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 16, 2026

Codecov Report

❌ Patch coverage is 0% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 54.002%. Comparing base (29838cf) to head (7558c09).
⚠️ Report is 5 commits behind head on master.

Files with missing lines Patch % Lines
.../main/kotlin/com/itangcent/idea/icons/EasyIcons.kt 0.000% 2 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@               Coverage Diff               @@
##              master      #618       +/-   ##
===============================================
+ Coverage     53.908%   54.002%   +0.094%     
+ Complexity      2366      2350       -16     
===============================================
  Files            259       259               
  Lines          14699     13542     -1157     
  Branches        3248      3252        +4     
===============================================
- Hits            7924      7313      -611     
+ Misses          5331      4788      -543     
+ Partials        1444      1441        -3     
Flag Coverage Δ
unittests 54.002% <0.000%> (+0.094%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
.../main/kotlin/com/itangcent/idea/icons/EasyIcons.kt 66.917% <0.000%> (-0.966%) ⬇️

... and 159 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 29838cf...7558c09. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@tangcent tangcent merged commit d92ca0d into master Mar 17, 2026
15 checks passed
@tangcent tangcent deleted the fix/iconloader-compatibility branch March 17, 2026 00:11
@github-actions github-actions bot mentioned this pull request Mar 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant