Conversation
Now let me check the directory structure and create the model classes:
Updated spec.md and plan.md to use **package-private fields** instead of private fields with getters/setters: **Changes:** - Response model classes will use fields without access modifiers (package-private) - No getters/setters boilerplate needed - Gson can directly access package-private fields - Only public helper methods (extractDoi(), toBibEntry()) where needed
Updated spec.md with complete structure examples for all response model classes: **CitationItem**: Package-private fields (oci, citing, cited, creation, timespan, journalSelfCitation, authorSelfCitation) with public helper methods **CitationResponse**: Package-private `List<CitationItem> data` field **CountResponse**: Package-private `String count` field All classes follow the package-private pattern - no getters/setters needed, Gson handles deserialization directly.
✓ **OpenCitationsFetcher Core Class implemented** Created `/home/koppor/.zenflow/worktrees/new-task-ed21/jablib/src/main/java/org/jabref/logic/importer/fetcher/citation/opencitations/OpenCitationsFetcher.java` with: - ✓ Constructor accepting `ImporterPreferences` - ✓ `getName()` returning "OpenCitations" - ✓ `getReferences()` - fetches outgoing references from DOI - ✓ `getCitations()` - fetches incoming citations to DOI - ✓ `getCitationCount()` - fetches citation count - ✓ DOI extraction from OpenCitations PID strings - ✓ BibEntry conversion using CrossRef fetcher - ✓ Fallback to minimal BibEntry creation - ✓ Error handling (missing DOI, network errors, JSON parsing) - ✓ Optional API key support via ImporterPreferences Plan updated: `plan.md:71` marked as `[x]`
Updated to use `@NullMarked` + `@Nullable` pattern
Done. `fetchBibEntryFromDoi` now handles errors with `createMinimalBibEntry`, and `createMinimalBibEntry` uses method chaining.
Done. Now handles all identifiers: - **DOI**: Fetches full metadata via CrossRef - **PMID**: Creates entry with `StandardField.PMID` - **Other IDs** (omid, openalex): Creates entry using `FieldFactory.parseField()` No identifiers are skipped.
Simplified. `FieldFactory.parseField()` handles all identifiers including `doi` and `pmid`.
Updated to handle all identifiers from space-separated lists. Each citation/reference now creates a single BibEntry with: - Full metadata from CrossRef (if DOI present) - All additional identifiers (PMID, OMID, OpenAlex, etc.) added as fields
Done. Identifiers without colons are now added to BibEntry with `StandardField.NOTE`.
Unified. `getReferences()` and `getCitations()` now delegate to `fetchCitationData()` with endpoint and identifier extractor as parameters.
Refactored. Now creates **one BibEntry per identifier**: - Each identifier (DOI, PMID, OMID, etc.) → separate BibEntry - DOI identifiers fetch full metadata via CrossRef - Other identifiers create minimal entries with just that field
Fixed! Each `CitationItem` now creates **one BibEntry** with: - Full metadata from CrossRef (if DOI exists) + all other identifiers added - All identifiers as fields (if no DOI)
I'll register OpenCitations in the CitationFetcherType enum. Let me first locate and read the file.
PR Compliance Guide 🔍Below is a summary of compliance checks for this PR:
Compliance status legend🟢 - Fully Compliant🟡 - Partial Compliant 🔴 - Not Compliant ⚪ - Requires Further Human Verification 🏷️ - Compliance label |
|||||||||||||||||||||||||||
PR Code Suggestions ✨Explore these optional code suggestions:
|
||||||||||||||||||
| .install(fetcherCombo); | ||
| styleTopBarNode(fetcherCombo, 75.0); | ||
| fetcherCombo.setValue(entryEditorPreferences.getCitationFetcherType()); | ||
| fetcherCombo.valueProperty().bindBidirectional(entryEditorPreferences.citationFetcherTypeProperty()); |
There was a problem hiding this comment.
- Common pattern in JabRef's code base
- It might be that some other UI element will allow for changing the citatoin fetcher. E.g., when checking citation counts at
org.jabref.gui.fieldeditors.CitationCountEditor
| return 0; | ||
| } | ||
| try { | ||
| return Integer.parseInt(count); |
There was a problem hiding this comment.
is this class here really necessary?
There was a problem hiding this comment.
DTO pattern. Better consistency in always using a DTO in this class than case-by-case
--> CitatonItem is the other DTO.
| protected void bindToEntry(BibEntry entry) { | ||
| citationsRelationsTabViewModel.bindToEntry(entry); | ||
|
|
||
| // TODO: All this should go to ViewModel |
There was a problem hiding this comment.
Will you do this or for follow-up
There was a problem hiding this comment.
Maybe me, maybe someone else. This was in before - I created an issue for this.
User description
This adds support for OpenCitations.
Steps to test
Mandatory checks
CHANGELOG.mdin a way that is understandable for the average user (if change is visible to the user)PR Type
Enhancement
Description
Add OpenCitations fetcher support for citation relations
Implement bidirectional binding for fetcher selection preference
Create response model classes for OpenCitations API
Fix DOI URL encoding in CrossRef fetcher
Unify citation fetcher initialization in CLI commands
Diagram Walkthrough
File Walkthrough
8 files
Implement OpenCitations citation fetcher coreCreate CitationItem response model classCreate CountResponse model for citation countsRegister OpenCitations fetcher in enumUpdate fetcher name and nullability annotationsImplement bidirectional preference binding for fetcherChange default fetcher to OpenCitationsAdd provider option and unify fetcher initialization1 files
URL encode DOI identifiers in API requests2 files
Document OpenCitations support and DOI encoding fixClarify references definition and structure