Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
f1f2086
add deadline
github-classroom[bot] Dec 15, 2025
8520f86
Update pom.xml with dependencies
bamsemats Dec 16, 2025
55e019d
Update pom.xml with dependencies.
bamsemats Dec 16, 2025
ed40602
Merge pull request #3 from ithsjava25/mats_branch
bamsemats Dec 16, 2025
d1aaae6
First version docker-compose
TatjanaTrajkovic Dec 16, 2025
3b2957d
Changes after coderabbit review
TatjanaTrajkovic Dec 16, 2025
03b2221
Merge pull request #5 from ithsjava25/feature/dockercompose_tatjana
TatjanaTrajkovic Dec 17, 2025
1787dbe
Update skeleton, create persistence.xml and start with entities.
bamsemats Dec 17, 2025
8ff13d2
version 1 entity
TatjanaTrajkovic Dec 17, 2025
d01637d
version 1 entity
TatjanaTrajkovic Dec 17, 2025
8252c5b
version 3 entity
TatjanaTrajkovic Dec 17, 2025
ab21961
version 3 entity
TatjanaTrajkovic Dec 17, 2025
2730c42
Updates with entity t Persistence
TatjanaTrajkovic Dec 17, 2025
c86c7ed
Changes persistence file to point to the corect db
TatjanaTrajkovic Dec 17, 2025
676443f
Merge pull request #9 from ithsjava25/feature/entity_tatjana into mai…
addee1 Dec 17, 2025
2ea5a94
adds dependency for dotenv and gson
addee1 Dec 17, 2025
69db4ee
adds .env to gitignore
addee1 Dec 17, 2025
eeaaf32
adds empty MovieDTO that represents the
addee1 Dec 17, 2025
e3f0aeb
adds TopRatedResponseDTO that represents the
addee1 Dec 17, 2025
2235457
adds method to get top-rated movies and
addee1 Dec 17, 2025
a9161ab
Updates movie entity
TatjanaTrajkovic Dec 17, 2025
7faddff
adds CastDTO
addee1 Dec 17, 2025
5df2668
adds CrewDTO
addee1 Dec 17, 2025
c98bf88
adds CreditsDTO
addee1 Dec 17, 2025
a34a97b
adds MovieDetailsDTO
addee1 Dec 17, 2025
5b899fd
adds metod to get MovieDetails with
addee1 Dec 17, 2025
30c1788
adds a comment
addee1 Dec 17, 2025
113e894
Updates movie entity from integer to string
TatjanaTrajkovic Dec 17, 2025
67a689a
Updates person entity from string to LocalDate
TatjanaTrajkovic Dec 17, 2025
02513de
Delete RoleType from persistence file
TatjanaTrajkovic Dec 17, 2025
5e5c93f
Updates entity role file
TatjanaTrajkovic Dec 17, 2025
9f53a78
Merge pull request #10 from ithsjava25/feature/entityupdates_tatjana
addee1 Dec 17, 2025
8d4a332
Add JavaFX basics.
bamsemats Dec 18, 2025
67ca487
Convert TMDB DTOs to immutable records and add @SerializedName
addee1 Dec 18, 2025
a9cc81b
Improve TMDB client robustness and error handling
addee1 Dec 18, 2025
ee1ae4f
Use IllegalArgumentException for missing TMDB configuration
addee1 Dec 18, 2025
20acec2
Merge feature/api – add TMDB client and DTOs
addee1 Dec 18, 2025
bffbf99
Delete variables (columns) in persons and update movie with timdbId c…
TatjanaTrajkovic Dec 18, 2025
e710b6b
Delete variables (columns) in persons and update movie with timdbId c…
TatjanaTrajkovic Dec 18, 2025
720d615
Moves EntityManagerFactory from App.java to JPAUtil
TatjanaTrajkovic Dec 18, 2025
32e412c
Changes movie constructor with tmdbid
TatjanaTrajkovic Dec 18, 2025
d61ead3
Fix issues commented on by the all-wise rabbit.
bamsemats Dec 18, 2025
25951ac
Changes App.java with JPAUtil
TatjanaTrajkovic Dec 18, 2025
4fee174
Update movie and person entities (bug fixes and refactoring)
addee1 Dec 18, 2025
3d13bc7
Refactor database initialization and transaction management
addee1 Dec 18, 2025
4d18099
Fix issues commented on by the all-wise rabbit.
bamsemats Dec 18, 2025
64b14d3
Update with pull from main.
bamsemats Dec 18, 2025
d2fdea1
Update with pull from main.
bamsemats Dec 18, 2025
5364429
Update with pull from main.
bamsemats Dec 19, 2025
5f8f90c
Sort GUI with structure/discipline and enable loading data from API (…
bamsemats Dec 19, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
target/
/.idea/
.env
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
[![Review Assignment Due Date](https://classroom.github.com/assets/deadline-readme-button-22041afd0340ce965d47ae6ef1cefeee28c7c493a6346c4f15d667ab976d596c.svg)](https://classroom.github.com/a/_uV8Mn8f)
# 📘 Projektarbete: JPA + Hibernate med GitHub-flöde

Projektet genomförs som antingen en Java CLI-applikation eller med hjälp av JavaFX om ni vill ha ett grafiskt gränssnitt.
Expand All @@ -9,11 +10,11 @@ Kommunikation med databasen ska ske med JPA och Hibernate, enligt code first-met

## 🗓️ Veckoplanering med Checklista
### ✅ Vecka 1 – Grundläggning och struktur
- [ ] Klona GitHub-repo
- [ ] Konfigurera persistence.xml eller använd PersistenceConfiguration i kod
- [ ] Skapa entiteter och verifiera tabellgenerering
- [ ] Lägg till relationer (One-to-Many, Many-to-Many)
- [ ] Arbeta på feature-branches och använd pull requests för kodgranskning
- [ x ] Klona GitHub-repo
- [ x ] Konfigurera persistence.xml eller använd PersistenceConfiguration i kod
- [ x ] Skapa entiteter och verifiera tabellgenerering
- [ x ] Lägg till relationer (One-to-Many, Many-to-Many)
- [ x ] Arbeta på feature-branches och använd pull requests för kodgranskning
Comment on lines +13 to +17
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

Fix markdown checkbox syntax.

The completed checkboxes use [ x ] which won't render properly in markdown. Remove the space between [ and x for correct rendering.

🔎 Proposed fix
-- [ x ] Klona GitHub-repo
-- [ x ] Konfigurera persistence.xml eller använd PersistenceConfiguration i kod
-- [ x ] Skapa entiteter och verifiera tabellgenerering
-- [ x ] Lägg till relationer (One-to-Many, Many-to-Many)
-- [ x ] Arbeta på feature-branches och använd pull requests för kodgranskning
+- [x] Klona GitHub-repo
+- [x] Konfigurera persistence.xml eller använd PersistenceConfiguration i kod
+- [x] Skapa entiteter och verifiera tabellgenerering
+- [x] Lägg till relationer (One-to-Many, Many-to-Many)
+- [x] Arbeta på feature-branches och använd pull requests för kodgranskning
📝 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
- [ x ] Klona GitHub-repo
- [ x ] Konfigurera persistence.xml eller använd PersistenceConfiguration i kod
- [ x ] Skapa entiteter och verifiera tabellgenerering
- [ x ] Lägg till relationer (One-to-Many, Many-to-Many)
- [ x ] Arbeta på feature-branches och använd pull requests för kodgranskning
- [x] Klona GitHub-repo
- [x] Konfigurera persistence.xml eller använd PersistenceConfiguration i kod
- [x] Skapa entiteter och verifiera tabellgenerering
- [x] Lägg till relationer (One-to-Many, Many-to-Many)
- [x] Arbeta på feature-branches och använd pull requests för kodgranskning
🤖 Prompt for AI Agents
In README.md around lines 13 to 17 the markdown checkboxes are written as "[ x
]" which won't render as checked items; update each checkbox token by removing
the extra spaces so completed items use "[x]" (and empty boxes use "[ ]" if
needed) to ensure proper GitHub-flavored Markdown rendering.


### ✅ Vecka 2 – Funktionalitet och relationer
- [ ] Dela upp funktioner mellan gruppmedlemmar
Expand Down
19 changes: 19 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
version: "3.8"

services:
mysql:
image: mysql:8.3
container_name: movieapp_mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: moviedb
MYSQL_USER: movieuser
MYSQL_PASSWORD: moviepass
Comment on lines +9 to +12
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

Move database credentials to environment variables.

Hardcoding database credentials directly in docker-compose.yml creates a security risk, as these values are committed to version control and could be exposed.

🔎 Recommended approach using environment variables

Create a .env file (already in .gitignore) with:

MYSQL_ROOT_PASSWORD=rootpass
MYSQL_DATABASE=moviedb
MYSQL_USER=movieuser
MYSQL_PASSWORD=moviepass

Then reference them in docker-compose.yml:

     environment:
-      MYSQL_ROOT_PASSWORD: rootpass
-      MYSQL_DATABASE: moviedb
-      MYSQL_USER: movieuser
-      MYSQL_PASSWORD: moviepass
+      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
+      MYSQL_DATABASE: ${MYSQL_DATABASE}
+      MYSQL_USER: ${MYSQL_USER}
+      MYSQL_PASSWORD: ${MYSQL_PASSWORD}

Provide a .env.example file in the repository with placeholder values for team members.

🤖 Prompt for AI Agents
In docker-compose.yml around lines 9 to 12, the DB credentials are hardcoded;
move those values into environment variables by removing the literal passwords
and referencing env vars (e.g. MYSQL_ROOT_PASSWORD, MYSQL_DATABASE, MYSQL_USER,
MYSQL_PASSWORD) so docker-compose reads them from the environment; create a .env
(and add it to .gitignore if not already) containing the real secrets for local
use and add a .env.example with placeholder values committed to the repo so team
members know required variables; ensure docker-compose.yml continues to
reference the same variable names and validate by running docker-compose config.

ports:
- "127.0.0.1:3306:3306"
volumes:
- mysql_data:/var/lib/mysql

volumes:
mysql_data:
47 changes: 47 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@
<mockito.version>5.21.0</mockito.version>
</properties>
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
<dependency>
<groupId>io.github.cdimascio</groupId>
<artifactId>dotenv-java</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
Expand Down Expand Up @@ -50,5 +60,42 @@
<artifactId>classgraph</artifactId>
<version>4.8.184</version>
</dependency>
<dependency>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.13</version>
</dependency>
Comment on lines +68 to +72
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

SLF4J API without a binding will produce warnings.

Adding slf4j-api without an implementation (e.g., slf4j-simple, logback-classic) results in "No SLF4J providers were found" warnings at runtime. Consider adding an SLF4J binding or removing this dependency if Hibernate's logging suffices.

🤖 Prompt for AI Agents
In pom.xml around lines 68 to 72, the project declares org.slf4j:slf4j-api
without providing a concrete SLF4J binding, which will cause "No SLF4J providers
were found" warnings at runtime; fix this by either adding a binding dependency
(for example ch.qos.logback:logback-classic or org.slf4j:slf4j-simple) with an
appropriate version to the pom, or remove the slf4j-api entry if you intend to
rely solely on your existing logging implementation (e.g., Hibernate's),
ensuring only one SLF4J binding is present to avoid multiple-binding conflicts.

<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-media</artifactId>
<version>25.0.1</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>25.0.1</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>25.0.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.8</version>
<configuration>
<mainClass>org.example.App</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
20 changes: 18 additions & 2 deletions src/main/java/org/example/App.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,23 @@
package org.example;

public class App {
import javafx.application.Application;
import javafx.stage.Stage;
import org.example.ui.MainApp;
import org.example.util.JPAUtil;

public class App extends Application {

@Override
public void start(Stage primaryStage) {
MainApp mainApp = new MainApp();
mainApp.start(primaryStage);
}

public static void main(String[] args) {
System.out.println("Hello There!");
launch(args);

JPAUtil.inTransaction(em -> {
System.out.println("Database schema initialized");
});
}
Comment on lines 16 to 22
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

Database initialization runs after application exits.

Application.launch() is a blocking call that only returns when the JavaFX application closes. The JPAUtil.inTransaction() block will execute after the user quits the app, which is almost certainly unintended. Move database initialization into start() or before launch().

🔎 Proposed fix
 public static void main(String[] args) {
+    // Initialize database before starting UI
+    JPAUtil.inTransaction(em -> {
+        System.out.println("Database schema initialized");
+    });
+
     launch(args);
-
-    JPAUtil.inTransaction(em -> {
-        System.out.println("Database schema initialized");
-    });
 }
🤖 Prompt for AI Agents
In src/main/java/org/example/App.java around lines 16–22, the
JPAUtil.inTransaction call is placed after Application.launch(), so DB
initialization runs only after the JavaFX app exits; move the initialization out
of main and into the JavaFX lifecycle: either call JPAUtil.inTransaction before
launch() in main (if it does not require the FX thread) or override start(...)
in your Application subclass and run JPAUtil.inTransaction there (or in init()
if you need pre-FX-thread setup); if initialization is long-running, run it off
the FX thread (e.g., CompletableFuture or Executor) and ensure any UI updates
are executed on the FX Application Thread.

}
133 changes: 133 additions & 0 deletions src/main/java/org/example/api/TmdbClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package org.example.api;

import com.google.gson.Gson;
import io.github.cdimascio.dotenv.Dotenv;
import nonapi.io.github.classgraph.json.JSONUtils;
import org.example.dto.CreditsDTO;
import org.example.dto.MovieDetailsDTO;
import org.example.dto.TopRatedResponseDTO;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;

public class TmdbClient {

private final String apiKey;
private final String baseUrl;
private final HttpClient httpClient;
private final Gson gson;


public TmdbClient() {
this(HttpClient.newHttpClient(), new Gson());
}


public TmdbClient(HttpClient httpClient, Gson gson) {

Dotenv dotenv = Dotenv.load();

this.apiKey = dotenv.get("TMDB_API_KEY");
this.baseUrl = dotenv.get("TMDB_BASE_URL");

if (apiKey == null || baseUrl == null) {
throw new IllegalArgumentException("TMDB config missing in .env");
}

this.httpClient = httpClient;
this.gson = gson;
}

public TmdbClient(HttpClient httpClient, Gson gson, String apiKey, String baseUrl) {
if (apiKey == null || baseUrl == null) {
throw new IllegalArgumentException("TMDB config missing");
}

this.httpClient = httpClient;
this.gson = gson;
this.apiKey = apiKey;
this.baseUrl = baseUrl;
System.out.println("TMDB BASE URL = " + baseUrl);
}

public TopRatedResponseDTO getTopRatedMovies() {
try {
String url = baseUrl + "/movie/top_rated?api_key=" + apiKey;

HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.timeout(Duration.ofSeconds(10))
.GET()
.build();

HttpResponse<String> response =
httpClient.send(request, HttpResponse.BodyHandlers.ofString());

if (response.statusCode() != 200) {
throw new RuntimeException(
"TMDB API error: HTTP " + response.statusCode() + " - " + response.body()
);
}

return gson.fromJson(response.body(), TopRatedResponseDTO.class);

} catch (Exception e) {
throw new RuntimeException("Could not get top rated movies from TMDB", e);
}
}
Comment on lines +56 to +80
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

Use TMDB Access Token with Authorization header instead of api_key query parameter.

The API key is currently passed as a query parameter. If logged anywhere—in error messages, debugging output, or monitoring systems—the API key could be exposed.

TMDB API supports a more secure approach: obtain an API Read Access Token from account settings and send it as an Authorization header. This eliminates the risk of accidental exposure through URL logging while providing a read-only authentication method.

🤖 Prompt for AI Agents
In src/main/java/org/example/api/TmdbClient.java around lines 56 to 80, replace
the current use of api_key as a query parameter with the TMDB Read Access Token
sent in an Authorization: Bearer <token> header: stop appending "?api_key=" +
apiKey to the URL (use baseUrl + "/movie/top_rated"), add an Authorization
header using a securely stored accessToken field (e.g., this.accessToken) when
building the HttpRequest, and ensure the access token is not interpolated into
any exception or log messages; also keep the existing response status check and
JSON parsing but avoid including sensitive tokens in thrown messages or logs.


public MovieDetailsDTO getMovieDetails(int movieId) {
try {
String url = baseUrl + "/movie/" + movieId + "?api_key=" + apiKey;

HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.timeout(Duration.ofSeconds(10))
.GET()
.build();

HttpResponse<String> response =
httpClient.send(request, HttpResponse.BodyHandlers.ofString());

if (response.statusCode() != 200) {
throw new RuntimeException(
"TMDB API error: HTTP " + response.statusCode() + " - " + response.body()
);
}

return gson.fromJson(response.body(), MovieDetailsDTO.class);

} catch (Exception e) {
throw new RuntimeException("Could not get movie details from TMDB", e);
}
}

public CreditsDTO getMovieCredits(int movieId) {
try {
String url = baseUrl + "/movie/" + movieId + "/credits?api_key=" + apiKey;

HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.timeout(Duration.ofSeconds(10))
.GET()
.build();

HttpResponse<String> response =
httpClient.send(request, HttpResponse.BodyHandlers.ofString());

if (response.statusCode() != 200) {
throw new RuntimeException(
"TMDB API error: HTTP " + response.statusCode() + " - " + response.body()
);
}

return gson.fromJson(response.body(), CreditsDTO.class);

} catch (Exception e) {
throw new RuntimeException("Could not get movie credits from TMDB", e);
}
}
}
10 changes: 10 additions & 0 deletions src/main/java/org/example/dto/CastDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.example.dto;

import com.google.gson.annotations.SerializedName;

public record CastDTO (
int id,
String name,
@SerializedName("profile_path") String profilePath,
int order // 0 = main actor, 2 = second actor, 3 = third actor etc.
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

Comment appears to have a typo.

The comment states "0 = main actor, 2 = second actor" but likely should be "0 = main actor, 1 = second actor, 2 = third actor" based on typical zero-based ordering.

🔎 Proposed fix
-    int order // 0 = main actor, 2 = second actor, 3 = third actor etc.
+    int order // 0 = main actor, 1 = second actor, 2 = third actor, etc.
📝 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
int order // 0 = main actor, 2 = second actor, 3 = third actor etc.
int order // 0 = main actor, 1 = second actor, 2 = third actor, etc.
🤖 Prompt for AI Agents
In src/main/java/org/example/dto/CastDTO.java around line 9, the inline comment
for the 'order' field has incorrect numbering ("0 = main actor, 2 = second
actor, 3 = third actor"); update the comment to reflect zero-based ordering
(e.g., "0 = main actor, 1 = second actor, 2 = third actor" or similar) so the
sequence is correct and unambiguous.

) {}
9 changes: 9 additions & 0 deletions src/main/java/org/example/dto/CreditsDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.example.dto;

import java.util.List;

public record CreditsDTO(
int id,
List<CastDTO> cast,
List<CrewDTO> crew
) {}
10 changes: 10 additions & 0 deletions src/main/java/org/example/dto/CrewDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.example.dto;

import com.google.gson.annotations.SerializedName;

public record CrewDTO(
int id,
String name,
@SerializedName("profile_path") String profilePath,
String job
) {}
12 changes: 12 additions & 0 deletions src/main/java/org/example/dto/MovieDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.example.dto;

import com.google.gson.annotations.SerializedName;

public record MovieDTO(
int id,
String title,
String overview,
@SerializedName("release_date") String releaseDate,
@SerializedName("vote_average") double voteAverage,
@SerializedName("poster_path") String posterPath
) {}
15 changes: 15 additions & 0 deletions src/main/java/org/example/dto/MovieDetailsDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.example.dto;

import com.google.gson.annotations.SerializedName;

public record MovieDetailsDTO(
int id,
String title,
String overview,
@SerializedName("release_date") String releaseDate,
int runtime,
@SerializedName("vote_average") double voteAverage,
@SerializedName("poster_path") String posterPath

// Should we add a genre DTO?
) {}
12 changes: 12 additions & 0 deletions src/main/java/org/example/dto/TopRatedResponseDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.example.dto;

import com.google.gson.annotations.SerializedName;

import java.util.List;

public record TopRatedResponseDTO(
int page,
List<MovieDTO> results,
@SerializedName("total_pages") int totalPages,
@SerializedName("total_results") int totalResults
) {}
Loading