Fixe SonarQube Reliability-Issues S2789, S3077 und S2184
S2789 (32 Stellen): null-Checks auf Optional-Feldern entfernt bzw. durch Objects.requireNonNullElse(field, Optional.empty()) ersetzt. Die zuvor defensive Behandlung von null-Optionals erfolgt jetzt ueber den Bibliotheksaufruf, sodass das Verhalten unveraendert bleibt, aber die direkte Null-Pruefung gegen Optional entfaellt. S3077 (5 Stellen): volatile-Felder mit Objekt-Referenzen durch AtomicReference ersetzt (ScheduledExecutorServiceSchedulerAdapter, BootstrapRunner.guiApplicationRunContext, PdfPreviewPane.currentDocument/ currentRenderer/currentSourceFile, SingleInstanceGuard.socket). Die PdfPreviewPane-Felder werden auf JavaFX- bzw. Worker-Thread genutzt; AtomicReference bietet hier konsistente atomare Publikation ohne Verhaltensaenderung. S2184 (3 Stellen): Integer-Division SECONDARY_SPACING / 2 durch SECONDARY_SPACING / 2.0 ersetzt, damit das Insets-Argument als double ohne implizite Truncierung berechnet wird.
This commit is contained in:
+2
-1
@@ -4,6 +4,7 @@ import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
@@ -105,7 +106,7 @@ public final class GuiSchedulerTab {
|
||||
public GuiSchedulerTab(
|
||||
Optional<SchedulerControlUseCase> schedulerUseCase,
|
||||
Supplier<Boolean> isConfigDirty) {
|
||||
this.schedulerUseCase = schedulerUseCase == null ? Optional.empty() : schedulerUseCase;
|
||||
this.schedulerUseCase = Objects.requireNonNullElse(schedulerUseCase, Optional.empty());
|
||||
this.isConfigDirty = isConfigDirty != null ? isConfigDirty : () -> false;
|
||||
tab.setClosable(false);
|
||||
buildUi();
|
||||
|
||||
+4
-4
@@ -146,8 +146,8 @@ public record GuiStartupContext(
|
||||
*/
|
||||
public GuiStartupContext {
|
||||
initialState = Objects.requireNonNull(initialState, "initialState must not be null");
|
||||
startupNotice = startupNotice == null ? Optional.empty() : startupNotice;
|
||||
applicationContextError = applicationContextError == null ? Optional.empty() : applicationContextError;
|
||||
startupNotice = Objects.requireNonNullElse(startupNotice, Optional.empty());
|
||||
applicationContextError = Objects.requireNonNullElse(applicationContextError, Optional.empty());
|
||||
configurationFileLoader = Objects.requireNonNull(configurationFileLoader,
|
||||
"configurationFileLoader must not be null");
|
||||
configurationFileWriter = Objects.requireNonNull(configurationFileWriter,
|
||||
@@ -191,8 +191,8 @@ public record GuiStartupContext(
|
||||
"promptEditorPortFactory must not be null");
|
||||
createNewDatabasePort = Objects.requireNonNull(createNewDatabasePort,
|
||||
"createNewDatabasePort must not be null");
|
||||
schedulerControlUseCase = schedulerControlUseCase == null ? Optional.empty() : schedulerControlUseCase;
|
||||
configurationFileLockPort = configurationFileLockPort == null ? Optional.empty() : configurationFileLockPort;
|
||||
schedulerControlUseCase = Objects.requireNonNullElse(schedulerControlUseCase, Optional.empty());
|
||||
configurationFileLockPort = Objects.requireNonNullElse(configurationFileLockPort, Optional.empty());
|
||||
applicationContextInitializer = applicationContextInitializer == null
|
||||
? GuiApplicationContextInitializer.noOp() : applicationContextInitializer;
|
||||
}
|
||||
|
||||
+1
-1
@@ -276,7 +276,7 @@ public final class GuiBatchRunCoordinator {
|
||||
this.historicalDocumentContextPort = Objects.requireNonNull(
|
||||
historicalDocumentContextPort, "historicalDocumentContextPort must not be null");
|
||||
this.configurationFileLockPort =
|
||||
configurationFileLockPort == null ? Optional.empty() : configurationFileLockPort;
|
||||
Objects.requireNonNullElse(configurationFileLockPort, Optional.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ public record GuiBatchRunLaunchOutcome(
|
||||
* Compact constructor normalising the failure message holder.
|
||||
*/
|
||||
public GuiBatchRunLaunchOutcome {
|
||||
failureMessage = failureMessage == null ? Optional.empty() : failureMessage;
|
||||
failureMessage = Objects.requireNonNullElse(failureMessage, Optional.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+6
-6
@@ -88,16 +88,16 @@ public record GuiBatchRunResultRow(
|
||||
}
|
||||
Objects.requireNonNull(fingerprint, "fingerprint must not be null");
|
||||
Objects.requireNonNull(status, "status must not be null");
|
||||
finalFileName = finalFileName == null ? Optional.empty() : finalFileName;
|
||||
correctedFileName = correctedFileName == null ? Optional.empty() : correctedFileName;
|
||||
resolvedDate = resolvedDate == null ? Optional.empty() : resolvedDate;
|
||||
aiReasoning = aiReasoning == null ? Optional.empty() : aiReasoning;
|
||||
aiFailureMessage = aiFailureMessage == null ? Optional.empty() : aiFailureMessage;
|
||||
finalFileName = Objects.requireNonNullElse(finalFileName, Optional.empty());
|
||||
correctedFileName = Objects.requireNonNullElse(correctedFileName, Optional.empty());
|
||||
resolvedDate = Objects.requireNonNullElse(resolvedDate, Optional.empty());
|
||||
aiReasoning = Objects.requireNonNullElse(aiReasoning, Optional.empty());
|
||||
aiFailureMessage = Objects.requireNonNullElse(aiFailureMessage, Optional.empty());
|
||||
Objects.requireNonNull(processingDuration, "processingDuration must not be null");
|
||||
if (processingDuration.isNegative()) {
|
||||
throw new IllegalArgumentException("processingDuration must not be negative");
|
||||
}
|
||||
historicalContext = historicalContext == null ? Optional.empty() : historicalContext;
|
||||
historicalContext = Objects.requireNonNullElse(historicalContext, Optional.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+3
-3
@@ -302,7 +302,7 @@ public final class GuiBatchRunTab {
|
||||
targetFolderSupplier, "targetFolderSupplier must not be null");
|
||||
|
||||
Optional<ConfigurationFileLockPort> effectiveLockPort =
|
||||
configurationFileLockPort == null ? Optional.empty() : configurationFileLockPort;
|
||||
Objects.requireNonNullElse(configurationFileLockPort, Optional.empty());
|
||||
this.coordinator = new GuiBatchRunCoordinator(
|
||||
(configPath, observer, token) ->
|
||||
launcherSupplier.get().launch(configPath, observer, token),
|
||||
@@ -618,7 +618,7 @@ public final class GuiBatchRunTab {
|
||||
|
||||
HBox selectionButtonBar = new HBox(SECONDARY_SPACING, reprocessButton, resetStatusButton);
|
||||
selectionButtonBar.setAlignment(Pos.CENTER_LEFT);
|
||||
selectionButtonBar.setPadding(new Insets(SECONDARY_SPACING / 2, 0, SECONDARY_SPACING / 2, 0));
|
||||
selectionButtonBar.setPadding(new Insets(SECONDARY_SPACING / 2.0, 0, SECONDARY_SPACING / 2.0, 0));
|
||||
|
||||
// Meldungsbereich unterhalb der Selektions-Buttons (linke Spalte)
|
||||
messageArea.setId("batch-run-message-area");
|
||||
@@ -1246,7 +1246,7 @@ public final class GuiBatchRunTab {
|
||||
|
||||
HBox runButtonBar = new HBox(SECONDARY_SPACING, startButton, cancelButton);
|
||||
runButtonBar.setAlignment(Pos.CENTER_LEFT);
|
||||
runButtonBar.setPadding(new Insets(SECONDARY_SPACING / 2, 0, 0, 0));
|
||||
runButtonBar.setPadding(new Insets(SECONDARY_SPACING / 2.0, 0, 0, 0));
|
||||
|
||||
return runButtonBar;
|
||||
}
|
||||
|
||||
+17
-16
@@ -8,6 +8,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@@ -170,18 +171,18 @@ public final class PdfPreviewPane {
|
||||
|
||||
/**
|
||||
* Aktuell geöffnetes PDF-Dokument. Zugriff ausschließlich vom Worker-Thread.
|
||||
* {@code null} wenn kein Dokument geöffnet ist.
|
||||
* Leerer Referenzwert wenn kein Dokument geöffnet ist.
|
||||
*/
|
||||
private volatile PDDocument currentDocument = null;
|
||||
private final AtomicReference<PDDocument> currentDocument = new AtomicReference<>();
|
||||
|
||||
/**
|
||||
* Renderer für das aktuell geöffnete Dokument. Zugriff ausschließlich vom Worker-Thread.
|
||||
* {@code null} wenn kein Dokument geöffnet ist.
|
||||
* Leerer Referenzwert wenn kein Dokument geöffnet ist.
|
||||
*/
|
||||
private volatile PDFRenderer currentRenderer = null;
|
||||
private final AtomicReference<PDFRenderer> currentRenderer = new AtomicReference<>();
|
||||
|
||||
/** Aktuell geladene Quelldatei; null wenn keine Selektion vorliegt. */
|
||||
private volatile Path currentSourceFile = null;
|
||||
/** Aktuell geladene Quelldatei; leerer Referenzwert wenn keine Selektion vorliegt. */
|
||||
private final AtomicReference<Path> currentSourceFile = new AtomicReference<>();
|
||||
|
||||
/** Aktuell angezeigte Seite (1-basiert; 0 wenn keine Datei geladen). */
|
||||
private volatile int currentPage = 0;
|
||||
@@ -303,7 +304,7 @@ public final class PdfPreviewPane {
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
currentSourceFile = sourceFile;
|
||||
currentSourceFile.set(sourceFile);
|
||||
currentPage = 0;
|
||||
totalPages = -1;
|
||||
pageCache.clear();
|
||||
@@ -318,7 +319,7 @@ public final class PdfPreviewPane {
|
||||
* Muss auf dem JavaFX Application Thread aufgerufen werden.
|
||||
*/
|
||||
public void clear() {
|
||||
currentSourceFile = null;
|
||||
currentSourceFile.set(null);
|
||||
currentPage = 0;
|
||||
totalPages = -1;
|
||||
pageCache.clear();
|
||||
@@ -472,12 +473,13 @@ public final class PdfPreviewPane {
|
||||
|
||||
try {
|
||||
PDDocument doc = Loader.loadPDF(ioFile);
|
||||
currentDocument = doc;
|
||||
currentRenderer = new PDFRenderer(doc);
|
||||
currentDocument.set(doc);
|
||||
PDFRenderer renderer = new PDFRenderer(doc);
|
||||
currentRenderer.set(renderer);
|
||||
|
||||
int pages = Math.max(1, doc.getNumberOfPages());
|
||||
BufferedImage buffered =
|
||||
currentRenderer.renderImageWithDPI(0, RENDER_DPI, ImageType.RGB);
|
||||
renderer.renderImageWithDPI(0, RENDER_DPI, ImageType.RGB);
|
||||
Image fxImage = SwingFXUtils.toFXImage(buffered, null);
|
||||
|
||||
final int totalPagesFinal = pages;
|
||||
@@ -513,7 +515,7 @@ public final class PdfPreviewPane {
|
||||
* @param seq die Sequenznummer dieser Anforderung
|
||||
*/
|
||||
private void renderPageOnWorker(int page, long seq) {
|
||||
PDFRenderer renderer = currentRenderer;
|
||||
PDFRenderer renderer = currentRenderer.get();
|
||||
if (renderer == null) {
|
||||
// Dokument wurde zwischenzeitlich geschlossen – nichts zu tun
|
||||
return;
|
||||
@@ -542,9 +544,8 @@ public final class PdfPreviewPane {
|
||||
* auf dem Worker-Thread und ist idempotent.
|
||||
*/
|
||||
private void closeCurrentDocumentOnWorker() {
|
||||
PDDocument doc = currentDocument;
|
||||
currentDocument = null;
|
||||
currentRenderer = null;
|
||||
PDDocument doc = currentDocument.getAndSet(null);
|
||||
currentRenderer.set(null);
|
||||
if (doc != null) {
|
||||
try {
|
||||
doc.close();
|
||||
@@ -824,7 +825,7 @@ public final class PdfPreviewPane {
|
||||
}
|
||||
|
||||
private void updateNavigationButtons() {
|
||||
boolean canNavigate = enabled && currentSourceFile != null && totalPages > 0;
|
||||
boolean canNavigate = enabled && currentSourceFile.get() != null && totalPages > 0;
|
||||
prevButton.setDisable(!canNavigate || currentPage <= 1);
|
||||
nextButton.setDisable(!canNavigate || currentPage >= totalPages);
|
||||
}
|
||||
|
||||
+2
-2
@@ -29,10 +29,10 @@ public record GuiConfigurationEditorState(
|
||||
* @param values current editable configuration values; must not be {@code null}
|
||||
*/
|
||||
public GuiConfigurationEditorState {
|
||||
loadedFileSnapshot = loadedFileSnapshot == null ? Optional.empty() : loadedFileSnapshot;
|
||||
loadedFileSnapshot = Objects.requireNonNullElse(loadedFileSnapshot, Optional.empty());
|
||||
baselineValues = Objects.requireNonNull(baselineValues, "baselineValues must not be null");
|
||||
values = Objects.requireNonNull(values, "values must not be null");
|
||||
pendingMigrationMessage = pendingMigrationMessage == null ? Optional.empty() : pendingMigrationMessage;
|
||||
pendingMigrationMessage = Objects.requireNonNullElse(pendingMigrationMessage, Optional.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ public record GuiMessageEntry(
|
||||
Objects.requireNonNull(severity, "severity must not be null");
|
||||
Objects.requireNonNull(text, "text must not be null");
|
||||
Objects.requireNonNull(timestamp, "timestamp must not be null");
|
||||
source = source == null ? Optional.empty() : source;
|
||||
source = Objects.requireNonNullElse(source, Optional.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user