From f8632b11458dcfd4aab4690da4a577f0f19ac06f Mon Sep 17 00:00:00 2001 From: Carl Christian Snethlage Date: Sun, 19 Oct 2025 17:16:34 +0200 Subject: [PATCH 1/4] Fix some null warnings --- .../java/org/jabref/logic/ai/AiPreferences.java | 9 ++++++--- .../logic/ai/ingestion/MVStoreEmbeddingStore.java | 2 +- .../ai/ingestion/model/JabRefEmbeddingModel.java | 4 ++-- .../org/jabref/logic/ai/util/MVStoreBase.java | 4 ++-- .../jabref/model/database/BibDatabaseContext.java | 15 +++++++++++++-- .../model/database/BibDatabaseContextTest.java | 1 - 6 files changed, 24 insertions(+), 11 deletions(-) diff --git a/jablib/src/main/java/org/jabref/logic/ai/AiPreferences.java b/jablib/src/main/java/org/jabref/logic/ai/AiPreferences.java index 42c3df7ba4b..a5f5a22f0f6 100644 --- a/jablib/src/main/java/org/jabref/logic/ai/AiPreferences.java +++ b/jablib/src/main/java/org/jabref/logic/ai/AiPreferences.java @@ -116,6 +116,9 @@ public AiPreferences(boolean enableAi, this.ragMaxResultsCount = new SimpleIntegerProperty(ragMaxResultsCount); this.ragMinScore = new SimpleDoubleProperty(ragMinScore); + this.apiKeyChangeListener = () -> { + }; + this.templates = Map.of( AiTemplate.CHATTING_SYSTEM_MESSAGE, new SimpleStringProperty(templates.get(AiTemplate.CHATTING_SYSTEM_MESSAGE)), AiTemplate.CHATTING_USER_MESSAGE, new SimpleStringProperty(templates.get(AiTemplate.CHATTING_USER_MESSAGE)), @@ -550,14 +553,14 @@ public void apiKeyUpdated() { } public void setTemplate(AiTemplate aiTemplate, String template) { - templates.get(aiTemplate).set(template); + templateProperty(aiTemplate).set(template); } public String getTemplate(AiTemplate aiTemplate) { - return templates.get(aiTemplate).get(); + return templateProperty(aiTemplate).get(); } public StringProperty templateProperty(AiTemplate aiTemplate) { - return templates.get(aiTemplate); + return templates.getOrDefault(aiTemplate, new SimpleStringProperty("")); } } diff --git a/jablib/src/main/java/org/jabref/logic/ai/ingestion/MVStoreEmbeddingStore.java b/jablib/src/main/java/org/jabref/logic/ai/ingestion/MVStoreEmbeddingStore.java index 70446cee9ab..2c6c2b85459 100644 --- a/jablib/src/main/java/org/jabref/logic/ai/ingestion/MVStoreEmbeddingStore.java +++ b/jablib/src/main/java/org/jabref/logic/ai/ingestion/MVStoreEmbeddingStore.java @@ -125,7 +125,7 @@ public EmbeddingSearchResult search(EmbeddingSearchRequest request) PriorityQueue> matches = new PriorityQueue<>(comparator); applyFilter(request.filter()).forEach(id -> { - EmbeddingRecord eRecord = embeddingsMap.get(id); + EmbeddingRecord eRecord = embeddingsMap.getOrDefault(id, new EmbeddingRecord(null, "", new float[0])); double cosineSimilarity = CosineSimilarity.between(Embedding.from(eRecord.embeddingVector), request.queryEmbedding()); double score = RelevanceScore.fromCosineSimilarity(cosineSimilarity); diff --git a/jablib/src/main/java/org/jabref/logic/ai/ingestion/model/JabRefEmbeddingModel.java b/jablib/src/main/java/org/jabref/logic/ai/ingestion/model/JabRefEmbeddingModel.java index b203ed92df9..487743d2701 100644 --- a/jablib/src/main/java/org/jabref/logic/ai/ingestion/model/JabRefEmbeddingModel.java +++ b/jablib/src/main/java/org/jabref/logic/ai/ingestion/model/JabRefEmbeddingModel.java @@ -74,7 +74,7 @@ public void startRebuildingTask() { predictorProperty.set(Optional.empty()); new UpdateEmbeddingModelTask(aiPreferences, predictorProperty) - .onSuccess(v -> { + .onSuccess(_ -> { LOGGER.info("Embedding model was successfully updated"); errorWhileBuildingModel = ""; eventBus.post(new EmbeddingModelBuiltEvent()); @@ -82,7 +82,7 @@ public void startRebuildingTask() { .onFailure(e -> { LOGGER.error("An error occurred while building the embedding model", e); notificationService.notify(Localization.lang("An error occurred while building the embedding model")); - errorWhileBuildingModel = e.getMessage(); + errorWhileBuildingModel = e.getMessage() == null ? "" : e.getMessage(); eventBus.post(new EmbeddingModelBuildingErrorEvent()); }) .executeWith(taskExecutor); diff --git a/jablib/src/main/java/org/jabref/logic/ai/util/MVStoreBase.java b/jablib/src/main/java/org/jabref/logic/ai/util/MVStoreBase.java index 4a46ab87c20..86a3d21c20a 100644 --- a/jablib/src/main/java/org/jabref/logic/ai/util/MVStoreBase.java +++ b/jablib/src/main/java/org/jabref/logic/ai/util/MVStoreBase.java @@ -8,7 +8,7 @@ import org.h2.mvstore.MVStore; import org.h2.mvstore.MVStoreException; -import org.jspecify.annotations.Nullable; +import org.jspecify.annotations.NonNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -17,7 +17,7 @@ public abstract class MVStoreBase implements AutoCloseable { protected MVStore mvStore; - public MVStoreBase(@Nullable Path path, NotificationService dialogService) { + public MVStoreBase(@NonNull Path path, NotificationService dialogService) { Path mvStorePath = path; try { diff --git a/jablib/src/main/java/org/jabref/model/database/BibDatabaseContext.java b/jablib/src/main/java/org/jabref/model/database/BibDatabaseContext.java index d031935936b..0f3661f6c09 100644 --- a/jablib/src/main/java/org/jabref/model/database/BibDatabaseContext.java +++ b/jablib/src/main/java/org/jabref/model/database/BibDatabaseContext.java @@ -32,6 +32,7 @@ import org.jabref.model.study.Study; import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -62,9 +63,12 @@ public class BibDatabaseContext { /** * The path where this database was last saved to. */ + @Nullable private Path path; + @Nullable private DatabaseSynchronizer dbmsSynchronizer; + @Nullable private CoarseChangeFilter dbmsListener; private DatabaseLocation location; @@ -223,10 +227,15 @@ private Path getFileDirectoryPath(String directory) { // If this path is relative, we try to interpret it as relative to the file path of this BIB file: return getDatabasePath() - .map(databaseFile -> databaseFile.getParent().resolve(path).normalize().toAbsolutePath()) + .map(databaseFile -> Optional.ofNullable(databaseFile.getParent()) + .orElse(Path.of("")) + .resolve(path) + .normalize() + .toAbsolutePath()) .orElse(path); } + @Nullable public DatabaseSynchronizer getDBMSSynchronizer() { return this.dbmsSynchronizer; } @@ -250,7 +259,9 @@ public void convertToSharedDatabase(DatabaseSynchronizer dmbsSynchronizer) { public void convertToLocalDatabase() { if (dbmsListener != null && (location == DatabaseLocation.SHARED)) { - dbmsListener.unregisterListener(dbmsSynchronizer); + if (dbmsSynchronizer != null) { + dbmsListener.unregisterListener(dbmsSynchronizer); + } dbmsListener.shutdown(); } diff --git a/jablib/src/test/java/org/jabref/model/database/BibDatabaseContextTest.java b/jablib/src/test/java/org/jabref/model/database/BibDatabaseContextTest.java index b4f61c9e1b7..6c393edd405 100644 --- a/jablib/src/test/java/org/jabref/model/database/BibDatabaseContextTest.java +++ b/jablib/src/test/java/org/jabref/model/database/BibDatabaseContextTest.java @@ -29,7 +29,6 @@ import static org.mockito.Mockito.when; class BibDatabaseContextTest { - private Path currentWorkingDir; private FilePreferences fileDirPrefs; From a841094d81ab27d2fc509cc215e87081cdb0c677 Mon Sep 17 00:00:00 2001 From: Carl Christian Snethlage Date: Sun, 19 Oct 2025 18:11:12 +0200 Subject: [PATCH 2/4] Remove artifact --- .../model/entry/field/StandardField.java | 33 +++++-------------- 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/jablib/src/main/java/org/jabref/model/entry/field/StandardField.java b/jablib/src/main/java/org/jabref/model/entry/field/StandardField.java index de6ff851511..68cb4865586 100644 --- a/jablib/src/main/java/org/jabref/model/entry/field/StandardField.java +++ b/jablib/src/main/java/org/jabref/model/entry/field/StandardField.java @@ -34,7 +34,7 @@ public enum StandardField implements Field { DATE("date", FieldProperty.DATE), DAY("day"), DAYFILED("dayfiled"), - DOI("doi", "DOI", FieldProperty.VERBATIM, FieldProperty.IDENTIFIER), + DOI("doi", FieldProperty.VERBATIM, FieldProperty.IDENTIFIER), EDITION("edition", FieldProperty.NUMERIC), EDITOR("editor", FieldProperty.PERSON_NAMES), EDITORA("editora", FieldProperty.PERSON_NAMES), @@ -64,9 +64,9 @@ public enum StandardField implements Field { IDS("ids", FieldProperty.MULTIPLE_ENTRY_LINK), INSTITUTION("institution"), INTRODUCTION("introduction", FieldProperty.PERSON_NAMES), - ISBN("isbn", "ISBN", FieldProperty.VERBATIM), - ISRN("isrn", "ISRN", FieldProperty.VERBATIM), - ISSN("issn", "ISSN", FieldProperty.VERBATIM), + ISBN("isbn", FieldProperty.VERBATIM), + ISRN("isrn", FieldProperty.VERBATIM), + ISSN("issn", FieldProperty.VERBATIM), ISSUE("issue"), ISSUETITLE("issuetitle"), ISSUESUBTITLE("issuesubtitle"), @@ -96,9 +96,9 @@ public enum StandardField implements Field { PAGETOTAL("pagetotal", FieldProperty.NUMERIC), PAGINATION("pagination", FieldProperty.PAGINATION), PART("part"), - PDF("pdf", "PDF"), - PMID("pmid", "PMID", FieldProperty.NUMERIC, FieldProperty.IDENTIFIER), - PS("ps", "PS"), + PDF("pdf"), + PMID("pmid", FieldProperty.NUMERIC, FieldProperty.IDENTIFIER), + PS("ps"), PUBLISHER("publisher"), PUBSTATE("pubstate"), PRIMARYCLASS("primaryclass"), @@ -118,8 +118,8 @@ public enum StandardField implements Field { TITLEADDON("titleaddon"), TRANSLATOR("translator", FieldProperty.PERSON_NAMES), TYPE("type"), - URI("uri", "URI", FieldProperty.EXTERNAL, FieldProperty.VERBATIM), - URL("url", "URL", FieldProperty.EXTERNAL, FieldProperty.VERBATIM), + URI("uri", FieldProperty.EXTERNAL, FieldProperty.VERBATIM), + URL("url", FieldProperty.EXTERNAL, FieldProperty.VERBATIM), URLDATE("urldate", FieldProperty.DATE), VENUE("venue"), VERSION("version"), @@ -152,7 +152,6 @@ public enum StandardField implements Field { private static final Map NAME_TO_STANDARD_FIELD = new HashMap<>(); private final String name; - private final String displayName; private final EnumSet properties; static { @@ -163,25 +162,11 @@ public enum StandardField implements Field { StandardField(String name) { this.name = name; - this.displayName = null; this.properties = EnumSet.noneOf(FieldProperty.class); } - StandardField(String name, String displayName) { - this.name = name; - this.displayName = displayName; - this.properties = EnumSet.noneOf(FieldProperty.class); - } - - StandardField(String name, String displayName, FieldProperty first, FieldProperty... rest) { - this.name = name; - this.displayName = displayName; - this.properties = EnumSet.of(first, rest); - } - StandardField(String name, FieldProperty first, FieldProperty... rest) { this.name = name; - this.displayName = null; this.properties = EnumSet.of(first, rest); } From e73dac9336a5f7461db6d5e6822e06bd57fb61ad Mon Sep 17 00:00:00 2001 From: Carl Christian Snethlage Date: Sun, 19 Oct 2025 19:35:01 +0200 Subject: [PATCH 3/4] Fix nullwarnings in FetcherException ISIDOREFetcher and ResearchGate --- .../jabref/logic/importer/FetcherException.java | 8 ++++++-- .../logic/importer/fetcher/ISIDOREFetcher.java | 2 +- .../logic/importer/fetcher/ResearchGate.java | 16 +++++++++------- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/jablib/src/main/java/org/jabref/logic/importer/FetcherException.java b/jablib/src/main/java/org/jabref/logic/importer/FetcherException.java index f5c77333fb4..980211d9ddb 100644 --- a/jablib/src/main/java/org/jabref/logic/importer/FetcherException.java +++ b/jablib/src/main/java/org/jabref/logic/importer/FetcherException.java @@ -9,6 +9,7 @@ import org.jabref.model.http.SimpleHttpResponse; import org.jabref.model.strings.StringUtil; +import org.jspecify.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -18,10 +19,13 @@ public class FetcherException extends JabRefException { private static final Pattern API_KEY_PATTERN = Pattern.compile("(?i)(?<" + API_KEY_PARAM_NAME + ">api|key|api[-_]?key)=[^&]*"); private static final String REDACTED_STRING = "[REDACTED]"; + @Nullable private final String url; + + @Nullable private final SimpleHttpResponse httpResponse; - public FetcherException(String url, SimpleHttpResponse httpResponse) { + public FetcherException(@Nullable String url, @Nullable SimpleHttpResponse httpResponse) { // Empty string handled at org.jabref.logic.importer.FetcherException.getPrefix. super(""); this.url = url; @@ -87,7 +91,7 @@ public String getLocalizedMessage() { } String getRedactedUrl() { - return getRedactedUrl(url); + return getRedactedUrl(url == null ? "" : url); } public static String getRedactedUrl(String source) { diff --git a/jablib/src/main/java/org/jabref/logic/importer/fetcher/ISIDOREFetcher.java b/jablib/src/main/java/org/jabref/logic/importer/fetcher/ISIDOREFetcher.java index 9712b7c14ad..8286a3ebb37 100644 --- a/jablib/src/main/java/org/jabref/logic/importer/fetcher/ISIDOREFetcher.java +++ b/jablib/src/main/java/org/jabref/logic/importer/fetcher/ISIDOREFetcher.java @@ -82,7 +82,7 @@ public Parser getParser() { } catch (ParserConfigurationException | IOException | SAXException e) { Unchecked.throwChecked(new FetcherException("Issue with parsing link", e)); } - return null; + return List.of(); }; } diff --git a/jablib/src/main/java/org/jabref/logic/importer/fetcher/ResearchGate.java b/jablib/src/main/java/org/jabref/logic/importer/fetcher/ResearchGate.java index e1e6b5da870..d41b8a8317f 100644 --- a/jablib/src/main/java/org/jabref/logic/importer/fetcher/ResearchGate.java +++ b/jablib/src/main/java/org/jabref/logic/importer/fetcher/ResearchGate.java @@ -221,7 +221,7 @@ public List performSearch(BaseQueryNode queryNode) throws FetcherExcep html = getPage(url); // ResearchGate's server blocks when too many request are made if (!html.getElementsByClass("nova-legacy-v-publication-item__title").hasText()) { - throw new FetcherException(url, "Required HTML element not found", null); + throw new FetcherException(url, "Required HTML element not found", new IllegalStateException("Missing element")); } } catch (IOException e) { throw new FetcherException(url, e); @@ -230,11 +230,13 @@ public List performSearch(BaseQueryNode queryNode) throws FetcherExcep Elements sol = html.getElementsByClass("nova-legacy-v-publication-item__title"); List urls = sol.select("a").eachAttr("href").stream() .filter(stream -> stream.contains("publication/")) - .map(resultStream -> resultStream.substring(resultStream.indexOf("publication/") + 12, resultStream.indexOf("_"))) + .map(resultStream -> resultStream.substring( + resultStream.indexOf("publication/") + 12, + resultStream.indexOf("_"))) .map(idStream -> SEARCH_FOR_BIB_ENTRY + idStream) .map(this::getInputStream) - .filter(Objects::nonNull) - .map(stream -> stream.lines().collect(Collectors.joining(OS.NEWLINE))) + .flatMap(Optional::stream) + .map(reader -> reader.lines().collect(Collectors.joining(OS.NEWLINE))) .toList(); List list = new ArrayList<>(); @@ -251,14 +253,14 @@ public List performSearch(BaseQueryNode queryNode) throws FetcherExcep return list; } - private BufferedReader getInputStream(String urlString) { + private Optional getInputStream(String urlString) { try { URL url = URLUtil.create(urlString); - return new BufferedReader(new InputStreamReader(url.openStream())); + return Optional.of(new BufferedReader(new InputStreamReader(url.openStream()))); } catch (IOException e) { LOGGER.debug("Wrong URL", e); + return Optional.empty(); } - return null; } @Override From ef3f58ad9e9023185d80be4716a96f26e7b5210c Mon Sep 17 00:00:00 2001 From: Carl Christian Snethlage Date: Sun, 19 Oct 2025 21:45:41 +0200 Subject: [PATCH 4/4] Undo newline --- .../java/org/jabref/model/database/BibDatabaseContextTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/jablib/src/test/java/org/jabref/model/database/BibDatabaseContextTest.java b/jablib/src/test/java/org/jabref/model/database/BibDatabaseContextTest.java index 6c393edd405..b4f61c9e1b7 100644 --- a/jablib/src/test/java/org/jabref/model/database/BibDatabaseContextTest.java +++ b/jablib/src/test/java/org/jabref/model/database/BibDatabaseContextTest.java @@ -29,6 +29,7 @@ import static org.mockito.Mockito.when; class BibDatabaseContextTest { + private Path currentWorkingDir; private FilePreferences fileDirPrefs;