Conversation
rostam
commented
Mar 16, 2026
- Replace Vector with ArrayList in GraphSaveObject
- Replace deprecated javax.xml.bind.DatatypeConverter with java.util.Base64
- Replace raw Enumeration/Class types with typed generics in ExtensionClassLoader
- Add try-with-resources for FileInputStream and ZipFile in ExtensionClassLoader
- Replace string concatenation in loops with StringBuilder in AlgorithmUtils
- Simplify isConnected() to use stream().distinct().count()
- Fix raw ArrayX types to ArrayX<?> across preferences classes (AbstractPreference, GraphPreferences, UserDefinedEligiblity, ArrowHandler)
- Replace Vector with ArrayList in GraphSaveObject - Replace deprecated javax.xml.bind.DatatypeConverter with java.util.Base64 - Replace raw Enumeration/Class types with typed generics in ExtensionClassLoader - Add try-with-resources for FileInputStream and ZipFile in ExtensionClassLoader - Replace string concatenation in loops with StringBuilder in AlgorithmUtils - Simplify isConnected() to use stream().distinct().count() - Fix raw ArrayX types to ArrayX<?> across preferences classes (AbstractPreference, GraphPreferences, UserDefinedEligiblity, ArrowHandler) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Review Summary by QodoModernize Java code: remove legacy APIs and improve type safety
WalkthroughsDescription• Replace deprecated javax.xml.bind.DatatypeConverter with java.util.Base64 • Replace Vector with ArrayList in GraphSaveObject • Replace raw type generics with typed generics across multiple classes • Replace string concatenation in loops with StringBuilder in AlgorithmUtils • Add try-with-resources for FileInputStream and ZipFile in ExtensionClassLoader • Simplify isConnected() to use stream().distinct().count() • Improve code formatting and control flow structure Diagramflowchart LR
A["Legacy APIs<br/>DatatypeConverter<br/>Vector"] -->|Replace| B["Modern APIs<br/>Base64<br/>ArrayList"]
C["Raw Types<br/>Class, ArrayX<br/>Enumeration"] -->|Add Generics| D["Typed Generics<br/>Class<?><br/>ArrayX<?>"]
E["String Concat<br/>in Loops"] -->|Refactor| F["StringBuilder<br/>Chaining"]
G["Manual Resource<br/>Management"] -->|Modernize| H["Try-with-resources<br/>Auto-close"]
File Changes1. src/graphtea/extensions/AlgorithmUtils.java
|
Code Review by Qodo
1. Old .tea files unreadable
|
| public ArrayList<VertexSaveObject> vs = new ArrayList<>(); | ||
| ArrayList<EdgeSaveObject> es = new ArrayList<>(); |
There was a problem hiding this comment.
1. Old .tea files unreadable 🐞 Bug ✓ Correctness
GraphSaveObject is serialized as the on-disk GraphTea format (*.tea); changing its serialized field types from Vector to ArrayList will prevent loading graphs saved by older versions (deserialization will fail due to incompatible field metadata). This breaks backward compatibility for SaveGraph/LoadGraph.
Agent Prompt
### Issue description
`GraphSaveObject` is persisted to disk via Java serialization for the GraphTea `*.tea` format. The PR changes the serialized field types (`Vector` -> `ArrayList`) without providing any migration logic, which will make older `*.tea` files fail to deserialize.
### Issue Context
`SaveGraph` writes `new GraphSaveObject(graph)` through `ObjectOutputStream`, and `LoadGraph` reads it back through `ObjectInputStream`.
### Fix Focus Areas
- src/graphtea/extensions/io/GraphSaveObject.java[16-36]
- src/graphtea/extensions/io/SaveGraph.java[27-34]
- src/graphtea/extensions/io/LoadGraph.java[35-42]
### Implementation direction
- Add explicit serialization compatibility in `GraphSaveObject`:
- Use `serialPersistentFields` and `readObject`/`writeObject` to persist the legacy schema (e.g., store as `Vector` in the stream) while using `ArrayList` in memory, **or** read both possible types (`Vector` or `ArrayList`) and convert.
- Keep stream field names stable (`vs`, `es`, etc.) and convert during `readObject`.
- Validate by loading a `.tea` file saved with the previous version.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| try (InputStream in = zipFile.getInputStream(entry); | ||
| OutputStream out = new BufferedOutputStream( | ||
| new FileOutputStream(destDir + File.separator + entry.getName()))) { | ||
| copyInputStream(in, out); |
There was a problem hiding this comment.
2. Zip path traversal extraction 🐞 Bug ⛨ Security
ExtensionClassLoader.unZip writes zip entries to destDir + File.separator + entry.getName() without normalizing/validating the entry path, allowing a crafted extension zip to write outside destDir via ../ (Zip Slip). This is particularly risky because loadClassFiles automatically unzips every *.zip in the extensions directory.
Agent Prompt
### Issue description
`ExtensionClassLoader.unZip` uses `entry.getName()` directly when creating output `File`s. A malicious zip entry name (e.g., `../outside.txt`) can cause writes outside the target directory (Zip Slip).
### Issue Context
`loadClassFiles` auto-unzips every `*.zip` under the extensions directory.
### Fix Focus Areas
- src/graphtea/platform/extension/ExtensionClassLoader.java[50-55]
- src/graphtea/platform/extension/ExtensionClassLoader.java[137-155]
### Implementation direction
- Use `java.nio.file.Path`:
- `Path dest = Paths.get(destDir).toRealPath();`
- `Path target = dest.resolve(entry.getName()).normalize();`
- Reject entries where `!target.startsWith(dest)`.
- For file entries:
- `Files.createDirectories(target.getParent());`
- Write to `target.toFile()`.
- Apply the same containment check for directory entries before `createDirectories`.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools