Skip to content

Model#40

Closed
Linsss123 wants to merge 9 commits intomainfrom
Model
Closed

Model#40
Linsss123 wants to merge 9 commits intomainfrom
Model

Conversation

@Linsss123
Copy link

@Linsss123 Linsss123 commented Nov 19, 2025

Summary by CodeRabbit

  • New Features

    • Messaging: send and receive messages with live updates and formatted timestamps.
    • UI: message input field, "Send message" button, and a list view showing message history.
  • Tests

    • Added unit and integration tests for send/receive flows and message parsing.
  • Chores

    • .env now excluded from version control; project dependencies updated to support network, JSON, UI, logging and testing.

@coderabbitai
Copy link

coderabbitai bot commented Nov 19, 2025

Walkthrough

Adds ntfy-based messaging: new NtfyConnection interface, HttpClient implementation and DTO; model/controller/FXML wired for send/receive; dotenv environment loading and .env ignored; Maven/module dependency additions; and new unit/integration tests (WireMock + test spy).

Changes

Cohort / File(s) Summary
Repo & Build
\.gitignore, pom.xml, src/main/java/module-info.java
Added .env to .gitignore; added dependencies io.github.cdimascio:dotenv-java:3.2.0, tools.jackson.core:jackson-databind:3.0.1, org.openjfx:javafx-swing:26-ea+16, org.slf4j:slf4j-api:2.0.17, and test org.wiremock:wiremock:4.0.0-beta.15 to pom.xml; module requires added for dotenv, java.net.http, Jackson, and javafx.graphics.
Messaging API & Impl
src/main/java/com/example/NtfyConnection.java, src/main/java/com/example/NtfyConnectionImpl.java, src/main/java/com/example/NtfyMessageDto.java
New NtfyConnection interface (send/receive); NtfyConnectionImpl implements HTTP POST /mytopic and streaming GET /mytopic/json using HttpClient and Jackson; NtfyMessageDto record added with @JsonIgnoreProperties.
Model
src/main/java/com/example/HelloModel.java
Model now accepts NtfyConnection (constructors), exposes ObservableList<NtfyMessageDto> messages and StringProperty messageToSend, and provides sendMessage() and receiveMessage() using a UI executor (default Platform::runLater) to update UI-bound state.
Controller & UI
src/main/java/com/example/HelloController.java, src/main/resources/com/example/hello-view.fxml
Controller creates HelloModel(new NtfyConnectionImpl()), exposes messageView and messageInput, binds view and model, sets custom cell factory, and adds sendMessage(ActionEvent); FXML root changed to VBox, added Button (onAction), ListView (fx:id="messageView"), and TextField (fx:id="messageInput").
App Startup / Env
src/main/java/com/example/HelloFX.java
Loads environment with Dotenv at startup, reads HOST_NAME and prints it if present.
Tests
src/test/java/com/example/HelloModelTest.java, src/test/java/com/example/NtfyConnectionSpy.java
Added NtfyConnectionSpy test double and HelloModelTest with unit and WireMock-based integration tests covering send/receive and JSON parsing behavior.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UI as HelloController
    participant Model as HelloModel
    participant Conn as NtfyConnectionImpl
    participant Server as NTFY HTTP

    User->>UI: Click "Send message"
    UI->>Model: sendMessage()
    Model->>Conn: sendMessage(messageToSend)
    Conn->>Server: POST /mytopic (body: message)
    Server-->>Conn: 200 OK
    Conn-->>Model: return true
    Model->>Model: clear messageToSend (UI-bound)

    Note right of Conn `#E8F0FE`: Streaming receive (async)
    Model->>Conn: receiveMessage(handler)
    Conn->>Server: GET /mytopic/json (stream)
    loop per event line
        Server-->>Conn: JSON line
        Conn->>Conn: deserialize -> NtfyMessageDto
        Conn->>Model: handler.accept(message)
        Model->>Model: uiExecutor.run() -> add to messages list
        Model-->>UI: ListView updates (binding)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Pay extra attention to:
    • NtfyConnectionImpl.receiveMessage(): async stream handling, resource lifecycle, cancellation, and exception paths.
    • Threading and use of UI executor (Platform.runLater) to avoid JavaFX thread blocking.
    • HTTP synchronous POST error handling and interruption handling in sendMessage().
    • Jackson deserialization and robust handling of unexpected JSON lines.
    • Tests relying on async timing and WireMock stubs (possible flakiness).

Possibly related PRs

Poem

🐰
I hopped a message through the stream tonight,
From textbox to POST by soft moonlight;
JSON crumbs parsed and sent along the trail,
Dotenv showed the path, the ListView wagged its tail,
The rabbit clicked send — and watched the UI light.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.35% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'Model' is vague and generic. It does not clearly convey the specific changes being made (e.g., implementing model-view architecture, adding connection handling, or refactoring UI bindings). Use a more descriptive title that captures the main objective, such as 'Implement Model class with NtfyConnection for message handling' or 'Add model layer with messaging functionality'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai
Copy link

coderabbitai bot commented Nov 19, 2025

Note

Unit test generation is an Early Access feature. Expect some limitations and changes as we gather feedback and continue to improve it.


Generating unit tests... This may take up to 20 minutes.

@coderabbitai
Copy link

coderabbitai bot commented Nov 19, 2025

Caution

The CodeRabbit agent failed during execution: Clone operation failed

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (8)
src/test/java/com/example/HelloModelTest.java (1)

29-40: Integration test correctly verifies HTTP interaction.

The test properly uses WireMock to stub the endpoint and verify the request body. The test structure is sound.

Consider adding a @DisplayName annotation to match the first test's documentation style:

    @Test
+    @DisplayName("When sending message it should POST to /mytopic with message body")
    void sendMessageToFakeServer(WireMockRuntimeInfo wireMockRuntimeInfo) {
src/main/java/com/example/HelloController.java (1)

13-13: Consider handling potential initialization failures.

Creating NtfyConnectionImpl directly in the field initializer provides no opportunity to handle exceptions if environment variables are missing or the connection cannot be established.

Consider moving initialization to a method where failures can be handled:

-    private final HelloModel model = new HelloModel(new NtfyConnectionImpl());
+    private HelloModel model;

Then in initialize():

@FXML
private void initialize() {
    try {
        model = new HelloModel(new NtfyConnectionImpl());
        if (messageLabel != null) {
            messageLabel.setText(model.getGreeting());
        }
        messageView.setItems(model.getMessages());
    } catch (Exception e) {
        // Handle initialization failure
        System.err.println("Failed to initialize: " + e.getMessage());
    }
}
pom.xml (1)

58-63: Consider upgrading to stable WireMock 3.13.2.

The latest stable version of org.wiremock:wiremock is 3.13.2 (released Nov 14, 2025). Your pom.xml currently specifies the beta version 4.0.0-beta.15. While test-scoped, beta dependencies risk API changes. Use the stable 3.13.2 release unless you specifically require features from 4.0.0.

src/test/java/com/example/NtfyConnectionSpy.java (1)

7-7: Add a getter for the message field to support test assertions.

The message field stores the last sent message but lacks a public accessor, making it difficult to verify the sent message in test assertions.

Apply this diff to add a getter:

     String message;
 
+    public String getMessage() {
+        return message;
+    }
+
     @Override
     public boolean sendMessage(String message) {
src/main/java/com/example/NtfyConnection.java (1)

7-9: Consider removing redundant public modifiers.

Interface methods are implicitly public in Java, so the explicit public modifier is redundant.

Apply this diff:

-    public boolean sendMessage(String message);
+    boolean sendMessage(String message);
 
-    public void receiveMessage(Consumer<NtfyMessageDto> messageHandler);
+    void receiveMessage(Consumer<NtfyMessageDto> messageHandler);
src/main/java/com/example/NtfyConnectionImpl.java (1)

4-4: Remove unused import.

The Platform import is not used anywhere in this file.

Apply this diff:

 import io.github.cdimascio.dotenv.Dotenv;
-import javafx.application.Platform;
 import tools.jackson.databind.ObjectMapper;
src/main/java/com/example/HelloModel.java (2)

3-18: Remove unused imports.

Several imports are not used in this file: JsonIgnoreProperties, Dotenv, ObjectMapper, IOException, URI, HttpClient, HttpRequest, HttpResponse, ArrayList, and Objects.

Apply this diff to clean up the imports:

 package com.example;
 
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import io.github.cdimascio.dotenv.Dotenv;
 import javafx.application.Platform;
 import javafx.beans.property.SimpleStringProperty;
 import javafx.beans.property.StringProperty;
 import javafx.collections.FXCollections;
 import javafx.collections.ObservableList;
-import tools.jackson.databind.ObjectMapper;
-
-import java.io.IOException;
-import java.net.URI;
-import java.net.http.HttpClient;
-import java.net.http.HttpRequest;
-import java.net.http.HttpResponse;
-import java.util.ArrayList;
-import java.util.Objects;

59-61: Handle the send result and clear the message field.

The method ignores the boolean return value from connection.sendMessage(), providing no feedback if the send fails. Additionally, the messageToSend field is not cleared after sending, which may confuse users.

Consider handling the result and clearing the field:

     public void sendMessage() {
-        connection.sendMessage(messageToSend.get());
+        boolean success = connection.sendMessage(messageToSend.get());
+        if (success) {
+            messageToSend.set("");
+        } else {
+            // Consider adding error handling or user notification
+            System.err.println("Failed to send message");
+        }
     }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7221be6 and 83dbcef.

📒 Files selected for processing (12)
  • .gitignore (1 hunks)
  • pom.xml (1 hunks)
  • src/main/java/com/example/HelloController.java (2 hunks)
  • src/main/java/com/example/HelloFX.java (2 hunks)
  • src/main/java/com/example/HelloModel.java (2 hunks)
  • src/main/java/com/example/NtfyConnection.java (1 hunks)
  • src/main/java/com/example/NtfyConnectionImpl.java (1 hunks)
  • src/main/java/com/example/NtfyMessageDto.java (1 hunks)
  • src/main/java/module-info.java (1 hunks)
  • src/main/resources/com/example/hello-view.fxml (1 hunks)
  • src/test/java/com/example/HelloModelTest.java (1 hunks)
  • src/test/java/com/example/NtfyConnectionSpy.java (1 hunks)
🔇 Additional comments (7)
.gitignore (1)

3-3: LGTM! Proper secret management.

Adding .env to version control exclusions is essential for preventing accidental commit of sensitive configuration.

src/main/resources/com/example/hello-view.fxml (1)

5-12: LGTM! UI structure updated correctly.

The migration from StackPane to VBox with added Button and ListView aligns well with the messaging functionality. The fx:id and onAction bindings match the controller's fields and methods.

src/test/java/com/example/HelloModelTest.java (1)

16-27: LGTM! Well-structured unit test.

The test follows AAA pattern and properly isolates the model using a spy. The assertion correctly verifies the delegation behavior.

src/main/java/com/example/NtfyMessageDto.java (1)

1-6: Record structure is correct, but depends on fixing Jackson dependency.

The DTO design is appropriate with @JsonIgnoreProperties(ignoreUnknown = true) for resilient deserialization. However, the import on line 3 (com.fasterxml.jackson.annotation.JsonIgnoreProperties) will fail with the current pom.xml dependency. This will be resolved once the Jackson dependency group ID is corrected.

src/main/java/com/example/HelloController.java (1)

28-30: LGTM! Proper delegation to model layer.

The sendMessage method correctly delegates to the model, maintaining separation of concerns between controller and model layers.

pom.xml (1)

53-57: Remove incorrect assertion about group ID; flag security vulnerability in version 3.0.1.

The group ID tools.jackson.core is actually correct for Jackson 3.0. Jackson 3.0 deliberately migrated the Maven group ID from com.fasterxml.jackson.* to tools.jackson.*. However, the real concern is that jackson-databind 3.0.1 contains a known security vulnerability (CVE-2020-36518 / GHSA-57j2-w4cx-62h2, a nested-object / deep-JSON DoS). Upgrade to version 3.0.2 (released Nov 7, 2025) to resolve this vulnerability.

Likely an incorrect or invalid review comment.

src/main/java/com/example/HelloModel.java (1)

30-33: Verify that calling receiveMessage in the constructor doesn't cause initialization issues.

The constructor immediately calls receiveMessage(), which starts an asynchronous operation that will add items to the messages list. Ensure that any UI components binding to this list are properly initialized before messages start arriving.

Comment on lines +14 to +15
Dotenv dotenv = Dotenv.load();
System.out.println(dotenv.get("HOST_NAME"));
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Handle missing environment variable gracefully.

If HOST_NAME is not defined in .env, dotenv.get() returns null, printing "null" to the console.

Apply this diff to provide a clearer message:

        Dotenv dotenv = Dotenv.load();
-        System.out.println(dotenv.get("HOST_NAME"));
+        String hostName = dotenv.get("HOST_NAME");
+        System.out.println("HOST_NAME: " + (hostName != null ? hostName : "<not set>"));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Dotenv dotenv = Dotenv.load();
System.out.println(dotenv.get("HOST_NAME"));
Dotenv dotenv = Dotenv.load();
String hostName = dotenv.get("HOST_NAME");
System.out.println("HOST_NAME: " + (hostName != null ? hostName : "<not set>"));
🤖 Prompt for AI Agents
In src/main/java/com/example/HelloFX.java around lines 14-15, printing
dotenv.get("HOST_NAME") can output "null" if the variable is missing; change
this to handle missing values gracefully by checking the returned value (or use
a getOrDefault-style approach), and print a clearer message such as "HOST_NAME
not set" or a provided default instead of "null"; ensure the code uses a simple
null-check (or Optional) and logs the human-friendly message.

Comment on lines +32 to +37
//Todo: Send message using HTTPClient

HttpRequest httpRequest = HttpRequest.newBuilder()
.POST(HttpRequest.BodyPublishers.ofString("Hello World"))
.uri(URI.create(hostName + "/mytopic"))
.build();
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: sendMessage ignores the parameter and sends hardcoded text.

The method accepts a message parameter but ignores it, sending "Hello World" instead. This breaks the contract and will cause all messages to be identical.

Apply this diff to use the actual message parameter:

     @Override
     public boolean sendMessage(String message) {
-        //Todo: Send message using HTTPClient
-
         HttpRequest httpRequest = HttpRequest.newBuilder()
-                .POST(HttpRequest.BodyPublishers.ofString("Hello World"))
+                .POST(HttpRequest.BodyPublishers.ofString(message))
                 .uri(URI.create(hostName + "/mytopic"))
                 .build();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
//Todo: Send message using HTTPClient
HttpRequest httpRequest = HttpRequest.newBuilder()
.POST(HttpRequest.BodyPublishers.ofString("Hello World"))
.uri(URI.create(hostName + "/mytopic"))
.build();
@Override
public boolean sendMessage(String message) {
HttpRequest httpRequest = HttpRequest.newBuilder()
.POST(HttpRequest.BodyPublishers.ofString(message))
.uri(URI.create(hostName + "/mytopic"))
.build();
🤖 Prompt for AI Agents
In src/main/java/com/example/NtfyConnectionImpl.java around lines 32 to 37, the
HttpRequest body is hardcoded to "Hello World" instead of using the method's
message parameter; replace the hardcoded string with the actual message (e.g.,
BodyPublishers.ofString(message)), guard against null by defaulting to an empty
string or throwing an IllegalArgumentException, and set an appropriate
Content-Type header (e.g., "text/plain; charset=UTF-8") so the sent payload
correctly reflects the caller's input.

Comment on lines +39 to +42
//Todo: handle long blocking send requests to not freeze the JavaFX thread
//1. Use thread send message?
//2. Use async?
var response = http.send(httpRequest, HttpResponse.BodyHandlers.ofString());
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Address blocking HTTP call on the JavaFX thread.

The synchronous http.send() call will block the calling thread. If this is invoked from the JavaFX Application Thread, it will freeze the UI during the HTTP request.

Consider using sendAsync() instead and returning a CompletableFuture<Boolean>, or offload the work to a background thread. Update the interface signature if needed:

public CompletableFuture<Boolean> sendMessage(String message) {
    HttpRequest httpRequest = HttpRequest.newBuilder()
            .POST(HttpRequest.BodyPublishers.ofString(message))
            .uri(URI.create(hostName + "/mytopic"))
            .build();
    
    return http.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofString())
            .thenApply(response -> true)
            .exceptionally(e -> {
                System.err.println("Error sending message: " + e.getMessage());
                return false;
            });
}
🤖 Prompt for AI Agents
In src/main/java/com/example/NtfyConnectionImpl.java around lines 39 to 42,
replace the blocking HttpClient.send(...) call that can freeze the JavaFX
Application Thread with a non-blocking approach: either switch to
HttpClient.sendAsync(...) and update the method signature to return a
CompletableFuture<Boolean> (mapping successful responses to true and handling
exceptions to return false and log the error), or offload the synchronous call
to a dedicated background thread/executor and return a Future/CompletableFuture;
ensure callers are updated to handle the new asynchronous return type and that
exceptions are properly logged rather than thrown on the UI thread.

requires javafx.fxml;
requires io.github.cdimascio.dotenv.java;
requires java.net.http;
requires tools.jackson.databind;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Update module name after fixing Jackson dependency.

This module name corresponds to the incorrect Jackson group ID in pom.xml. After correcting the dependency to com.fasterxml.jackson.core:jackson-databind, update this to:

-    requires tools.jackson.databind;
+    requires com.fasterxml.jackson.databind;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
requires tools.jackson.databind;
requires com.fasterxml.jackson.databind;
🤖 Prompt for AI Agents
In src/main/java/module-info.java around line 6, the module requires declaration
uses the incorrect module name "tools.jackson.databind"; update it to the
correct Jackson module name "com.fasterxml.jackson.databind" to match the fixed
Maven dependency (com.fasterxml.jackson.core:jackson-databind). Replace the
existing requires entry with the correct module name and verify there are no
other references to the old module name in module-info.java.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

♻️ Duplicate comments (1)
src/main/java/com/example/NtfyConnectionImpl.java (1)

39-42: Blocking HTTP call remains unresolved.

The blocking http.send() call can freeze the JavaFX UI thread, as noted in the TODO comments and previous reviews. While the TODO acknowledges the issue, it should be addressed before production use.

As suggested in the previous review, consider using sendAsync():

public CompletableFuture<Boolean> sendMessage(String message) {
    HttpRequest httpRequest = HttpRequest.newBuilder()
            .header("Content-Type", "text/plain; charset=UTF-8")
            .POST(HttpRequest.BodyPublishers.ofString(message))
            .uri(URI.create(hostName + "/mytopic"))
            .build();
    
    return http.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofString())
            .thenApply(response -> response.statusCode() == 200)
            .exceptionally(e -> {
                System.err.println("Error sending message: " + e.getMessage());
                return false;
            });
}

Update the interface signature and callers accordingly.

🧹 Nitpick comments (10)
src/test/java/com/example/HelloModelTest.java (1)

29-43: Add @DisplayName for consistency and clarify test scope.

The GET stub on line 31 is necessary because HelloModel's constructor calls receiveMessage(), which initiates an HTTP GET stream. However, the test only verifies the POST behavior. Consider adding a @DisplayName annotation for consistency with the first test and potentially splitting this into separate tests for send and receive behaviors.

Apply this diff to add a display name:

     @Test
+    @DisplayName("When calling sendMessage it should POST to the fake server")
     void sendMessageToFakeServer(WireMockRuntimeInfo wireMockRuntimeInfo) {
src/main/java/com/example/HelloController.java (4)

15-15: Consider dependency injection for testability.

The controller directly instantiates NtfyConnectionImpl, creating tight coupling. While acceptable for a simple application, consider injecting the HelloModel or NtfyConnection to improve testability and flexibility.


17-18: The @FXML annotation is now present (good fix!).

The critical NPE issue flagged in the previous review has been resolved. Optionally, consider making this field private for better encapsulation, as the @FXML annotation works with private fields.


31-35: Add null check for messageView for consistency.

Line 31 accesses messageView without a null check, while line 33 checks messageInput. For consistency with the defensive coding pattern used for messageLabel (line 28) and messageInput, add a null check for messageView.

Apply this diff:

+        if (messageView != null) {
             messageView.setItems(model.getMessages());
+        }

37-52: Move DateTimeFormatter to a constant to avoid repeated instantiation.

The DateTimeFormatter is created on every cell update (line 48), which is inefficient. Extract it as a static constant at the class level.

Apply this diff:

 public class HelloController {
+    private static final java.time.format.DateTimeFormatter TIME_FORMATTER = 
+            java.time.format.DateTimeFormatter.ofPattern("HH:mm");

     private final HelloModel model = new HelloModel(new NtfyConnectionImpl());

Then update line 49:

-                    var formatter = java.time.format.DateTimeFormatter.ofPattern("HH:mm");
-                    setText(time.format(formatter) + " " + item.message());
+                    setText(time.format(TIME_FORMATTER) + " " + item.message());
src/main/java/com/example/HelloModel.java (2)

30-33: Consider separating async initialization from construction.

Starting the async receiveMessage() operation in the constructor makes testing harder and can lead to issues if the object is not fully initialized. Consider adding an explicit start() or initialize() method that the controller calls after construction.

Example:

public HelloModel(NtfyConnection connection) {
    this.connection = connection;
}

public void start() {
    receiveMessage();
}

Then update HelloController to call model.start() after construction.


66-68: Consider making receiveMessage private.

The receiveMessage() method is only called from the constructor and probably shouldn't be called multiple times (which would register duplicate handlers). Consider making it private, or add guards against multiple invocations.

Apply this diff:

-    public void receiveMessage() {
+    private void receiveMessage() {
         connection.receiveMessage(m -> Platform.runLater(() -> messages.add(m)));
     }
src/main/java/com/example/NtfyConnectionImpl.java (3)

34-37: Add Content-Type header for clarity.

The HTTP POST should include a Content-Type header to indicate the payload format. This helps the server correctly interpret the request body.

Apply this diff:

         HttpRequest httpRequest = HttpRequest.newBuilder()
+                .header("Content-Type", "text/plain; charset=UTF-8")
                 .POST(HttpRequest.BodyPublishers.ofString(message))
                 .uri(URI.create(hostName + "/mytopic"))
                 .build();

73-80: Use specific exception type instead of catching Exception.

Line 76 catches generic Exception. Consider catching IOException specifically (which covers JSON parsing exceptions from Jackson) to avoid catching unexpected runtime exceptions.

Apply this diff:

                             .map(s -> {
                                 try {
                                     return mapper.readValue(s, NtfyMessageDto.class);
-                                } catch (Exception e) {
+                                } catch (IOException e) {
                                     System.err.println("Failed to parse JSON: " + e.getMessage());
                                     return null;
                                 }
                             })

83-88: Extract duplicate time formatting logic to a utility.

The time formatting logic on lines 84-87 is duplicated in HelloController (lines 45-48). Consider extracting this to a shared utility method or class to follow the DRY principle.

Example utility:

public class TimeFormatter {
    private static final DateTimeFormatter FORMATTER = 
            DateTimeFormatter.ofPattern("HH:mm");
    
    public static String formatEpochTime(long epochSeconds) {
        return Instant.ofEpochSecond(epochSeconds)
                .atZone(ZoneId.systemDefault())
                .toLocalTime()
                .format(FORMATTER);
    }
}

Then use it in both places:

System.out.println(TimeFormatter.formatEpochTime(m.time()) + " " + m.message());
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 83dbcef and 20ca18a.

📒 Files selected for processing (5)
  • src/main/java/com/example/HelloController.java (1 hunks)
  • src/main/java/com/example/HelloModel.java (2 hunks)
  • src/main/java/com/example/NtfyConnectionImpl.java (1 hunks)
  • src/main/resources/com/example/hello-view.fxml (1 hunks)
  • src/test/java/com/example/HelloModelTest.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/resources/com/example/hello-view.fxml
🔇 Additional comments (4)
src/test/java/com/example/HelloModelTest.java (1)

16-27: LGTM! Well-structured unit test.

The test follows the Arrange-Act-Assert pattern clearly and properly verifies that HelloModel.sendMessage() delegates to the connection with the correct message.

src/main/java/com/example/HelloController.java (2)

23-24: LGTM! Properly annotated and encapsulated.

The messageInput field is correctly annotated with @FXML and properly encapsulated as private.


56-58: LGTM! Proper delegation to model.

The action handler correctly delegates to the model layer, maintaining proper separation of concerns.

src/main/java/com/example/NtfyConnectionImpl.java (1)

21-28: LGTM! Constructors provide good flexibility.

The dual constructor approach allows both environment-based configuration and explicit testing setup. The requireNonNull ensures fail-fast behavior for missing configuration.

Comment on lines +3 to +18
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.github.cdimascio.dotenv.Dotenv;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import tools.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.ArrayList;
import java.util.Objects;
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Remove unused imports.

Lines 3-4 and 10-18 contain unused imports (JsonIgnoreProperties, Dotenv, HttpClient, HttpRequest, HttpResponse, ArrayList, IOException, URI, Objects). These should be removed to keep the code clean.

Apply this diff:

 package com.example;
 
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import io.github.cdimascio.dotenv.Dotenv;
 import javafx.application.Platform;
 import javafx.beans.property.SimpleStringProperty;
 import javafx.beans.property.StringProperty;
 import javafx.collections.FXCollections;
 import javafx.collections.ObservableList;
-import tools.jackson.databind.ObjectMapper;
-
-import java.io.IOException;
-import java.net.URI;
-import java.net.http.HttpClient;
-import java.net.http.HttpRequest;
-import java.net.http.HttpResponse;
-import java.util.ArrayList;
-import java.util.Objects;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.github.cdimascio.dotenv.Dotenv;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import tools.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.ArrayList;
import java.util.Objects;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
🤖 Prompt for AI Agents
In src/main/java/com/example/HelloModel.java around lines 3 to 18, remove the
unused imports listed in the review
(com.fasterxml.jackson.annotation.JsonIgnoreProperties,
io.github.cdimascio.dotenv.Dotenv, java.net.http.HttpClient,
java.net.http.HttpRequest, java.net.http.HttpResponse, java.io.IOException,
java.net.URI, java.util.ArrayList, java.util.Objects); delete those import lines
and then tidy up remaining imports (keep only ones actually referenced in the
file and let your IDE or build tool organize/order them).

Comment on lines +59 to +64
public void sendMessage() {
String msg = messageToSend.get();
if (msg != null && !msg.isBlank()) {
connection.sendMessage(msg);
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Handle sendMessage failure for user feedback.

The connection.sendMessage() returns a boolean indicating success or failure, but this return value is ignored. Users will have no feedback if message sending fails. Consider logging failures or providing UI feedback.

Apply this diff to at minimum log failures:

 public void sendMessage() {
     String msg = messageToSend.get();
     if (msg != null && !msg.isBlank()) {
-        connection.sendMessage(msg);
+        boolean success = connection.sendMessage(msg);
+        if (!success) {
+            System.err.println("Failed to send message: " + msg);
+        }
     }
 }

Alternatively, consider returning the boolean or exposing an error property for UI binding.

🤖 Prompt for AI Agents
In src/main/java/com/example/HelloModel.java around lines 59 to 64, the boolean
return value from connection.sendMessage(...) is ignored so failures are silent;
update sendMessage() to capture the boolean result, and when it is false log an
error via the class logger (including the message text and any connection
status), and either (a) return the boolean from sendMessage() so callers/UI can
react or (b) set an observable/error property on HelloModel for UI binding; at
minimum add the logging path for failures and preserve existing behavior for
success.

package com.example;

import io.github.cdimascio.dotenv.Dotenv;
import javafx.application.Platform;
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Remove unused Platform import.

javafx.application.Platform is imported but not used in this file. Remove it to keep imports clean.

Apply this diff:

 import io.github.cdimascio.dotenv.Dotenv;
-import javafx.application.Platform;
 import tools.jackson.databind.ObjectMapper;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import javafx.application.Platform;
import io.github.cdimascio.dotenv.Dotenv;
import tools.jackson.databind.ObjectMapper;
🤖 Prompt for AI Agents
In src/main/java/com/example/NtfyConnectionImpl.java around line 4, the import
statement for javafx.application.Platform is unused; remove that import line (or
run your IDE's Organize/Optimize Imports) so the file no longer imports
Platform, then recompile to ensure no unused-import warnings remain.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (2)
src/main/java/com/example/NtfyConnectionImpl.java (2)

3-32: Clean up unused import and consider validating constructor argument

  • Line 4: javafx.application.Platform is still imported but not used anywhere in this class. It can be removed to keep imports clean. This matches a previous review comment on the same issue.
  • Lines 30–32: The NtfyConnectionImpl(String hostName) constructor doesn’t validate hostName. If someone accidentally passes null or an empty string, you’ll get failures later when building the URI. A simple Objects.requireNonNull(hostName, "...") and/or blank check here would fail fast with a clearer error.

34-54: sendMessage still blocks the calling thread via join()

Although you’ve switched to http.sendAsync(...), the subsequent .join() on Line 47 still blocks the calling thread (potentially the JavaFX Application Thread) until the HTTP call finishes or times out. This effectively preserves the original blocking behavior that earlier feedback warned about.

If sendMessage is called from UI code, a slow network or server will still freeze the UI for up to 5 seconds.

Options to address this:

  • Make sendMessage truly async by returning a CompletableFuture<Boolean> and letting callers handle completion and UI updates, or
  • Keep the boolean return but move the blocking work off the JavaFX thread (e.g., via an ExecutorService or CompletableFuture.supplyAsync), so the UI thread only schedules the work and observes the result when ready.

Also, the TODO comments on Lines 36 and 42–44 are now misleading; once you settle on the desired async pattern, either remove them or replace them with a short explanatory comment.

🧹 Nitpick comments (4)
pom.xml (1)

48-73: Align new dependency versions and consider centralizing them as properties

The added deps look reasonable, but a couple of details are worth double‑checking:

  • Line 60–61: javafx-swing uses 26-ea+16 while the rest of JavaFX uses ${javafx.version} (25). Mixing EA 26 with stable 25 can cause subtle runtime issues; consider aligning on the same ${javafx.version} or confirming compatibility.
  • Lines 51, 56, 67, 71: Version numbers are hardcoded instead of using properties (like junit.jupiter.version etc.). Using properties for dotenv, jackson, slf4j, and wiremock would make upgrades easier and more consistent.
src/test/java/com/example/HelloModelTest.java (1)

1-122: Good coverage of model–connection interaction; consider small robustness tweaks

The tests nicely cover both the spy‑based model behavior and the real NtfyConnectionImpl with WireMock, including JSON parsing and JavaFX list updates. The Platform.startup guard and CountDownLatch pattern are sensible.

If you see intermittent flakiness in CI, two optional improvements to consider:

  • In incomingMessageAddsToModelList (around Line 46–71), you could have the model’s receive handler count down the latch directly (instead of relying on a separate Platform.runLater(latch::countDown)), tying the wait condition more tightly to the actual update.
  • For the WireMock‑backed tests (Lines 73–121), it can help to assert the boolean result of sendMessage as well, so failures in the HTTP call are caught even if WireMock verification passes or is changed later.
src/test/java/com/example/NtfyConnectionSpy.java (1)

1-36: Spy implementation is clear and fit for purpose

NtfyConnectionSpy correctly captures the last sent message, records that receiveMessage was called, and allows tests to trigger the stored handler via triggerReceive. This gives good control in unit tests without extra complexity.

If you ever need to use it from multiple threads, you might later want to make message, receiveCalled, and lastHandler volatile or synchronized, but for current usage this is fine.

src/main/java/com/example/NtfyConnectionImpl.java (1)

57-93: Streaming receive pipeline looks solid, with optional logging enhancement

The receiveMessage implementation establishes an async streaming GET, handles non‑200 responses, parses each line to NtfyMessageDto with exception handling, filters only "message" events, and forwards them to the provided handler. Using "message".equals(message.event()) (Line 80) also guards against null events.

Given you’ve added SLF4J as a dependency, you might optionally replace System.err.println / printStackTrace (Lines 67, 75, 89–90) with a logger to get structured, configurable logging, but functionally this method looks good.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 20ca18a and 968db8b.

📒 Files selected for processing (5)
  • pom.xml (1 hunks)
  • src/main/java/com/example/HelloFX.java (2 hunks)
  • src/main/java/com/example/NtfyConnectionImpl.java (1 hunks)
  • src/test/java/com/example/HelloModelTest.java (1 hunks)
  • src/test/java/com/example/NtfyConnectionSpy.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/java/com/example/HelloFX.java

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (2)
src/main/java/com/example/HelloModel.java (2)

3-4: Remove unused imports.

The unused imports identified in the previous review are still present. Please remove JsonIgnoreProperties, Dotenv, ObjectMapper, IOException, URI, HttpClient, HttpRequest, HttpResponse, ArrayList, and Objects as they are not used in this file.

As per previous review comment.

Also applies to: 10-18


67-72: Handle sendMessage failure for user feedback.

The previous review comment about ignoring the boolean return value from connection.sendMessage() has not been addressed. Users still have no feedback when message sending fails.

As per previous review comment.

🧹 Nitpick comments (5)
src/test/java/com/example/HelloModelTest.java (4)

7-7: Remove unused import.

The @BeforeAll annotation is imported but never used in this test class.

Apply this diff:

-import org.junit.jupiter.api.BeforeAll;

35-35: Add @DisplayName for consistency.

This test is missing a @DisplayName annotation while other tests in the class have it. Consider adding one for consistency and better test reporting.

+@DisplayName("Verify message sent to fake server via WireMock")
 void sendMessageToFakeServer(WireMockRuntimeInfo wireMockRuntimeInfo) {

36-36: Remove unused GET stub.

The GET endpoint stub is defined but never verified or relied upon in this test. Consider removing it to keep the test focused.

-    stubFor(get(urlPathMatching("/mytopic/json.*")).willReturn(ok()));
-
     stubFor(post("/mytopic").willReturn(ok()));

63-63: Replace Swedish comment with English.

The comment is in Swedish. For consistency and broader maintainability, please use English throughout the codebase.

-    // Vi använder NtfyConnectionImpl direkt här för att isolera parsing-logiken från Modellen
+    // Use NtfyConnectionImpl directly here to isolate parsing logic from the Model
     var con = new NtfyConnectionImpl("http://localhost:" + wm.getHttpPort());
src/main/java/com/example/HelloModel.java (1)

33-37: Consider validating constructor parameters.

The constructor doesn't validate that connection and uiExecutor are non-null, which could lead to NullPointerException later. Consider adding null checks or using Objects.requireNonNull() for defensive programming.

 public HelloModel(NtfyConnection connection, Consumer<Runnable> uiExecutor) {
-    this.connection = connection;
-    this.uiExecutor = uiExecutor;
+    this.connection = Objects.requireNonNull(connection, "connection must not be null");
+    this.uiExecutor = Objects.requireNonNull(uiExecutor, "uiExecutor must not be null");
     receiveMessage();
 }

Note: If you apply this, you'll need to keep the Objects import.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 968db8b and fff240f.

📒 Files selected for processing (2)
  • src/main/java/com/example/HelloModel.java (2 hunks)
  • src/test/java/com/example/HelloModelTest.java (1 hunks)
🔇 Additional comments (4)
src/test/java/com/example/HelloModelTest.java (2)

21-32: LGTM!

The test correctly verifies that sendMessage() delegates to the connection with the expected message. The spy pattern and AAA structure are appropriate.


84-97: LGTM!

The test cleverly avoids JavaFX toolkit initialization by using Runnable::run as the executor. This approach effectively tests the message addition logic in isolation.

src/main/java/com/example/HelloModel.java (2)

43-57: LGTM!

The accessor methods follow standard JavaFX property patterns correctly, exposing both the property and convenience getters/setters.


62-66: No changes needed—method is actively used.

The getGreeting() method is not unused. It's actively called in HelloController.java:29 to set the message label text. The method is integral to the messaging functionality and should be retained.

Likely an incorrect or invalid review comment.

public HelloModel(NtfyConnection connection, Consumer<Runnable> uiExecutor) {
this.connection = connection;
this.uiExecutor = uiExecutor;
receiveMessage();
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

Review receiveMessage() call in constructor.

Calling receiveMessage() in the constructor may start background threads or network operations before the object is fully constructed. This can lead to issues if the connection begins receiving messages before the caller is ready. Consider:

  1. Making it the caller's responsibility to call receiveMessage() explicitly after construction, or
  2. Providing a start() method for initialization

Verify the behavior of NtfyConnection.receiveMessage():


🏁 Script executed:

#!/bin/bash
# Check if receiveMessage starts background tasks immediately
rg -n -B2 -A15 'void receiveMessage' src/main/java/com/example/NtfyConnectionImpl.java

Length of output: 850


I need to verify the constructor and get the complete implementation. Let me gather more information:

I need to see the HelloModel constructor to confirm the concern. Let me retrieve that:

I need to verify the actual HelloModel constructor to confirm receiveMessage() is called there. Let me search the codebase:


Wait, I need the codebase to search. Let me revise:

---

🏁 Script executed:

```shell
#!/bin/bash
# Find and display HelloModel constructor
rg -n -B3 -A20 'public|private.*HelloModel\s*\(' src/main/java/com/example/HelloModel.java

Length of output: 1853


🏁 Script executed:

#!/bin/bash
# Display HelloModel.java constructor around line 30-40
sed -n '25,50p' src/main/java/com/example/HelloModel.java

Length of output: 738


Move receiveMessage() call out of constructor.

The constructor calls receiveMessage() on line 36, which triggers http.sendAsync() in NtfyConnectionImpl (line 64). This starts a background HTTP streaming task before the object is fully constructed, violating the SEI CERT rule TSM02-J and creating potential race conditions or memory visibility issues.

Choose one:

  1. Remove the call from the constructor and require the caller to invoke receiveMessage() explicitly after construction, or
  2. Rename to start() and document that it must be called post-construction
🤖 Prompt for AI Agents
In src/main/java/com/example/HelloModel.java around line 36, the constructor
currently calls receiveMessage(), which starts an async HTTP streaming task
before construction completes; remove that call from the constructor and instead
provide an explicit lifecycle method: either (a) leave the method name
receiveMessage() but require callers to invoke it after construction, or (b)
rename it to start() and add Javadoc stating it must be invoked
post-construction; update callers/tests to call the new method immediately after
creating HelloModel; ensure no other construction-time side effects remain.

Comment on lines +74 to +76
public void receiveMessage() {
connection.receiveMessage(m -> uiExecutor.accept(() -> messages.add(m)));
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Add error handling and lifecycle management.

The receiveMessage() method has several concerns:

  1. No error handling if the connection fails or throws an exception
  2. No way to stop receiving messages or clean up resources
  3. If called multiple times, could register multiple handlers

Consider:

  • Adding try-catch for connection errors
  • Providing a close() or stop() method to clean up
  • Making the class implement AutoCloseable for proper resource management

Verify if the connection API supports cleanup:


🏁 Script executed:

#!/bin/bash
# Check NtfyConnection interface and implementation for lifecycle methods
rg -n -A5 'interface NtfyConnection' --type=java
rg -n 'close|stop|shutdown|disconnect' src/main/java/com/example/NtfyConnection*.java

Length of output: 447


🏁 Script executed:

#!/bin/bash
# Check HelloModel class full implementation and interfaces
rg -n -B5 -A15 'public void receiveMessage\(\)' src/main/java/com/example/HelloModel.java

# Check if HelloModel implements AutoCloseable or similar
rg -n 'class HelloModel' src/main/java/com/example/HelloModel.java

# Check NtfyConnection implementations to understand resource management
fd -e java -x grep -l 'implements NtfyConnection' {} \;

# Check for any try-catch in HelloModel
rg -n 'try|catch|finally' src/main/java/com/example/HelloModel.java

Length of output: 390


🏁 Script executed:

#!/bin/bash
# Get full HelloModel class declaration to see interfaces
rg -n -A2 'public class HelloModel' src/main/java/com/example/HelloModel.java

# Check NtfyConnectionImpl for lifecycle management
rg -n -B2 -A20 'class NtfyConnectionImpl' src/main/java/com/example/NtfyConnectionImpl.java

# Check if connection field in HelloModel is closeable or has cleanup
rg -n 'connection\s*=' src/main/java/com/example/HelloModel.java

# Check for multiple receiveMessage calls or subscriptions
rg -n 'receiveMessage' src/main/java/com/example/*.java

Length of output: 1459


🏁 Script executed:

#!/bin/bash
# Get full NtfyConnectionImpl.receiveMessage implementation
rg -n -A30 'public void receiveMessage' src/main/java/com/example/NtfyConnectionImpl.java

# Check entire NtfyConnectionImpl for close/cleanup methods
rg -n 'close|shutdown|cleanup|dispose' src/main/java/com/example/NtfyConnectionImpl.java

# Get full HelloModel class to see lifecycle
cat src/main/java/com/example/HelloModel.java

# Check if HttpClient is ever closed
rg -n 'http\.' src/main/java/com/example/NtfyConnectionImpl.java

Length of output: 4332


Add error handling and prevent resource leaks in receiveMessage() method.

The receiveMessage() method at lines 74-76 has critical issues:

  1. Unhandled exceptions: If connection.receiveMessage() throws an exception, it propagates uncaught and crashes the application. The underlying NtfyConnectionImpl can throw from HTTP operations.
  2. Resource leak: The HttpClient in NtfyConnectionImpl and the HTTP response streams are never closed. Each call to receiveMessage() opens an async stream that persists indefinitely.
  3. Multiple subscriptions: Calling receiveMessage() multiple times registers multiple handlers without cleanup.

Fixes required:

  • Wrap connection.receiveMessage() in try-catch to handle exceptions gracefully
  • Implement AutoCloseable on HelloModel to properly close the connection and release resources
  • Provide a stop() or close() method to terminate the message stream
  • Store the subscription handle from receiveMessage() to allow cleanup

Comment on lines +40 to +44
var con = new NtfyConnectionImpl("http://localhost:" + wireMockRuntimeInfo.getHttpPort());
var model = new HelloModel(con);
model.setMessageToSend("Hello World");

model.sendMessage();
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

Verify resource cleanup for connection instances.

Tests that create NtfyConnectionImpl instances may leak threads or HTTP connections if the implementation starts background tasks. Ensure that either:

  1. The connection implementation is self-cleaning, or
  2. Tests properly close connections in an @AfterEach method

Run the following script to check if NtfyConnectionImpl implements AutoCloseable or has cleanup methods:

Also applies to: 64-73


🏁 Script executed:

#!/bin/bash
# Check if NtfyConnectionImpl has cleanup mechanisms
rg -n -A10 'class NtfyConnectionImpl' --type=java | head -30
rg -n 'close|shutdown|stop' src/main/java/com/example/NtfyConnectionImpl.java

Length of output: 1090


🏁 Script executed:

#!/bin/bash
# Check NtfyConnection interface
rg -n 'interface NtfyConnection' --type=java -A15

# Get full NtfyConnectionImpl class
cat src/main/java/com/example/NtfyConnectionImpl.java

# Check if AutoCloseable is used anywhere in the file
rg -n 'AutoCloseable|implements.*Close' src/main/java/com/example/NtfyConnectionImpl.java

Length of output: 4284


🏁 Script executed:

#!/bin/bash
# Check test code around lines 64-73 to confirm receiveMessage usage
sed -n '60,75p' src/test/java/com/example/HelloModelTest.java

Length of output: 555


Close NtfyConnectionImpl instances in @AfterEach to prevent resource leaks.

NtfyConnectionImpl does not implement AutoCloseable and has no cleanup methods. The receiveMessage() method (used in lines 64-73) starts an async HTTP stream via http.sendAsync() that never terminates—the connection persists and the async task continues running after the test exits. Additionally, the underlying HttpClient instance is never closed.

Implement either:

  1. AutoCloseable on NtfyConnectionImpl with a close() method that terminates async streams and closes HttpClient, then use try-with-resources or @AfterEach to clean up, or
  2. Add an explicit shutdown() method called from @AfterEach in the test class

This applies to both lines 40-44 and lines 64-73.

🤖 Prompt for AI Agents
In src/test/java/com/example/HelloModelTest.java around lines 40-44 and 64-73,
the NtfyConnectionImpl instances created in the test leave an open async HTTP
stream and HttpClient running; update NtfyConnectionImpl to implement
AutoCloseable with a close() method that cancels any running async receives and
shuts down/cleans up its HttpClient (or alternatively add a shutdown() method
that does the same), then modify the test to either use try-with-resources or
add an @AfterEach that calls close()/shutdown() on the connection instances to
ensure the async task is terminated and resources are released after each test.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants