Skip to content

Fix IllegalAccessException and NoSuchMethodException on startup#80

Merged
rostam merged 2 commits intomasterfrom
fix/extension-loader-reflection
Mar 16, 2026
Merged

Fix IllegalAccessException and NoSuchMethodException on startup#80
rostam merged 2 commits intomasterfrom
fix/extension-loader-reflection

Conversation

@rostam
Copy link
Owner

@rostam rostam commented Mar 16, 2026

  • Settings: call f.setAccessible(true) before reflective field access so public fields on package-private extension classes (e.g. GProductAction, SubdividedGraphBase) are reachable across classloader boundaries.
  • ExtensionLoader: skip abstract classes in loadExtension() to avoid NoSuchMethodException when scanning extension JARs for instantiable types.

- Settings: call f.setAccessible(true) before reflective field access so
  public fields on package-private extension classes (e.g. GProductAction,
  SubdividedGraphBase) are reachable across classloader boundaries.
- ExtensionLoader: skip abstract classes in loadExtension() to avoid
  NoSuchMethodException when scanning extension JARs for instantiable types.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@qodo-code-review
Copy link

Review Summary by Qodo

Fix reflection exceptions in extension loading and settings persistence
🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Fix IllegalAccessException in Settings by calling setAccessible(true) on fields before reflective
  access
• Skip abstract classes in ExtensionLoader to prevent NoSuchMethodException during extension
  scanning
• Enable cross-classloader access to public fields on package-private extension classes
Diagram
flowchart LR
  A["Extension Loading"] -->|Skip Abstract Classes| B["Avoid NoSuchMethodException"]
  C["Field Reflection Access"] -->|Call setAccessible| D["Cross-Classloader Access"]
  B --> E["Successful Extension Initialization"]
  D --> E
Loading

Grey Divider

File Changes

1. src/graphtea/platform/extension/ExtensionLoader.java 🐞 Bug fix +3/-1

Skip abstract classes in extension loading

• Added import for java.lang.reflect.Modifier to check class modifiers
• Modified loadExtension() method to skip abstract classes using Modifier.isAbstract() check
• Prevents NoSuchMethodException when scanning extension JARs for instantiable types

src/graphtea/platform/extension/ExtensionLoader.java


2. src/graphtea/platform/preferences/lastsettings/Settings.java 🐞 Bug fix +2/-0

Enable reflective access to package-private fields

• Added f.setAccessible(true) call in saveField() method before reflective field access
• Added f.setAccessible(true) call in loadField() method before field operations
• Enables access to public fields on package-private extension classes across classloader boundaries

src/graphtea/platform/preferences/lastsettings/Settings.java


Grey Divider

Qodo Logo

@qodo-code-review
Copy link

qodo-code-review bot commented Mar 16, 2026

Code Review by Qodo

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

Grey Divider


Remediation recommended

1. Access error aborts loading 🐞 Bug ⛯ Reliability
Description
Settings.loadField calls Field.setAccessible(true) outside its per-field exception handling, so if
that call throws, loadSettings stops processing the remaining annotated fields for that object and
only reports a generic error via the outer catch. This is inconsistent with saveField, which handles
accessibility failures per-field and continues processing other fields.
Code

src/graphtea/platform/preferences/lastsettings/Settings.java[89]

+        f.setAccessible(true);
Evidence
The newly-added setAccessible(true) is executed before any of loadField’s internal try/catches, so
an exception at that line escapes loadField. loadSettings wraps the whole field loop in a single
try/catch; therefore any exception escaping loadField exits the loop early and prevents subsequent
fields from loading. In contrast, saveField wraps setAccessible(true) + Field.get in a per-field
try/catch and returns just for that field, allowing other fields to continue.

src/graphtea/platform/preferences/lastsettings/Settings.java[88-116]
src/graphtea/platform/preferences/lastsettings/Settings.java[118-136]
src/graphtea/platform/preferences/lastsettings/Settings.java[59-70]

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

### Issue description
`Settings.loadField` invokes `Field#setAccessible(true)` outside of per-field exception handling. If that call throws, the exception escapes `loadField` and is caught by the outer `loadSettings` try/catch, which aborts the remaining field loop for that object and provides less-specific diagnostics.

### Issue Context
`saveField` already treats reflective access issues per-field (it logs the field and returns for that field only). `loadField` should follow the same pattern to keep settings loading robust.

### Fix Focus Areas
- src/graphtea/platform/preferences/lastsettings/Settings.java[88-116]
- src/graphtea/platform/preferences/lastsettings/Settings.java[118-136]

### Suggested change
- Wrap `f.setAccessible(true)` inside a try/catch in `loadField`.
- On failure, log `f` (and/or key/class) and return from `loadField` (so other fields still load).
- Optionally keep behavior consistent with `saveField` by using the same logging + `ExceptionHandler.catchException(e)` pattern.

ⓘ 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

1. Remove 32 trivial checkParameters() { return null; } overrides — default already on Parametrizable
2. Clean up dead variables and commented-out experimental code in Estrada/LaplacianEstrada
3. Extract concatWithArrayCopy() to AlgorithmUtils.concatArrays(); remove 6 duplicate copies
4. Add AlgorithmUtils.getEccentricities(); eliminate duplicated max-distance loop in AllEccen,
   TotalEccentricityIndex, EccentricityComplexityIndex; AllEccen now delegates to Eccentricity.eccentricity()
5. Introduce WienerIndexBase to consolidate FloydWarshall boilerplate and getCategory() across
   WienerIndex, MWienerIndex, EccentricWienerIndex
6. Remove dead private edge_adj() methods from ZagrebCoindex, ZagrebCoindexSelectedEdges,
   ZagrebIndexSelectedEdges (never called in those classes)
7. Override clear() in NotifiableAttributeSetImpl to fire attributeUpdated(name, old, null)
   for each entry, consistent with the notification contract on put()

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@rostam rostam merged commit 2b085dc into master Mar 16, 2026
3 checks passed
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.

1 participant