Skip to content

Feature#30

Closed
bamsemats wants to merge 6 commits intomainfrom
feature
Closed

Feature#30
bamsemats wants to merge 6 commits intomainfrom
feature

Conversation

@bamsemats
Copy link

@bamsemats bamsemats commented Nov 16, 2025

Wanna try a pull request..?

Summary by CodeRabbit

  • New Features

    • Chat messaging interface with username display and timestamps
    • File attachment support with inline image rendering and downloadable file links
    • Message filtering and visibility toggle options
  • Chores

    • Added project dependencies and environment configuration support

@coderabbitai
Copy link

coderabbitai bot commented Nov 16, 2025

Warning

Rate limit exceeded

@bamsemats has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 9 minutes and 39 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between ac2dccc and e59bb6e.

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

Walkthrough

Introduces a JavaFX chat application with file-sharing support. Adds new model classes (ChatMessage, EnvLoader), environment configuration loading, network messaging via HTTP, async message handling, dynamic UI filtering, file selection and upload capabilities, comprehensive test coverage, and updated build configuration with new dependencies.

Changes

Cohort / File(s) Summary
Build and Module Configuration
pom.xml, src/main/java/module-info.java
Added httpclient.version property and two new Maven dependencies (org.json, httpclient5). Updated module-info to require org.json and java.net.http.
Environment and Project Setup
.gitignore, javafx.iml
Added .env to .gitignore for environment secrets. Added new IntelliJ module configuration with test source folder.
Data Models
src/main/java/com/example/ChatMessage.java, src/main/java/com/example/EnvLoader.java
Introduced ChatMessage immutable value object with seven fields and overloaded constructors. Added EnvLoader utility to parse .env files into a static map.
Application Core and Business Logic
src/main/java/com/example/HelloFX.java, src/main/java/com/example/HelloModel.java
Refactored HelloFX to initialize HostServices, update window title/size, load stylesheet, and change FXML path. Refactored HelloModel to replace greeting logic with message sending, history loading, and real-time listening capabilities via HTTP.
User Interface
src/main/java/com/example/HelloController.java, src/main/resources/com/example/hello-view.fxml, src/main/resources/css/style.css
Completely redesigned UI from StackPane to BorderPane with username bar, message filtering, chat list with inline images/links, file attachment, and input controls. Refactored controller to implement Initializable, add ObservableList/FilteredList, cell factory rendering, async send/attach operations, and filter binding. Added new stylesheet with component styling.
Testing
src/test/java/com/example/HelloModelTest.java
Introduced comprehensive test suite covering message sending, file sending, envelope parsing, and async callback validation.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Controller as HelloController
    participant Model as HelloModel
    participant HTTP as HTTP Client
    participant NTFY as NTFY Server

    User->>Controller: Type message + Click send()
    Controller->>Model: sendMessage(username, text)
    activate Model
    Model->>Model: Build JSON payload
    Model->>HTTP: POST with username, message, timestamp
    activate HTTP
    HTTP->>NTFY: Send to /topic
    NTFY-->>HTTP: 200 OK
    deactivate HTTP
    deactivate Model
    
    Model->>Controller: listenForMessages(callback)
    activate Model
    loop Listen for incoming
        Model->>NTFY: GET /topic (streaming)
        NTFY-->>Model: Message envelope
        Model->>Model: parseEnvelopeToChatMessage()
        Model->>Controller: callback(ChatMessage)
        Controller->>Controller: Add to ObservableList
        Controller->>Controller: Re-render ListView
    end
Loading
sequenceDiagram
    actor User
    participant Controller as HelloController
    participant FileChooser as FileChooser
    participant Model as HelloModel
    participant HTTP as HTTP Client
    participant NTFY as NTFY Server

    User->>Controller: Click attachButton
    Controller->>FileChooser: Show file picker
    FileChooser-->>Controller: Selected file path
    Controller->>Model: onAttachFile() internally calls sendFile(File)
    activate Model
    Model->>HTTP: POST multipart/form-data (file + metadata)
    activate HTTP
    HTTP->>NTFY: Upload to /topic
    NTFY-->>HTTP: URL response
    deactivate HTTP
    Model->>Model: Construct ChatMessage with fileUrl & mimeType
    Model->>Controller: callback with file-attached message
    deactivate Model
    Controller->>Controller: Add to ObservableList + Render
    User->>Controller: Click inline image/link in chat
    Controller->>HostServices: openDocument(fileUrl)
    HostServices->>User: Open in browser
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • HelloController.java — Substantial refactoring with new lifecycle (Initializable), observable list binding, filtering logic, custom cell rendering with inline images and hyperlinks, and async operations. Requires verification of observer/listener lifecycle and memory leak prevention.
  • HelloModel.java — Complete API replacement with network communication (HTTP POST/GET streaming), JSON parsing, callback-driven async flows, deduplication logic. Requires careful review of threading safety, error handling, and HTTP resource cleanup.
  • HelloFX.java — HostServices integration and FXML/stylesheet loading paths need verification for correctness across deployment scenarios.
  • hello-view.fxml — Major layout redesign and fx:id wiring to controller methods require validation of FXML syntax and event binding correctness.
  • ChatMessage.java, EnvLoader.java — New classes are straightforward but EnvLoader's file I/O and parsing should be reviewed for robustness (malformed .env handling).
  • HelloModelTest.java — Test suite logic and mock setup should be validated for adequate coverage of async edge cases and error paths.

Poem

🐰 A chat room springs to life with bounded lists and files in flight,
Messages flow like carrots stacked, with images shining bright!
The envelope unfolds to show what listeners seek,
While filters hide the noisy chatter — calm, clean, and sleek! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The pull request title 'Feature' is too vague and generic, providing no meaningful information about the actual changeset. Replace the generic title with a specific, descriptive title that captures the main change, such as 'Add chat messaging system with file attachment support' or 'Implement JavaFX chat application with environment configuration'.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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.

@bamsemats bamsemats closed this Nov 16, 2025
@bamsemats bamsemats reopened this Nov 16, 2025
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: 5

🧹 Nitpick comments (14)
javafx.iml (1)

1-8: Consider excluding IDE-specific files from version control.

IntelliJ IDEA module files (.iml) are typically IDE-specific and can vary between team members' configurations. Consider adding *.iml to .gitignore to prevent potential merge conflicts.

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

13-27: Consider more robust .env file handling.

The current implementation has a few limitations:

  1. Hardcoded file path: The .env file is read from the current working directory, which may not be consistent across different execution contexts (IDE, command line, JAR execution). Consider using a path relative to the classpath or project root.

  2. No support for quoted values: The parser doesn't handle quoted values like KEY="value with spaces" or KEY='value', which is common in .env files. Values with special characters or spaces won't be parsed correctly.

  3. Silent failure: IOException only logs a warning. If the .env file is required, consider failing fast with a proper exception.

Example improvement for quoted value support:

                String[] parts = line.split("=", 2);
                if (parts.length == 2) {
-                   env.put(parts[0].trim(), parts[1].trim());
+                   String value = parts[1].trim();
+                   // Remove surrounding quotes if present
+                   if ((value.startsWith("\"") && value.endsWith("\"")) ||
+                       (value.startsWith("'") && value.endsWith("'"))) {
+                       value = value.substring(1, value.length() - 1);
+                   }
+                   env.put(parts[0].trim(), value);
                }

29-31: Consider adding overload with default value support.

The get() method returns null when a key is not found, which can lead to NullPointerExceptions. Consider adding an overload that accepts a default value.

Example:

public static String get(String key) {
    return env.get(key);
}

public static String get(String key, String defaultValue) {
    return env.getOrDefault(key, defaultValue);
}
src/main/java/com/example/HelloFX.java (1)

11-15: Make the static field private for better encapsulation.

The hostServices field is declared as public static, which allows direct mutation from anywhere. Consider making it private to enforce access through the getter method.

Apply this diff:

-    public static HostServices hostServices;
+    private static HostServices hostServices;

     public static HostServices hostServices() {
         return hostServices;
     }
src/main/resources/com/example/hello-view.fxml (2)

19-22: Consider adding accessibility improvements.

The username field and controls lack accessibility features:

  1. Prompt text: The usernameField should have a promptText attribute to guide users.
  2. Mnemonics: Consider adding keyboard shortcuts (e.g., _Username: label text) for keyboard-only navigation.
  3. Tooltips: Controls like the attach button could benefit from tooltips.

Example:

<TextField fx:id="usernameField" prefWidth="200" promptText="Enter your username" />

48-48: Add prompt text to input field.

The message input field lacks a promptText attribute to guide users on what to type.

Example:

<TextField fx:id="inputField" onAction="#onSend" promptText="Type a message..." HBox.hgrow="ALWAYS" />
src/main/java/com/example/HelloModel.java (4)

22-27: Constructor’s hard dependency on .env is fine for app, but awkward for tests and reuse

Fail‑fast on missing NTFY_URL is reasonable for the running app, but it forces any consumer (including tests and tools) to have a valid .env. A small overload like HelloModel(String topicUrl) or a factory would make the model easier to test and reuse while keeping the default constructor for production.


37-106: sendFile is already asynchronous; document this and avoid nesting extra threads elsewhere

sendFile does its own new Thread(...).start(), which is good for keeping I/O off the FX thread, but it means callers should treat it as fire‑and‑forget. Right now HelloController.onAttachFile wraps sendFile in yet another new Thread, which is redundant and makes debugging harder.

I’d recommend:

  • Documenting in Javadoc that sendFile is asynchronous, and
  • Calling it directly from the controller (no extra thread) to avoid unnecessary thread nesting.

138-214: History/listen threads lack lifecycle management (optional improvement)

loadHistory and listenForMessages spawn background threads that run until the HTTP stream ends (or errors) with no way to cancel from the outside. For a simple demo this is acceptable, but in a longer‑lived app you’ll likely want some lifecycle control (interrupt flags, closing the connection on shutdown, or using an ExecutorService).

Not urgent for a sample/chat toy, but worth keeping in mind if you build on this.


218-253: Envelope parsing is robust but swallows errors; consider logging more structurally

parseEnvelopeToChatMessage defensively checks the message shape and wraps JSON parsing in a try/catch, returning null on any error, which keeps the stream loops resilient. The trade‑off is that you only get stacktraces to stderr, which can be noisy and hard to correlate.

If you keep evolving this, consider:

  • Logging parse failures with a short summary including the id value, and
  • Maybe returning a sentinel ChatMessage for clearly invalid payloads if you ever want to surface them in the UI.

Behavior as‑is is fine for now.

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

49-84: Handle image‑load failures by resetting the cell graphic

If new Image(msg.getFileUrl(), true) or any of the image code throws, the catch block only prints the stacktrace and never calls setGraphic(...), which can leave stale content from a previous cell reuse. It’s safer to always set some graphic (even a text‑only fallback) in both success and failure paths.

Example tweak inside the catch:

-                    if (msg.getMimeType() != null && msg.getMimeType().startsWith("image/")) {
+                    if (msg.getMimeType() != null && msg.getMimeType().startsWith("image/")) {
                         try {
                             ImageView imageView = new ImageView(new Image(msg.getFileUrl(), true));
                             imageView.setFitWidth(200);
                             imageView.setPreserveRatio(true);
                             Text messageText = new Text(msg.getMessage() + "\n");
                             messageText.setStyle("-fx-font-size: 14px;");
                             setGraphic(new TextFlow(user, time, messageText, imageView));
-                        } catch (Exception e) { e.printStackTrace(); }
+                        } catch (Exception e) {
+                            e.printStackTrace();
+                            Text messageText = new Text(msg.getMessage() + "\n");
+                            messageText.setStyle("-fx-font-size: 14px;");
+                            setGraphic(new TextFlow(user, time, messageText));
+                        }

93-98: Filter predicate is simple and correct, but won’t retroactively tag old usernames

The predicate msg -> !hideMine || !current.equals(msg.getUsername()) cleanly hides only messages with the current username; messages sent before a username change won’t be treated as “mine” anymore. That’s probably acceptable, but keep it in mind if you later introduce a stable user id.


100-111: onSend threading approach is reasonable; consider centralizing async behavior in the model later

Spawning a short‑lived thread per send avoids blocking the FX thread on network I/O, which is fine for a small app. Long‑term you might want HelloModel itself to expose async APIs (or use an ExecutorService) so controllers don’t manage threads directly.


113-119: Avoid double‑threading for file send; call sendFile directly here

onAttachFile starts a new thread and then calls model.sendFile, which itself creates another thread for the actual upload. The outer thread does almost nothing except immediately spawn the inner one.

You can simplify to a single background thread by removing the extra new Thread:

-        File file = fileChooser.showOpenDialog(chatList.getScene().getWindow());
-        if (file != null) new Thread(() -> model.sendFile(getCurrentUsername(), file)).start();
+        File file = fileChooser.showOpenDialog(chatList.getScene().getWindow());
+        if (file != null) {
+            model.sendFile(getCurrentUsername(), file); // already async
+        }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 21c51e8 and ac2dccc.

⛔ Files ignored due to path filters (6)
  • src/main/resources/background.png is excluded by !**/*.png
  • src/main/resources/lantern.png is excluded by !**/*.png
  • src/main/resources/lantern1.png is excluded by !**/*.png
  • src/main/resources/lantern2.png is excluded by !**/*.png
  • src/main/resources/lantern3.png is excluded by !**/*.png
  • src/main/resources/lantern4.png is excluded by !**/*.png
📒 Files selected for processing (12)
  • .gitignore (1 hunks)
  • javafx.iml (1 hunks)
  • pom.xml (5 hunks)
  • src/main/java/com/example/ChatMessage.java (1 hunks)
  • src/main/java/com/example/EnvLoader.java (1 hunks)
  • src/main/java/com/example/HelloController.java (1 hunks)
  • src/main/java/com/example/HelloFX.java (1 hunks)
  • src/main/java/com/example/HelloModel.java (1 hunks)
  • src/main/java/module-info.java (1 hunks)
  • src/main/resources/com/example/hello-view.fxml (1 hunks)
  • src/main/resources/css/style.css (1 hunks)
  • src/test/java/com/example/HelloModelTest.java (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/main/java/com/example/HelloModel.java (1)
src/main/java/com/example/EnvLoader.java (1)
  • EnvLoader (9-32)
src/main/java/com/example/HelloController.java (1)
src/main/java/com/example/HelloFX.java (1)
  • HelloFX (10-32)
🪛 Biome (2.1.2)
src/main/resources/css/style.css

[error] 2-2: Unknown property is not allowed.

See CSS Specifications and browser specific properties for more details.
To resolve this issue, replace the unknown property with a valid CSS property.

(lint/correctness/noUnknownProperty)


[error] 3-3: Unknown property is not allowed.

See CSS Specifications and browser specific properties for more details.
To resolve this issue, replace the unknown property with a valid CSS property.

(lint/correctness/noUnknownProperty)


[error] 7-7: Unknown property is not allowed.

See CSS Specifications and browser specific properties for more details.
To resolve this issue, replace the unknown property with a valid CSS property.

(lint/correctness/noUnknownProperty)


[error] 11-11: Unknown property is not allowed.

See CSS Specifications and browser specific properties for more details.
To resolve this issue, replace the unknown property with a valid CSS property.

(lint/correctness/noUnknownProperty)


[error] 12-12: Unknown property is not allowed.

See CSS Specifications and browser specific properties for more details.
To resolve this issue, replace the unknown property with a valid CSS property.

(lint/correctness/noUnknownProperty)


[error] 16-16: Unknown property is not allowed.

See CSS Specifications and browser specific properties for more details.
To resolve this issue, replace the unknown property with a valid CSS property.

(lint/correctness/noUnknownProperty)


[error] 17-17: Unknown property is not allowed.

See CSS Specifications and browser specific properties for more details.
To resolve this issue, replace the unknown property with a valid CSS property.

(lint/correctness/noUnknownProperty)


[error] 18-18: Unknown property is not allowed.

See CSS Specifications and browser specific properties for more details.
To resolve this issue, replace the unknown property with a valid CSS property.

(lint/correctness/noUnknownProperty)


[error] 18-18: Unexpected unknown function: derive

Use a known function instead.
See MDN web docs for more details.

(lint/correctness/noUnknownFunction)


[error] 22-22: Unknown property is not allowed.

See CSS Specifications and browser specific properties for more details.
To resolve this issue, replace the unknown property with a valid CSS property.

(lint/correctness/noUnknownProperty)

🔇 Additional comments (6)
.gitignore (1)

3-3: LGTM!

Adding .env to .gitignore is appropriate to prevent environment configuration files from being committed to version control.

src/main/java/module-info.java (1)

4-5: LGTM!

The new module requirements for org.json and java.net.http align with the added Maven dependencies and support the chat application's JSON processing and HTTP communication capabilities.

src/main/resources/css/style.css (1)

1-23: Static analysis hints are false positives.

The static analysis tool (Biome) is flagging JavaFX-specific CSS properties and functions as unknown because it's designed for web CSS, not JavaFX CSS. All properties (prefixed with -fx-) and the derive() function are valid JavaFX CSS extensions and are correctly used in this stylesheet.

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

70-94: JSON envelope parsing tests look good and match parseEnvelopeToChatMessage semantics

These two tests nicely cover the “JSON message vs plain text” envelope behavior and verify that a proper ChatMessage is created only for the JSON case. This is a solid regression net around the parsing logic.

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

89-91: Good use of Platform.runLater to marshal model callbacks onto the FX thread

Wiring loadHistory/listenForMessages into masterList through Platform.runLater is the right pattern and keeps UI updates thread‑safe.

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

3-34: Immutable ChatMessage value object looks solid

Fields are final, constructors cover both “with attachment” and “text‑only” cases, and getters are straightforward. This is a clean, minimal data carrier for the rest of the app.

Comment on lines +56 to +66
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20240303</version>
</dependency>

<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>${httpclient.version}</version>
</dependency>
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 dependency versions and security advisories.

Since the project uses fixed versions for org.json (20240303, from March 2024) and httpclient5 (5.3.1), please verify these are current and check for any security advisories.

Run the following script to check for the latest versions and security advisories:


🏁 Script executed:

#!/bin/bash
# Check latest versions from Maven Central
echo "=== Checking org.json:json latest version ==="
curl -s "https://search.maven.org/solrsearch/select?q=g:org.json+AND+a:json&rows=1&wt=json" | jq -r '.response.docs[0].latestVersion'

echo "=== Checking httpclient5 latest version ==="
curl -s "https://search.maven.org/solrsearch/select?q=g:org.apache.httpcomponents.client5+AND+a:httpclient5&rows=1&wt=json" | jq -r '.response.docs[0].latestVersion'

echo "=== Checking for security advisories ==="
gh api graphql -f query='
{
  securityVulnerabilities(first: 5, ecosystem: MAVEN, package: "org.json:json") {
    nodes {
      advisory {
        summary
        severity
        publishedAt
      }
      vulnerableVersionRange
      firstPatchedVersion {
        identifier
      }
    }
  }
}' 

gh api graphql -f query='
{
  securityVulnerabilities(first: 5, ecosystem: MAVEN, package: "org.apache.httpcomponents.client5:httpclient5") {
    nodes {
      advisory {
        summary
        severity
        publishedAt
      }
      vulnerableVersionRange
      firstPatchedVersion {
        identifier
      }
    }
  }
}'

Length of output: 1094


Update outdated dependencies in pom.xml.

HttpClient 5.5.x is stable and production ready, and actively maintained, while the current version (5.3.1) is from an older release series. Latest stable httpclient5 is 5.5.1.

org.json latest version is 20250517 (May 2025), but the pom.xml uses 20240303 (March 2024)—17 months behind. Both current versions lack recent security patches and improvements.

Update:

  • org.json:json from 20240303 to 20250517
  • httpclient5 from 5.3.1 to 5.5.1
🤖 Prompt for AI Agents
In pom.xml around lines 56 to 66, the project is using outdated dependency
versions: org.json:json is set to 20240303 and httpclient5 is resolved to
${httpclient.version} which currently points to 5.3.1; update org.json:json to
version 20250517 and update httpclient5 to 5.5.1 (either by changing the
explicit <version> for the httpclient5 dependency to 5.5.1 or by updating the
httpclient.version property in the pom.xml to 5.5.1) so the POM uses
org.json:json:20250517 and org.apache.httpcomponents.client5:httpclient5:5.5.1.

Parent root = loader.load();
Scene scene = new Scene(root, 720, 520);
scene.getStylesheets().add(getClass().getResource("/css/style.css").toExternalForm());
stage.setTitle("JavaFX NTFY Chat — mats_notiser");
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

Remove hardcoded username from window title.

The window title includes a hardcoded username "mats_notiser", which appears to be developer-specific. Since the UI includes a usernameField, consider either:

  1. Using a generic title without a username
  2. Dynamically updating the title when the username changes

Example for a generic title:

-        stage.setTitle("JavaFX NTFY Chat — mats_notiser");
+        stage.setTitle("JavaFX NTFY Chat");
📝 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
stage.setTitle("JavaFX NTFY Chat — mats_notiser");
stage.setTitle("JavaFX NTFY Chat");
🤖 Prompt for AI Agents
In src/main/java/com/example/HelloFX.java around line 24, remove the hardcoded
username in the window title ("mats_notiser") and either set a generic title
(e.g., "JavaFX NTFY Chat") or make the title dynamic by updating/binding it to
the usernameField so it reflects the entered username; implement this by
replacing the literal title string with a generic one or by adding a
listener/binding on usernameField.textProperty() to update stage.setTitle(...)
when the username changes (use a fallback when the field is empty).

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<BorderPane xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/17.0.12" fx:controller="com.example.HelloController">
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

Verify controller implementation matches FXML bindings.

The FXML references HelloController with multiple fx:id bindings and action handlers. Please ensure the controller has:

  1. @FXML annotated fields: usernameField, hideMyMessagesCheck, attachButton, chatList, uploadProgress, statusLabel, inputField, sendButton
  2. Action handler methods: onAttachFile() and onSend()
  3. Proper initialization logic in the initialize() method

Run the following script to verify the controller implementation:


🏁 Script executed:

#!/bin/bash
# Verify HelloController exists and has required fields and methods

echo "=== Checking for HelloController class ==="
rg -n "class HelloController" --type java

echo "=== Checking for @FXML fields ==="
rg -n "@FXML" --type java -A 1 -g '**/HelloController.java'

echo "=== Checking for action handlers ==="
rg -n "(onAttachFile|onSend)" --type java -g '**/HelloController.java'

echo "=== Checking for initialize method ==="
rg -n "void initialize\(" --type java -g '**/HelloController.java'

Length of output: 1253


🏁 Script executed:

#!/bin/bash
# Get complete list of @FXML fields and verify method signatures

echo "=== All @FXML fields in HelloController ==="
rg -n "@FXML" --type java -A 1 src/main/java/com/example/HelloController.java

echo "=== Action handler signatures ==="
rg -nP "(@FXML\s+)?private void (onAttachFile|onSend)" --type java -A 1 src/main/java/com/example/HelloController.java

echo "=== Check FXML file for all fx:id and fx:controller references ==="
grep -n "fx:id\|fx:controller" src/main/resources/com/example/hello-view.fxml

Length of output: 1387


Missing @FXML field bindings in HelloController will cause runtime failures.

The FXML file defines 8 fx:id bindings, but the controller only implements 4 @FXML fields. Missing fields that must be added to src/main/java/com/example/HelloController.java:

  • attachButton (Button)
  • uploadProgress (ProgressBar)
  • statusLabel (Label)
  • sendButton (Button)

The controller has correct @FXML annotations for usernameField, hideMyMessagesCheck, chatList, and inputField. The action handlers onSend() and onAttachFile() are properly defined. Add the missing field declarations to prevent JavaFX injection errors.

🤖 Prompt for AI Agents
In src/main/java/com/example/HelloController.java (corresponding to
src/main/resources/com/example/hello-view.fxml around line 7), the controller is
missing four @FXML field declarations that the FXML references, causing JavaFX
injection failures at runtime; add private fields annotated with @FXML for
attachButton (javafx.scene.control.Button), uploadProgress
(javafx.scene.control.ProgressBar), statusLabel (javafx.scene.control.Label),
and sendButton (javafx.scene.control.Button) to the HelloController class
alongside the existing @FXML fields so the FXML loader can inject those UI
controls.

Comment on lines +97 to +109
@Test
void testLoadHistoryCallbackCalled() {
AtomicBoolean called = new AtomicBoolean(false);
model.loadHistory(msg -> called.set(true));
assertDoesNotThrow(() -> model.loadHistory(msg -> {}));
}

@Test
void testListenForMessagesCallbackCalled() {
AtomicReference<ChatMessage> ref = new AtomicReference<>();
model.listenForMessages(ref::set);
assertDoesNotThrow(() -> model.listenForMessages(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

🧩 Analysis chain

loadHistory/listenForMessages tests don’t assert callbacks and still hit real network

Both testLoadHistoryCallbackCalled and testListenForMessagesCallbackCalled only assert “no exception thrown” and never check called.get() / ref.get(), so they do not actually verify that callbacks are invoked. On top of that, they call the real loadHistory/listenForMessages, which spin up threads and try to talk to whatever NTFY_URL points at, making tests slow and brittle.

Consider either:

  • Overriding loadHistory/listenForMessages in the anonymous subclass to invoke the callback immediately without networking; or
  • Using a CountDownLatch with a short timeout and a stubbed HelloModel that doesn’t talk to the network.

Also rename the tests (or tighten the assertions) so names match what is actually verified.


🏁 Script executed:

#!/bin/bash
# Examine the test file to see full context and class setup
cat src/test/java/com/example/HelloModelTest.java

Length of output: 3425


🏁 Script executed:

#!/bin/bash
# Search for HelloModel class definition and implementation
fd -t f HelloModel.java | head -5 | xargs -I {} cat {}

Length of output: 10595


🏁 Script executed:

#!/bin/bash
# Look for NTFY_URL and network-related code
rg -n "NTFY_URL|loadHistory|listenForMessages" --type=java -B2 -A5

Length of output: 4123


🏁 Script executed:

#!/bin/bash
# Check if there are any mock frameworks being used
rg -n "@Mock|@Spy|mockito|when\(|thenReturn" --type=java

Length of output: 0


Tests don't verify callback invocation and make real network requests

Both testLoadHistoryCallbackCalled and testListenForMessagesCallbackCalled have two problems:

  1. No callback verification: The tests initialize called and ref but never assert on them. Adding assertTrue(called.get()) and assertNotNull(ref.get()) after the first call would catch missing callbacks.

  2. Real network calls: loadHistory and listenForMessages are not overridden in the test's anonymous HelloModel subclass, so they execute the real implementations that spawn threads and make HTTP requests to TOPIC_URL, making tests slow and brittle.

Fix by either:

  • Overriding both methods in the anonymous subclass to invoke callbacks immediately without networking, or
  • Using a CountDownLatch with a timeout to verify async callback invocation on a stubbed model

Also rename tests (or add proper assertions) to match what is actually verified.

🤖 Prompt for AI Agents
In src/test/java/com/example/HelloModelTest.java around lines 97 to 109, the two
tests call model.loadHistory and model.listenForMessages but neither assert the
callbacks were invoked and they call the real implementations which perform
network work; update the tests to (1) either override loadHistory and
listenForMessages in the test’s HelloModel stub to synchronously invoke the
provided callbacks (so no network/threads run) and then add assertions
assertTrue(called.get()) and assertNotNull(ref.get()) after the call, or (2)
replace with a CountDownLatch per test that the overridden/stubbed async
callback counts down and use await with a timeout, then assert the latch reached
zero; also rename or update test names to reflect the verified behavior.

@kappsegla kappsegla closed this Nov 19, 2025
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