Skip to content

Feature provide insights citation fetcher#15093

Merged
koppor merged 32 commits intoJabRef:mainfrom
LoayTarek5:feature-provide-insights-citation-fetcher-15033
Feb 14, 2026
Merged

Feature provide insights citation fetcher#15093
koppor merged 32 commits intoJabRef:mainfrom
LoayTarek5:feature-provide-insights-citation-fetcher-15033

Conversation

@LoayTarek5
Copy link
Contributor

@LoayTarek5 LoayTarek5 commented Feb 11, 2026

Related issues and pull requests

Closes #15033

PR Description

Added an "Open API URL in browser" option in the Citations tab,
allowing users to view the raw API response from all citation fetchers except for CrossRef does not support fetching citations for a given entry
This is accessible via a context menu on the "References cited" and "References that cite" labels.

Steps to test

1- load a library with entries
2- Select an entry and go to the Citations tab
3- Select a citation fetcher(OpenAlex, OpenCitations, Semantic Scholar, and CrossRef)
3- Right-click on "References cited in {entry}" or "References that cite {entry}"
4- Click "Open API URL in browser"
image
image
image
image
image

Checklist

  • I own the copyright of the code submitted and I license it under the MIT license
  • I manually tested my changes in running JabRef (always required)
  • [/] I added JUnit tests for changes (if applicable)
  • I added screenshots in the PR description (if change is visible to the user)
  • I added a screenshot in the PR description showing a library with a single entry with me as author and as title the issue number
  • I described the change in CHANGELOG.md in a way that can be understood by the average user (if change is visible to the user)
  • [/] I checked the user documentation for up to dateness and submitted a pull request to our user documentation repository

@qodo-free-for-open-source-projects
Copy link
Contributor

Review Summary by Qodo

Add API URL browser access for citation fetchers in Citations tab

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Added context menu to citation labels for opening API URLs in browser
• Implemented API URI retrieval methods across all citation fetchers (OpenAlex, OpenCitations,
  Semantic Scholar, CrossRef)
• Integrated native browser opening functionality with error handling
• Added localization support for new API URL features
Diagram
flowchart LR
  A["User right-clicks citation label"] --> B["Context menu displays"]
  B --> C["Select 'Open API URL in browser'"]
  C --> D["Fetch API URI from citation fetcher"]
  D --> E["Open URI in native browser"]
Loading

Grey Divider

File Changes

1. jabgui/src/main/java/org/jabref/gui/entryeditor/citationrelationtab/CitationRelationsTab.java ✨ Enhancement +36/-0

Add context menu for opening citation API URLs

jabgui/src/main/java/org/jabref/gui/entryeditor/citationrelationtab/CitationRelationsTab.java


2. jablib/src/main/java/org/jabref/logic/citation/SearchCitationsRelationsService.java ✨ Enhancement +9/-0

Add methods to retrieve API URIs for citations

jablib/src/main/java/org/jabref/logic/citation/SearchCitationsRelationsService.java


3. jablib/src/main/java/org/jabref/logic/importer/fetcher/OpenAlex.java ✨ Enhancement +29/-0

Implement API URI generation for OpenAlex fetcher

jablib/src/main/java/org/jabref/logic/importer/fetcher/OpenAlex.java


View more (6)
4. jablib/src/main/java/org/jabref/logic/importer/fetcher/citation/CitationFetcher.java ✨ Enhancement +17/-0

Add default API URI methods to interface

jablib/src/main/java/org/jabref/logic/importer/fetcher/citation/CitationFetcher.java


5. jablib/src/main/java/org/jabref/logic/importer/fetcher/citation/crossref/CrossRefCitationFetcher.java ✨ Enhancement +24/-0

Implement references API URI for CrossRef fetcher

jablib/src/main/java/org/jabref/logic/importer/fetcher/citation/crossref/CrossRefCitationFetcher.java


6. jablib/src/main/java/org/jabref/logic/importer/fetcher/citation/opencitations/OpenCitationsFetcher.java ✨ Enhancement +34/-0

Implement API URI methods for OpenCitations fetcher

jablib/src/main/java/org/jabref/logic/importer/fetcher/citation/opencitations/OpenCitationsFetcher.java


7. jablib/src/main/java/org/jabref/logic/importer/fetcher/citation/semanticscholar/SemanticScholarCitationFetcher.java ✨ Enhancement +32/-0

Implement API URI methods for Semantic Scholar

jablib/src/main/java/org/jabref/logic/importer/fetcher/citation/semanticscholar/SemanticScholarCitationFetcher.java


8. CHANGELOG.md 📝 Documentation +1/-0

Document new API URL browser feature

CHANGELOG.md


9. jablib/src/main/resources/l10n/JabRef_en.properties ⚙️ Configuration changes +3/-0

Add localization entries for API URL feature

jablib/src/main/resources/l10n/JabRef_en.properties


Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects
Copy link
Contributor

qodo-free-for-open-source-projects bot commented Feb 11, 2026

Code Review by Qodo

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

Grey Divider


Action required

✅ 1. IOException swallowed without log 📘 Rule violation ✓ Correctness
Description
When opening the API URL fails, the caught IOException is not logged, which prevents diagnosing
failures in production. This violates the requirement to log exceptions (with the exception as the
last logger argument) instead of silently handling them.
Code

jabgui/src/main/java/org/jabref/gui/entryeditor/citationrelationtab/CitationRelationsTab.java[R645-649]

+                        try {
+                            NativeDesktop.openBrowser(apiUri, preferences.getExternalApplicationsPreferences());
+                        } catch (IOException e) {
+                            dialogService.notify(Localization.lang("Unable to open link."));
+                        }
Evidence
PR Compliance ID 21 requires exceptions to be logged properly. The newly added catch block for
IOException only shows a user notification and drops the exception without any logger call.

AGENTS.md
jabgui/src/main/java/org/jabref/gui/entryeditor/citationrelationtab/CitationRelationsTab.java[645-649]

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

## Issue description
A newly added `catch (IOException e)` swallows the exception without logging it, making browser-opening failures hard to diagnose.
## Issue Context
The compliance checklist requires exceptions to be logged and passed as the last argument to the logger call.
## Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/entryeditor/citationrelationtab/CitationRelationsTab.java[645-649]

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



Remediation recommended

✅ 2. OpenAlex URI exceptions leak 🐞 Bug ⛯ Reliability
Description
OpenAlex#getCitationsApiUri / #getReferencesApiUri can throw unchecked exceptions because
checked exceptions inside Unchecked.function(...) are wrapped into RuntimeException and not
caught, causing the action to fail (and likely be logged) when users click “Open API URL in
browser”. Additionally, optString("id") can be empty, yielding a bogus filter=cites: URL.
Code

jablib/src/main/java/org/jabref/logic/importer/fetcher/OpenAlex.java[R424-448]

+    public Optional<URI> getCitationsApiUri(BibEntry entry) {
+        try {
+            return getWorkObject(entry, List.of("id"))
+                    .map(work -> work.optString("id"))
+                    .filter(Objects::nonNull)
+                    .map(Unchecked.function(id ->
+                            getUriBuilder("", List.of())
+                                    .addParameter("filter", "cites:" + id)
+                                    .build()
+                    ));
+        } catch (FetcherException e) {
+            LOGGER.debug("Could not create citations API URI", e);
+            return Optional.empty();
+        }
+    }
+
+    @Override
+    public Optional<URI> getReferencesApiUri(BibEntry entry) {
+        try {
+            return getUrl(entry, List.of())
+                    .map(Unchecked.function(URL::toURI));
+        } catch (MalformedURLException e) {
+            LOGGER.debug("Could not create references API URI", e);
+            return Optional.empty();
+        }
Evidence
The new API-URI methods use Unchecked.function(...) but only catch FetcherException /
MalformedURLException. However, URL/URI construction in OpenAlex can throw
MalformedURLException/URISyntaxException (e.g., from URIBuilder.build()), and
Unchecked.function wraps those into RuntimeException, which will bypass the current catch
blocks. Also, optString("id") returns an empty string when missing, so filtering only nonNull
can still generate an invalid cites: filter URL.

jablib/src/main/java/org/jabref/logic/importer/fetcher/OpenAlex.java[423-449]
jablib/src/main/java/org/jabref/logic/importer/fetcher/OpenAlex.java[123-144]
jablib/src/main/java/org/jabref/logic/importer/fetcher/OpenAlex.java[365-413]

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

## Issue description
`OpenAlex#getCitationsApiUri` and `#getReferencesApiUri` can throw unchecked exceptions because checked exceptions inside `Unchecked.function(...)` are wrapped as `RuntimeException` and are not caught. This can break the “Open API URL in browser” action. Additionally, `optString(&amp;amp;quot;id&amp;amp;quot;)` can be empty, producing a malformed OpenAlex citations query (`filter=cites:`).
### Issue Context
These methods are invoked from a JavaFX context-menu action and should be robust (return `Optional.empty()` when they cannot produce a valid URI).
### Fix Focus Areas
- jablib/src/main/java/org/jabref/logic/importer/fetcher/OpenAlex.java[423-449]
- jablib/src/main/java/org/jabref/logic/importer/fetcher/OpenAlex.java[123-144]

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


✅ 3. UI thread may block 🐞 Bug ➹ Performance
Description
The context-menu action computes the API URI synchronously on the JavaFX thread; for OpenAlex
citations this calls getWorkObject(...), which performs a network request, potentially freezing
the UI until the request completes.
Code

jabgui/src/main/java/org/jabref/gui/entryeditor/citationrelationtab/CitationRelationsTab.java[R637-653]

+        MenuItem openApiUrl = new MenuItem(Localization.lang("Open API URL in browser"));
+        openApiUrl.setOnAction(_ -> {
+            Optional<URI> uri = searchType == CitationFetcher.SearchType.CITES
+                                ? searchCitationsRelationsService.getReferencesApiUri(entry)
+                                : searchCitationsRelationsService.getCitationsApiUri(entry);
+
+            uri.ifPresentOrElse(
+                    apiUri -> {
+                        try {
+                            NativeDesktop.openBrowser(apiUri, preferences.getExternalApplicationsPreferences());
+                        } catch (IOException e) {
+                            dialogService.notify(Localization.lang("Unable to open link."));
+                        }
+                    },
+                    () -> dialogService.notify(Localization.lang("No API URL available."))
+            );
+        });
Evidence
The JavaFX action handler directly calls searchCitationsRelationsService.get*CitationsApiUri(...)
without using a background task. For OpenAlex, getCitationsApiUri calls getWorkObject, which
downloads JSON via getUrlDownload(...).asInputStream(), i.e., network I/O, and will run on the UI
thread as written.

jabgui/src/main/java/org/jabref/gui/entryeditor/citationrelationtab/CitationRelationsTab.java[634-653]
jablib/src/main/java/org/jabref/logic/importer/fetcher/OpenAlex.java[261-277]

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

## Issue description
The “Open API URL in browser” menu action performs API-URI resolution on the JavaFX UI thread. For OpenAlex citations this triggers a network request, which can freeze the UI.
### Issue Context
JavaFX event handlers should avoid blocking operations; the codebase already uses background tasks in this tab for citation fetching.
### Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/entryeditor/citationrelationtab/CitationRelationsTab.java[634-653]
- jablib/src/main/java/org/jabref/logic/importer/fetcher/OpenAlex.java[261-277]

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



Advisory comments

✅ 4. CrossRef URL inconsistent 🐞 Bug ✓ Correctness
Description
CrossRefCitationFetcher#getReferences can succeed without an existing DOI by calling
findDoiForEntry, but getReferencesApiUri returns empty when the DOI field is missing, so the UI
may misleadingly show “No API URL available.”
Code

jablib/src/main/java/org/jabref/logic/importer/fetcher/citation/crossref/CrossRefCitationFetcher.java[R199-212]

+    public Optional<URI> getReferencesApiUri(BibEntry entry) {
+        Optional<DOI> doi = entry.getField(StandardField.DOI).flatMap(DOI::parse);
+        if (doi.isEmpty()) {
+            return Optional.empty();
+        }
+
+        try {
+            String apiUrl = API_URL + doi.get().asString();
+            return Optional.of(new URI(apiUrl));
+        } catch (URISyntaxException e) {
+            LOGGER.debug("Could not create references API URI", e);
+            return Optional.empty();
+        }
+    }
Evidence
CrossRef references fetching has a DOI-recovery path, but the new API-URI method does not, so the
new context-menu behavior can diverge from actual fetch capability for entries without a DOI.

jablib/src/main/java/org/jabref/logic/importer/fetcher/citation/crossref/CrossRefCitationFetcher.java[75-83]
jablib/src/main/java/org/jabref/logic/importer/fetcher/citation/crossref/CrossRefCitationFetcher.java[199-203]

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

## Issue description
CrossRef can fetch references even if the entry has no DOI (it tries to find one), but `getReferencesApiUri` returns empty in that case, which can mislead users.
### Issue Context
The UI uses `getReferencesApiUri` to decide whether to open a browser or show “No API URL available.”
### Fix Focus Areas
- jablib/src/main/java/org/jabref/logic/importer/fetcher/citation/crossref/CrossRefCitationFetcher.java[74-83]
- jablib/src/main/java/org/jabref/logic/importer/fetcher/citation/crossref/CrossRefCitationFetcher.java[198-212]

ⓘ 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 645 to 649
try {
NativeDesktop.openBrowser(apiUri, preferences.getExternalApplicationsPreferences());
} catch (IOException e) {
dialogService.notify(Localization.lang("Unable to open link."));
}

Choose a reason for hiding this comment

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

Action required

1. ioexception swallowed without log 📘 Rule violation ✧ Quality

When opening the API URL fails, the caught IOException is not logged, which prevents diagnosing
failures in production. This violates the requirement to log exceptions (with the exception as the
last logger argument) instead of silently handling them.
Agent Prompt
## Issue description
A newly added `catch (IOException e)` swallows the exception without logging it, making browser-opening failures hard to diagnose.

## Issue Context
The compliance checklist requires exceptions to be logged and passed as the last argument to the logger call.

## Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/entryeditor/citationrelationtab/CitationRelationsTab.java[645-649]

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

Copy link
Member

@koppor koppor left a comment

Choose a reason for hiding this comment

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

Please try harder to follow

If possible, the new methods should be used by the CitationFetcher implementations

I think, one can use the method at each fetcher.

Especially at OpenCitatoinsFechter.

Please use this as chance to learn about code reading for yourself - and not just to generate some code. Please!!

@github-actions github-actions bot added status: changes-required Pull requests that are not yet complete and removed status: no-bot-comments labels Feb 11, 2026
@testlens-app
Copy link

testlens-app bot commented Feb 11, 2026

✅ All tests passed ✅

🏷️ Commit: 125fb2d
▶️ Tests: 11192 executed
⚪️ Checks: 50/50 completed


Learn more about TestLens at testlens.app.

@LoayTarek5 LoayTarek5 requested a review from koppor February 12, 2026 09:37
@github-actions
Copy link
Contributor

Do not request reviews if changes are required.
Address the changes first.

@github-actions github-actions bot added status: changes-required Pull requests that are not yet complete and removed status: no-bot-comments labels Feb 13, 2026
@github-actions github-actions bot added status: no-bot-comments and removed status: changes-required Pull requests that are not yet complete labels Feb 13, 2026
@LoayTarek5 LoayTarek5 requested a review from koppor February 13, 2026 12:28
@github-actions github-actions bot added status: changes-required Pull requests that are not yet complete and removed status: no-bot-comments labels Feb 14, 2026
@github-actions
Copy link
Contributor

Your pull request conflicts with the target branch.

Please merge with your code. For a step-by-step guide to resolve merge conflicts, see https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/addressing-merge-conflicts/resolving-a-merge-conflict-using-the-command-line.

Copy link
Member

@koppor koppor left a comment

Choose a reason for hiding this comment

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

Thank you for working on this.

Some last steps missing, but I think, they can only be done with experience.

OK, they are somehow expected to be done at a "good third issue", but I want the feature early (and need to review other PRs). Thus, I did the last steps for myself.

--> We are still a project focussing on maintainable code; especially avoiding code duplication.

@koppor koppor enabled auto-merge February 14, 2026 04:59
@github-actions github-actions bot added status: no-bot-comments and removed status: changes-required Pull requests that are not yet complete labels Feb 14, 2026
@koppor koppor added this pull request to the merge queue Feb 14, 2026
@github-actions github-actions bot added the status: to-be-merged PRs which are accepted and should go into the merge-queue. label Feb 14, 2026
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Feb 14, 2026
@koppor
Copy link
Member

koppor commented Feb 14, 2026

I used this PR as example to ask GitHub support. See https://github.com/orgs/community/discussions/187123#discussion-9475767 (you can vote up if you want)

@LoayTarek5
Copy link
Contributor Author

Thank you for working on this.

Some last steps missing, but I think, they can only be done with experience.

OK, they are somehow expected to be done at a "good third issue", but I want the feature early (and need to review other PRs). Thus, I did the last steps for myself.

--> We are still a project focussing on maintainable code; especially avoiding code duplication.

Thank you very much, to be honest, i learned so much while working on this issue and having fun. Also, sorry for some improper code quality, I will try to improve it.
Also, if you have any references or documents that will help me with that, feel free to drop them.
I think i need to read more code from the codebase to get familiar with the style and pattern

@koppor koppor merged commit ec56cc2 into JabRef:main Feb 14, 2026
50 checks passed
Siedlerchr added a commit to faneeshh/jabref that referenced this pull request Feb 14, 2026
* upstream/main:
  Refine Automatic Field Editor filtering logic (fixes JabRef#15066) (JabRef#15094)
  Output URL to workflow
  Fix token
  Refine stats message
  Quick fix to reduce load on runners
  "Debug" output for assign-issue-action
  Streamline pr-comment.yml (and remove status: stale label)
  Feature provide insights citation fetcher (JabRef#15093)
  Automatic Grouping By Entry Type (JabRef#15081)
  Minor test fixes for arXiv (JabRef#15100)
  New Crowdin updates (JabRef#15101)
  recomment linked files handler (JabRef#15105)
  Chore(deps): Bump jablib/src/main/resources/csl-styles (JabRef#15087)
  Streamline binaries (JabRef#15085)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

good third issue status: no-bot-comments status: to-be-merged PRs which are accepted and should go into the merge-queue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Provide insights at the citation fetcher

2 participants