-
Notifications
You must be signed in to change notification settings - Fork 66
Branch fix #42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Branch fix #42
Changes from all commits
d9b1ca1
6dab50c
abcb23b
0ef4d6e
baa5a45
0b4c16f
6caee10
12c2d78
8c030c3
9a41f79
0b83363
8d6c523
9534fea
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,3 @@ | ||
| target/ | ||
| /.idea/ | ||
| .env |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,22 +1,58 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package com.example; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import javafx.application.Platform; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import javafx.fxml.FXML; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import javafx.scene.control.Label; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import javafx.scene.control.TextArea; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import javafx.scene.control.TextField; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import javafx.stage.FileChooser; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import javafx.scene.control.Button; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.io.File; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Controller layer: mediates between the view (FXML) and the model. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public class HelloController { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final HelloModel model = new HelloModel(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @FXML | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private TextArea chatArea; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @FXML | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private TextField inputField; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @FXML | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private Button sendButton; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @FXML | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private Label messageLabel; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private Button attachButton; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
23
to
+24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Remove unused The - @FXML
- private Button attachButton;📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private HelloModel model; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @FXML | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public void initialize() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Läser BACKEND_URL och TOPIC från .env via HelloModel | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| model = new HelloModel(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Lyssna på inkommande meddelanden | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| model.listen(msg -> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Platform.runLater(() -> chatArea.appendText(msg + "\n")); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| System.out.println("📩 Mottaget: " + msg); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+28
to
+38
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add error handling for model initialization. The @FXML
public void initialize() {
- // Läser BACKEND_URL och TOPIC från .env via HelloModel
- model = new HelloModel();
-
- // Lyssna på inkommande meddelanden
- model.listen(msg -> {
- Platform.runLater(() -> chatArea.appendText(msg + "\n"));
- System.out.println("📩 Mottaget: " + msg);
- });
+ try {
+ // Läser BACKEND_URL och TOPIC från .env via HelloModel
+ model = new HelloModel();
+
+ // Lyssna på inkommande meddelanden
+ model.listen(msg -> {
+ Platform.runLater(() -> chatArea.appendText(msg + "\n"));
+ System.out.println("📩 Mottaget: " + msg);
+ });
+ } catch (IllegalStateException e) {
+ Platform.runLater(() -> {
+ chatArea.appendText("⚠️ Fel: Kunde inte initiera chat. Kontrollera .env-filen.\n");
+ chatArea.appendText("Meddelande: " + e.getMessage() + "\n");
+ });
+ sendButton.setDisable(true);
+ }
}🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @FXML | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| protected void onSendButtonClick() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| String message = inputField.getText().trim(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!message.isEmpty()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| model.sendMessage(message); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| inputField.clear(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+40
to
+47
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add error handling for message sending failures. The @FXML
protected void onSendButtonClick() {
String message = inputField.getText().trim();
if (!message.isEmpty()) {
- model.sendMessage(message);
- inputField.clear();
+ try {
+ model.sendMessage(message);
+ inputField.clear();
+ } catch (Exception e) {
+ Platform.runLater(() ->
+ chatArea.appendText("⚠️ Kunde inte skicka meddelande: " + e.getMessage() + "\n")
+ );
+ }
}
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @FXML | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private void initialize() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (messageLabel != null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| messageLabel.setText(model.getGreeting()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| protected void onAttachFileClick() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| FileChooser fileChooser = new FileChooser(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fileChooser.setTitle("Välj en fil att skicka"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| File file = fileChooser.showOpenDialog(chatArea.getScene().getWindow()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (file != null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| model.sendFile(file); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
49
to
57
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add error handling for file sending failures. Similar to message sending, file operations may fail. Add error handling and user feedback. @FXML
protected void onAttachFileClick() {
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("Välj en fil att skicka");
File file = fileChooser.showOpenDialog(chatArea.getScene().getWindow());
if (file != null) {
- model.sendFile(file);
+ try {
+ model.sendFile(file);
+ Platform.runLater(() ->
+ chatArea.appendText("📎 Skickade fil: " + file.getName() + "\n")
+ );
+ } catch (Exception e) {
+ Platform.runLater(() ->
+ chatArea.appendText("⚠️ Kunde inte skicka fil: " + e.getMessage() + "\n")
+ );
+ }
}
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,15 +1,140 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package com.example; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Model layer: encapsulates application data and business logic. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import io.github.cdimascio.dotenv.Dotenv; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.fasterxml.jackson.databind.JsonNode; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.io.File; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.net.URI; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.net.http.HttpClient; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.net.http.HttpRequest; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.net.http.HttpResponse; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.nio.file.Files; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.concurrent.CompletableFuture; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public class HelloModel { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Returns a greeting based on the current Java and JavaFX versions. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public String getGreeting() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| String javaVersion = System.getProperty("java.version"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| String javafxVersion = System.getProperty("javafx.version"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return "Hello, JavaFX " + javafxVersion + ", running on Java " + javaVersion + "."; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private static final ObjectMapper mapper = new ObjectMapper(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final HttpClient client = HttpClient.newHttpClient(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final String topic; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final String backendUrl; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** Standardkonstruktor som läser från .env */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public HelloModel() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Dotenv dotenv = Dotenv.configure().ignoreIfMissing().load(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.backendUrl = dotenv.get("BACKEND_URL", System.getenv("BACKEND_URL")); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.topic = dotenv.get("TOPIC", System.getenv("TOPIC")); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (backendUrl == null || topic == null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new IllegalStateException("BACKEND_URL eller TOPIC saknas i .env"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** Alternativ konstruktor för tester */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| HelloModel(String topic, String backendUrl) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (backendUrl == null || backendUrl.isBlank()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new IllegalArgumentException("backendUrl must not be null/blank"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.backendUrl = backendUrl; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.topic = topic; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+17
to
+40
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Validate
Consider enforcing non-null/non-blank - HelloModel(String topic, String backendUrl) {
- if (backendUrl == null || backendUrl.isBlank()) {
- throw new IllegalArgumentException("backendUrl must not be null/blank");
- }
- this.backendUrl = backendUrl;
- this.topic = topic;
- }
+ HelloModel(String topic, String backendUrl) {
+ if (backendUrl == null || backendUrl.isBlank()) {
+ throw new IllegalArgumentException("backendUrl must not be null/blank");
+ }
+ if (topic == null || topic.isBlank()) {
+ throw new IllegalArgumentException("topic must not be null/blank");
+ }
+ this.backendUrl = backendUrl;
+ this.topic = topic;
+ }🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public void sendMessage(String message) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| String sender = "[Eric Chat App]"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| String fullMessage = sender + " " + message; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| String json = "{\"message\": \"" + fullMessage.replace("\"", "\\\"") + "\"}"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| String url = backendUrl + "/" + topic; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| HttpRequest request = HttpRequest.newBuilder() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .uri(URI.create(url)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .header("Content-Type", "application/json") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .POST(HttpRequest.BodyPublishers.ofString(json)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .build(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| client.sendAsync(request, HttpResponse.BodyHandlers.ofString()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .thenAccept(response -> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (response.statusCode() >= 300) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| System.err.println("⚠️ Misslyckades att skicka: " + response.statusCode() + " - " + response.body()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .exceptionally(ex -> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| System.err.println("⚠️ Nätverksfel vid sendMessage: " + ex.getMessage()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+42
to
+65
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid manual JSON string building in Right now JSON is constructed by hand and only double quotes are escaped. Messages containing newlines, backslashes, or other special characters will generate invalid JSON and may fail on the server. Since you already have Jackson, it’s safer to let it build the payload: - public void sendMessage(String message) {
- String sender = "[Eric Chat App]";
- String fullMessage = sender + " " + message;
-
- String json = "{\"message\": \"" + fullMessage.replace("\"", "\\\"") + "\"}";
+ public void sendMessage(String message) {
+ String sender = "[Eric Chat App]";
+ String fullMessage = sender + " " + message;
+
+ String json;
+ try {
+ json = mapper.writeValueAsString(java.util.Map.of("message", fullMessage));
+ } catch (Exception e) {
+ System.err.println("⚠️ Kunde inte serialisera meddelande: " + e.getMessage());
+ return;
+ }Optionally, return the
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public void sendFile(File file) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| String url = backendUrl + "/" + topic; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| String contentType = Files.probeContentType(file.toPath()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (contentType == null) contentType = "application/octet-stream"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| HttpRequest request = HttpRequest.newBuilder() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .uri(URI.create(url)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .header("Content-Type", contentType) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .header("X-Filename", file.getName()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .header("Title", "File: " + file.getName()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .POST(HttpRequest.BodyPublishers.ofFile(file.toPath())) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .build(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| client.sendAsync(request, HttpResponse.BodyHandlers.ofString()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .thenAccept(response -> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (response.statusCode() >= 300) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| System.err.println("⚠️ Filupload misslyckades: " + response.statusCode() + " - " + response.body()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| System.out.println("✅ Fil skickad: " + file.getName()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .exceptionally(ex -> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| System.err.println("⚠️ Nätverksfel vid sendFile: " + ex.getMessage()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (Exception e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| System.err.println("⚠️ Kunde inte läsa/skicka fil: " + e.getMessage()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+67
to
+96
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add basic validation for
You can fail fast with clearer messages: - public void sendFile(File file) {
- try {
+ public void sendFile(File file) {
+ if (file == null) {
+ throw new IllegalArgumentException("file must not be null");
+ }
+ if (!file.isFile() || !file.canRead()) {
+ System.err.println("⚠️ Ogiltig fil: " + file);
+ return;
+ }
+ try {
String url = backendUrl + "/" + topic;
String contentType = Files.probeContentType(file.toPath());This keeps the async flow but avoids ambiguous failures. 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public CompletableFuture<Void> listen(MessageHandler handler) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| String url = backendUrl + "/" + topic + "/json"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| HttpRequest request = HttpRequest.newBuilder().uri(URI.create(url)).build(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return client.sendAsync(request, HttpResponse.BodyHandlers.ofLines()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .thenAccept(response -> response.body().forEach(line -> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| String parsed = parseIncomingLine(line); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!parsed.isEmpty()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| handler.onMessage(parsed); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| System.out.println("📩 Meddelande: " + parsed); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| })) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .exceptionally(ex -> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| System.err.println("⚠️ Nätverksfel vid listen: " + ex.getMessage()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+98
to
+114
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider handling non-2xx status codes in
A small guard can improve diagnostics: - return client.sendAsync(request, HttpResponse.BodyHandlers.ofLines())
- .thenAccept(response -> response.body().forEach(line -> {
+ return client.sendAsync(request, HttpResponse.BodyHandlers.ofLines())
+ .thenAccept(response -> {
+ if (response.statusCode() >= 300) {
+ System.err.println("⚠️ Lyssning misslyckades: " + response.statusCode());
+ return;
+ }
+ response.body().forEach(line -> {
String parsed = parseIncomingLine(line);
if (!parsed.isEmpty()) {
handler.onMessage(parsed);
System.out.println("📩 Meddelande: " + parsed);
}
- }
- }))
+ });
+ })Also ensure that 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| String parseIncomingLine(String line) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| JsonNode outer = mapper.readTree(line); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| String raw = outer.path("message").asText(""); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (raw.isEmpty()) return ""; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| String clean = raw.startsWith("{") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? mapper.readTree(raw).path("message").asText(raw) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : raw; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!clean.contains("[Eric Chat App]") && !clean.contains("[Javafx-chat]")) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| clean = "[Javafx-chat] " + clean; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return "💬 " + clean; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (Exception e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| System.err.println("⚠️ Kunde inte tolka rad: " + line + " | " + e.getMessage()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return ""; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public interface MessageHandler { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| void onMessage(String message); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| package com.example; | ||
|
|
||
| import com.fasterxml.jackson.annotation.JsonIgnoreProperties; | ||
|
|
||
| @JsonIgnoreProperties(ignoreUnknown = true) | ||
| public record NtfyMessageDto(String event, String topic, String message) {} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,11 @@ | ||
| module hellofx { | ||
| requires javafx.controls; | ||
| requires javafx.fxml; | ||
| requires java.net.http; | ||
| requires io.github.cdimascio.dotenv.java; | ||
| requires com.fasterxml.jackson.databind; | ||
| requires com.fasterxml.jackson.annotation; | ||
|
|
||
| opens com.example to javafx.fxml; | ||
| opens com.example to javafx.fxml, com.fasterxml.jackson.databind; | ||
| exports com.example; | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Verify dependency and plugin versions (Java 25, JavaFX 25, JUnit 5.13.4, Surefire 3.2.5)
The structure of the POM looks good and aligns with the new features (JavaFX, dotenv, Jackson, JUnit 5 + Surefire). The main thing to double‑check is that the chosen versions actually exist in your environment and match the JDK you’re using:
maven.compiler.release=25and JavaFX25→ ensure you’re really building against a JDK/JavaFX SDK that supports this combo.junit.jupiter.version=5.13.4→ confirm this version is published and matches the Surefire version.maven-surefire-plugin=3.2.5withorg.junit.jupiter:junit-jupiter→ in general this pairing should work, but still worth validating withmvn test.You can quickly verify by running a dependency resolution + tests locally and checking for version resolution errors.
Also applies to: 55-71
🏁 Script executed:
Length of output: 68
🏁 Script executed:
Length of output: 123
🌐 Web query:
💡 Result:
Java 25 (JDK 25) reached general availability on September 16, 2025. Downloads/ builds are available from Oracle (Oracle JDK), the OpenJDK reference builds (jdk.java.net/25), and major vendors (e.g., Microsoft Build of OpenJDK). [1][2][3][4]
Sources:
🌐 Web query:
💡 Result:
JavaFX 25 is generally available. The GA release (JavaFX 25) was published September 15, 2025, with binaries (SDK/jmods) downloadable from the official JavaFX page (jdk.java.net/javafx25) and openjfx.io. A subsequent 25.0.1 update was released October 21, 2025. [1][2][3]
Sources:
🌐 Web query:
💡 Result:
Yes. JUnit 5.13.4 was released and published to Maven Central on July 21, 2025. [1][2]
Sources:
[1] JUnit 5.13.4 release notes (July 21, 2025).
[2] Maven Central (org/junit/jupiter/junit-jupiter/5.13.4) listing (artifacts dated July 21, 2025).
🌐 Web query:
💡 Result:
Short answer: Yes — Maven Surefire Plugin 3.2.5 natively supports running JUnit 5 (the JUnit Platform / Jupiter) via the built-in junit-platform provider. [1][2]
Caveat: 3.2.5 ships with/controls JUnit Platform launcher/engine versions (it pulls junit-platform-launcher / engine 1.9.3), so it can conflict with newer JUnit Jupiter/Platform releases (e.g. JUnit 5.10+ / platform 1.10.x). If you use a newer JUnit 5 (Jupiter) version, either:
References:
If you want, tell me which JUnit Jupiter/platform version you're using and I’ll give the exact pom.xml changes to make it work.
Critical: Maven Surefire 3.2.5 incompatible with JUnit 5.13.4
All specified versions (Java 25, JavaFX 25, JUnit 5.13.4, Surefire 3.2.5) are published and available. However, verification uncovered a compatibility issue: Maven Surefire Plugin 3.2.5 ships with JUnit Platform 1.9.3, which can conflict with newer JUnit Jupiter/Platform releases like JUnit 5.10+ that require Platform 1.10.x. JUnit 5.13.4 (released July 2025) falls into this newer range and will likely trigger version conflicts during builds or test execution.
Fix: Upgrade
maven-surefire-pluginto version 3.3.x or later, or downgradejunit.jupiter.versionto 5.9.x/5.10.x that aligns with Platform 1.9.3. After resolving, runmvn testlocally to confirm compatibility.🤖 Prompt for AI Agents