Conversation
Update pom.xml with dependencies.
First version docker-compose
…n branch Feature/entity tatjana merge into main branch.
data from API
data from API
setup httpClient and gson
movieId and Credits with movieId
Adds initial TMDB integration: - TMDB API client with timeout and error handling - DTOs for top rated movies, movie details and credits - Gson mapping with @SerializedName - Package naming aligned with Java conventions (api, dto)
…olumn rabbit review
This PR updates the entity model with a combination of bug fixes and refactoring. - Release year is now stored as a numeric year for improved consistency - Added a validated TMDB identifier to Movie for reliable external references - Simplified Person by removing birth date and image URL fields These changes improve data consistency and simplify the domain model.
This PR refactors the database setup by moving EntityManagerFactory initialization and transaction management into a dedicated JPAUtil class. - Centralizes database connection and transaction handling for reuse - Simplifies application startup logic - Initializes the database schema on startup and logs a confirmation message This improves code organization, maintainability, and consistency.
…directly for now) to create cards for each movie shown at start page.
WalkthroughThis PR introduces a complete JavaFX-based movie database application stack with JPA entities (Movie, Person, Role), TMDB API integration via a client and DTO layer, a data source abstraction for the UI, and a JavaFX interface that fetches and displays top-rated movies from TMDB with database and Docker persistence configuration. Changes
Sequence DiagramsequenceDiagram
participant User
participant App as App.java
participant MainApp
participant MainController
participant ApiDataSource
participant TmdbClient
participant TMDB as TMDB API
participant Database
participant JPAUtil
User->>App: launch(args)
App->>JPAUtil: inTransaction (init block)
JPAUtil->>Database: create EntityManager
Database-->>JPAUtil: EntityManager ready
JPAUtil->>Database: commit
Database-->>JPAUtil: success
App->>MainApp: start(stage)
MainApp->>MainApp: load MainView.fxml
MainApp->>MainApp: create TmdbClient()
MainApp->>MainApp: create ApiDataSource(tmdbClient)
MainApp->>MainController: instantiate with ApiDataSource
MainController->>MainController: `@FXML` initialize()
MainController->>ApiDataSource: getTopRatedMovies()
ApiDataSource->>TmdbClient: getTopRatedMovies()
TmdbClient->>TMDB: GET /movie/top_rated?api_key=...
TMDB-->>TmdbClient: JSON response (movies)
TmdbClient->>TmdbClient: deserialize to TopRatedResponseDTO
TmdbClient-->>ApiDataSource: TopRatedResponseDTO
ApiDataSource-->>MainController: List<MovieDTO>
MainController->>MainController: render movie cards in FlowPane
MainApp->>App: stage.show()
App-->>User: display UI
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 11
🧹 Nitpick comments (22)
src/main/java/org/example/repository/MovieRepository.java (1)
3-4: Consider defining this as an interface to follow the repository pattern.The standard repository pattern uses an interface to define the contract and a separate implementation class. This improves testability and allows for multiple implementations.
🔎 Proposed refactor to interface
-public class MovieRepository { +public interface MovieRepository { + // Define repository methods here when ready }src/main/java/org/example/service/MovieServices.java (1)
1-4: Consider removing the stub class or adding a TODO comment.This empty class provides no functionality. If it's genuinely temporary, consider either:
- Removing it until implementation is ready (preferred)
- Adding a TODO comment explaining the planned functionality
Keeping empty placeholder classes can create confusion about the codebase's actual structure.
src/main/java/org/example/ui/MovieDataSource.java (1)
9-10: Minor: Remove extra blank lines.Consider removing the trailing blank lines for cleaner formatting.
src/main/resources/MainView.fxml (2)
14-32: VBox wrapper appears unnecessary.The
VBoxwraps only theScrollPaneand the commented-outToolBar. If the toolbar remains disabled, the VBox adds no value. Consider placing theScrollPanedirectly in the<center>or uncommenting the toolbar when ready.
25-30: Commented-out code should be tracked separately.The disabled toolbar hints at planned functionality. Consider removing the commented code and tracking it in an issue or TODO list to keep the FXML clean.
pom.xml (1)
47-61: Inconsistent indentation in dependencies block.These dependencies use different indentation levels than the newly added ones (lines 19-28, 63-87). Consider normalizing to 4-space indentation for consistency.
src/main/java/org/example/ui/ApiMovieDataSource.java (2)
11-13: Consider adding null validation for the constructor parameter.If
tmdbClientis null, the error will only surface whengetTopRatedMovies()is called, making debugging harder.🔎 Proposed fix
public ApiMovieDataSource(TmdbClient tmdbClient) { + if (tmdbClient == null) { + throw new IllegalArgumentException("tmdbClient must not be null"); + } this.tmdbClient = tmdbClient; }
15-18: Remove the noise comment.The inline comment
// or searchMovies(), etc.doesn't add value and should be removed.🔎 Proposed fix
@Override public List<MovieDTO> getTopRatedMovies() { - return tmdbClient.getTopRatedMovies().results(); // or searchMovies(), etc. + return tmdbClient.getTopRatedMovies().results(); }src/main/java/org/example/ui/MainApp.java (2)
14-20: Inconsistent indentation.Lines 15-20 use 8-space indentation while the rest of the method uses 4-space. Normalize the formatting.
🔎 Proposed fix
public void start(Stage stage) { try { - TmdbClient tmdbClient = new TmdbClient(); - MovieDataSource dataSource = new ApiMovieDataSource(tmdbClient); - var fxmlUrl = getClass().getResource("/MainView.fxml"); - if (fxmlUrl == null) { - throw new IllegalStateException("Cannot find FXML resource: /MainView.fxml"); - } + TmdbClient tmdbClient = new TmdbClient(); + MovieDataSource dataSource = new ApiMovieDataSource(tmdbClient); + var fxmlUrl = getClass().getResource("/MainView.fxml"); + if (fxmlUrl == null) { + throw new IllegalStateException("Cannot find FXML resource: /MainView.fxml"); + } FXMLLoader loader = new FXMLLoader(fxmlUrl);
15-16: TmdbClient initialization may fail silently before UI loads.
TmdbClient()reads from.envand throwsIllegalArgumentExceptionifTMDB_API_KEYorTMDB_BASE_URLis missing. This exception gets caught by the outer catch block and shows a generic error. Consider providing a more specific error message for missing configuration.🔎 Proposed fix
public void start(Stage stage) { try { - TmdbClient tmdbClient = new TmdbClient(); + TmdbClient tmdbClient; + try { + tmdbClient = new TmdbClient(); + } catch (IllegalArgumentException e) { + throw new IllegalStateException( + "TMDB configuration missing. Please ensure TMDB_API_KEY and TMDB_BASE_URL are set in .env file.", e); + } MovieDataSource dataSource = new ApiMovieDataSource(tmdbClient);src/main/resources/META-INF/persistence.xml (1)
35-42: Review production readiness of these settings.Several settings here are suitable for development but problematic for production:
hbm2ddl.auto=updatecan cause unintended schema changesshow_sql,format_sql,highlight_sqlenabled can leak query details and impact performance- Hibernate's built-in connection pool (
connection.pool_size) is not production-gradeConsider using profiles or external configuration to differentiate dev/prod settings.
src/main/java/org/example/util/JPAUtil.java (1)
13-21: Consider handling static initialization failure gracefully.If
Persistence.createEntityManagerFactory("myPU")fails (e.g., database unavailable), it throws anExceptionInInitializerErrorwhich can be difficult to diagnose. Consider wrapping initialization to provide clearer error messaging or implementing lazy initialization.src/main/java/org/example/dto/MovieDetailsDTO.java (1)
5-15: DTO structure looks good.The record correctly maps TMDB API response fields with appropriate
@SerializedNameannotations for JSON deserialization.Regarding the comment on line 14 about genres: TMDB returns genres as an array of objects (
[{id, name}]), so you'd need a separateGenreDTOrecord and addList<GenreDTO> genreshere if needed.Would you like me to help create a
GenreDTOand integrate it?src/main/java/org/example/ui/MainController.java (3)
3-18: Remove unused imports.Several imports are not used in this file:
FXMLLoader,ListView,MovieServices, andMovie. Clean these up to avoid confusion.🔎 Proposed fix
package org.example.ui; import javafx.fxml.FXML; -import javafx.fxml.FXMLLoader; import javafx.scene.control.Label; -import javafx.scene.control.ListView; import javafx.scene.control.TextField; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.FlowPane; import javafx.scene.layout.Priority; import javafx.scene.layout.VBox; import org.example.dto.MovieDTO; -import org.example.service.MovieServices; -import org.example.movie.entity.Movie; import java.util.List; import java.util.Objects;
22-29: Remove commented-out legacy code.Dead/commented code clutters the file and creates confusion. If this code might be needed later, consider using version control history instead.
Also applies to: 115-124
46-54: Avoide.printStackTrace()in production code.Use a proper logging framework (e.g., SLF4J) instead of
printStackTrace(). Also, consider whether re-throwing aRuntimeExceptionis the desired behavior, as it may cause the application to crash.src/main/java/org/example/movie/entity/Person.java (1)
4-4: Remove unused import.
java.time.LocalDateis imported but not used.🔎 Proposed fix
import jakarta.persistence.*; -import java.time.LocalDate; import java.util.ArrayList;src/main/java/org/example/movie/entity/Role.java (1)
48-61: Bidirectional sync is duplicated across entities.Both
Role.setMovie()/setPerson()andMovie.addRole()/Person.addRole()manage the bidirectional relationship. For example, callingmovie.addRole(role)setsrole.movie = this, which then tries to add the role back tomovie.roles. Thecontains()check prevents duplicates but creates confusing semantics.Consider choosing one owner for the relationship sync:
- Keep sync only in the owning side helpers (
Movie.addRole,Person.addRole) and simplify setters:🔎 Simplified setters
public void setMovie(Movie movie) { this.movie = movie; - if (movie != null && !movie.getRoles().contains(this)) { - movie.getRoles().add(this); - } } public void setPerson(Person person) { this.person = person; - if (person != null && !person.getRoles().contains(this)) { - person.getRoles().add(this); - } }src/main/java/org/example/api/TmdbClient.java (3)
5-5: Remove unused import.The
JSONUtilsimport is not used anywhere in this class.🔎 Proposed fix
-import nonapi.io.github.classgraph.json.JSONUtils;
53-53: Replace debug print with proper logging.The
System.out.printlnstatement should be removed or replaced with a proper logging framework (e.g., SLF4J) for production code.🔎 Proposed fix
- System.out.println("TMDB BASE URL = " + baseUrl);
56-132: Consider extracting common HTTP logic to reduce duplication.All three methods (
getTopRatedMovies,getMovieDetails,getMovieCredits) share nearly identical HTTP request/response handling logic. Consider extracting this into a private helper method to improve maintainability.🔎 Example refactoring approach
private <T> T fetchFromTmdb(String endpoint, Class<T> responseType) { try { String url = baseUrl + endpoint + (endpoint.contains("?") ? "&" : "?") + "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(), responseType); } catch (Exception e) { throw new RuntimeException("Could not fetch from TMDB: " + endpoint, e); } } public TopRatedResponseDTO getTopRatedMovies() { return fetchFromTmdb("/movie/top_rated", TopRatedResponseDTO.class); } public MovieDetailsDTO getMovieDetails(int movieId) { return fetchFromTmdb("/movie/" + movieId, MovieDetailsDTO.class); } public CreditsDTO getMovieCredits(int movieId) { return fetchFromTmdb("/movie/" + movieId + "/credits", CreditsDTO.class); }src/main/java/org/example/movie/entity/Movie.java (1)
38-41: Consider validating title in the constructor.The
titlefield has@Column(nullable = false), but the constructor doesn't validate that the providedtitleis not null. While JPA will enforce this constraint at persistence time, validating in the constructor provides fail-fast behavior and clearer error messages.🔎 Proposed fix
public Movie(String title, Integer tmdbId) { + if (title == null || title.trim().isEmpty()) { + throw new IllegalArgumentException("title cannot be null or empty"); + } + if (tmdbId == null || tmdbId <= 0) { + throw new IllegalArgumentException("tmdbId must be a positive number"); + } this.title = title; - this.tmdbId = tmdbId; + this.tmdbId = tmdbId; }
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
src/main/resources/Images/no-poster.jpgis excluded by!**/*.jpg
📒 Files selected for processing (26)
.gitignore(1 hunks)README.md(2 hunks)docker-compose.yml(1 hunks)pom.xml(2 hunks)src/main/java/org/example/App.java(1 hunks)src/main/java/org/example/api/TmdbClient.java(1 hunks)src/main/java/org/example/dto/CastDTO.java(1 hunks)src/main/java/org/example/dto/CreditsDTO.java(1 hunks)src/main/java/org/example/dto/CrewDTO.java(1 hunks)src/main/java/org/example/dto/MovieDTO.java(1 hunks)src/main/java/org/example/dto/MovieDetailsDTO.java(1 hunks)src/main/java/org/example/dto/TopRatedResponseDTO.java(1 hunks)src/main/java/org/example/movie/entity/Movie.java(1 hunks)src/main/java/org/example/movie/entity/Person.java(1 hunks)src/main/java/org/example/movie/entity/Role.java(1 hunks)src/main/java/org/example/movie/entity/RoleType.java(1 hunks)src/main/java/org/example/repository/MovieRepository.java(1 hunks)src/main/java/org/example/repository/MovieRepositoryImp.java(1 hunks)src/main/java/org/example/service/MovieServices.java(1 hunks)src/main/java/org/example/ui/ApiMovieDataSource.java(1 hunks)src/main/java/org/example/ui/MainApp.java(1 hunks)src/main/java/org/example/ui/MainController.java(1 hunks)src/main/java/org/example/ui/MovieDataSource.java(1 hunks)src/main/java/org/example/util/JPAUtil.java(1 hunks)src/main/resources/META-INF/persistence.xml(1 hunks)src/main/resources/MainView.fxml(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (7)
src/main/java/org/example/ui/ApiMovieDataSource.java (1)
src/main/java/org/example/api/TmdbClient.java (1)
TmdbClient(16-133)
src/main/java/org/example/ui/MainApp.java (2)
src/main/java/org/example/api/TmdbClient.java (1)
TmdbClient(16-133)src/main/java/org/example/service/MovieServices.java (1)
MovieServices(3-4)
src/main/java/org/example/movie/entity/Role.java (2)
src/main/java/org/example/movie/entity/Movie.java (1)
Entity(8-88)src/main/java/org/example/movie/entity/Person.java (1)
Entity(9-40)
src/main/java/org/example/movie/entity/Person.java (2)
src/main/java/org/example/movie/entity/Movie.java (1)
Entity(8-88)src/main/java/org/example/movie/entity/Role.java (1)
Entity(5-62)
src/main/java/org/example/App.java (2)
src/main/java/org/example/ui/MainApp.java (1)
MainApp(9-51)src/main/java/org/example/util/JPAUtil.java (1)
JPAUtil(9-43)
src/main/java/org/example/movie/entity/Movie.java (2)
src/main/java/org/example/movie/entity/Person.java (1)
Entity(9-40)src/main/java/org/example/movie/entity/Role.java (1)
Entity(5-62)
src/main/java/org/example/ui/MainController.java (1)
src/main/java/org/example/service/MovieServices.java (1)
MovieServices(3-4)
🔇 Additional comments (16)
.gitignore (1)
3-3: LGTM! Essential security practice.Adding
.envto the ignore list prevents API keys and sensitive configuration from being committed to the repository, which aligns with the TmdbClient's use of environment-based configuration.docker-compose.yml (1)
13-14: Good practice: Port binding restricted to localhost.Binding the MySQL port to
127.0.0.1prevents external network access, which is appropriate for a development database.src/main/java/org/example/movie/entity/RoleType.java (1)
3-6: LGTM! Clean enum definition.The enum provides clear type-safe constants for role categorization. The two values (ACTOR, DIRECTOR) cover the current requirements and can be extended later if additional role types are needed.
src/main/java/org/example/dto/CreditsDTO.java (1)
5-9: LGTM! Appropriate DTO record structure.The record definition is clean and follows the pattern established in other DTOs. The field names appear to match the expected JSON structure from TMDB API responses for credits.
src/main/java/org/example/ui/MovieDataSource.java (1)
6-8: LGTM! Clean abstraction for movie data access.The interface provides a clear contract for fetching top-rated movies, enabling easy swapping between data sources (API, database, mock) for testing and flexibility.
src/main/java/org/example/dto/CrewDTO.java (1)
5-10: LGTM! Proper JSON field mapping.The record correctly uses
@SerializedNameto map the snake_case JSON fieldprofile_pathto the camelCase Java fieldprofilePath, following Java naming conventions while maintaining compatibility with the TMDB API response format.src/main/java/org/example/dto/TopRatedResponseDTO.java (1)
7-12: LGTM!Clean record definition with appropriate Gson annotations for snake_case field mapping.
pom.xml (2)
14-14: > Likely an incorrect or invalid review comment.
63-67: Keep the explicitjakarta.persistence-apidependency.The Jakarta Persistence API is not automatically provided by Hibernate and should remain as an explicit dependency for compilation and use in this project. All current documentation and examples with Hibernate 7.x show
jakarta.persistence-apideclared separately.src/main/java/org/example/util/JPAUtil.java (1)
27-42: Transaction handling looks correct.The
inTransactionmethod properly handles the transaction lifecycle: begins transaction, executes work, commits on success, rolls back on failure if active, and always closes the EntityManager in the finally block.src/main/java/org/example/dto/MovieDTO.java (1)
5-12: LGTM!The record is well-structured for the top-rated movies list response, with correct
@SerializedNameannotations for TMDB API field mapping.src/main/java/org/example/movie/entity/Person.java (1)
9-39: Entity structure looks good.The
Personentity is correctly configured with JPA annotations, has a proper protected no-arg constructor for JPA, and the bidirectional relationship withRoleis well-managed through theaddRole()method.src/main/java/org/example/movie/entity/Role.java (1)
5-33: Entity mapping is correct.The
Roleentity properly defines the join table structure with@ManyToOnerelationships to bothMovieandPerson, uses lazy fetching appropriately, and stores the enum as a string.src/main/java/org/example/api/TmdbClient.java (1)
29-42: LGTM: Constructor validation is well-implemented.The constructors properly validate that
apiKeyandbaseUrlare not null, throwingIllegalArgumentExceptionwith clear messages when configuration is missing. The constructor chaining pattern is also appropriate.Also applies to: 44-54
src/main/java/org/example/movie/entity/Movie.java (2)
84-87: LGTM: Bidirectional relationship management is correctly implemented.The
addRolemethod properly maintains bidirectional consistency by adding the role to the collection and setting the movie reference. The implementation inRole.setMovie(from Role.java) includes a duplicate check that prevents the same role from being added twice, ensuring data integrity.
8-34: LGTM: JPA entity structure follows best practices.The entity is properly annotated with appropriate constraints:
@Column(nullable = false, unique = true)ontmdbIdensures data integrity for the external TMDB identifier@Column(length = 1000)ondescriptionprovides adequate space for movie descriptions@OneToManywithCascadeType.ALLensures related roles are managed with the movie lifecycle- Protected no-arg constructor satisfies JPA requirements
| MYSQL_ROOT_PASSWORD: rootpass | ||
| MYSQL_DATABASE: moviedb | ||
| MYSQL_USER: movieuser | ||
| MYSQL_PASSWORD: moviepass |
There was a problem hiding this comment.
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=moviepassThen 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.
| <dependency> | ||
| <groupId>org.slf4j</groupId> | ||
| <artifactId>slf4j-api</artifactId> | ||
| <version>2.0.13</version> | ||
| </dependency> |
There was a problem hiding this comment.
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.
| - [ 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 |
There was a problem hiding this comment.
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.
| - [ 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.
| 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); | ||
| } | ||
| } |
There was a problem hiding this comment.
🛠️ 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 static void main(String[] args) { | ||
| System.out.println("Hello There!"); | ||
| launch(args); | ||
|
|
||
| JPAUtil.inTransaction(em -> { | ||
| System.out.println("Database schema initialized"); | ||
| }); | ||
| } |
There was a problem hiding this comment.
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.
| public Movie(String title, Integer tmdbId) { | ||
| this.title = title; | ||
| this.tmdbId = tmdbId; | ||
| } |
There was a problem hiding this comment.
Apply consistent validation in the constructor.
The constructor directly assigns tmdbId without validation, but the setter (lines 75-80) validates that tmdbId is not null and must be positive. This inconsistency allows invalid tmdbId values to be created via the constructor, violating the @Column(nullable = false, unique = true) constraint and the business rule enforced by the setter.
🔎 Proposed fix
public Movie(String title, Integer tmdbId) {
this.title = title;
- this.tmdbId = tmdbId;
+ setTmdbId(tmdbId);
}Alternatively, duplicate the validation logic in the constructor:
public Movie(String title, Integer tmdbId) {
+ if (tmdbId == null || tmdbId <= 0) {
+ throw new IllegalArgumentException("tmdbId must be a positive number");
+ }
this.title = title;
this.tmdbId = tmdbId;
}📝 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.
| public Movie(String title, Integer tmdbId) { | |
| this.title = title; | |
| this.tmdbId = tmdbId; | |
| } | |
| public Movie(String title, Integer tmdbId) { | |
| this.title = title; | |
| setTmdbId(tmdbId); | |
| } |
🤖 Prompt for AI Agents
In src/main/java/org/example/movie/entity/Movie.java around lines 38 to 41, the
constructor assigns tmdbId directly which bypasses the validation present in the
setter and can create invalid entities; update the constructor to enforce the
same validation as the setter by either calling setTmdbId(tmdbId) from the
constructor or replicating the checks (ensure tmdbId is not null and > 0) and
throw an IllegalArgumentException if the value is invalid so the
@Column(nullable = false, unique = true) and business rules are preserved.
| public class MovieRepositoryImp { | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Fix naming convention and implement the repository interface.
Two improvements needed:
- Naming: The class name should use
Impl(notImp) suffix to follow Java naming conventions for implementation classes. - Interface: This implementation class should implement the
MovieRepositoryinterface (assumingMovieRepositorybecomes an interface as suggested).
🔎 Proposed refactor
First, rename the file from MovieRepositoryImp.java to MovieRepositoryImpl.java, then apply:
-public class MovieRepositoryImp {
+public class MovieRepositoryImpl implements MovieRepository {
+ // Implement repository methods here when ready
}Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In src/main/java/org/example/repository/MovieRepositoryImp.java around lines
3-4, the class uses the wrong naming suffix and does not implement the
repository interface; rename the file to MovieRepositoryImpl.java, change the
class declaration to public class MovieRepositoryImpl implements
MovieRepository, add any required imports, implement (or stub) all methods
declared in the MovieRepository interface (or delegate to an underlying
DAO/service), and update all call sites to reference MovieRepositoryImpl; ensure
compilation by adding @Override annotations for implemented methods and
adjusting package declarations if the file move requires it.
|
|
||
| public class MainApp { | ||
|
|
||
| private final MovieServices movieServices = new MovieServices(); |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Unused field movieServices.
The movieServices field is instantiated but never used. Remove it or implement its intended functionality.
🔎 Proposed fix
public class MainApp {
-
- private final MovieServices movieServices = new MovieServices();
public void start(Stage stage) {📝 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.
| private final MovieServices movieServices = new MovieServices(); | |
| public class MainApp { | |
| public void start(Stage stage) { |
🤖 Prompt for AI Agents
In src/main/java/org/example/ui/MainApp.java at line 11, the private final field
"movieServices" is instantiated but never used; remove the unused field
declaration or use it where intended. If the service is unnecessary, delete the
line "private final MovieServices movieServices = new MovieServices();" and
remove any imports referencing MovieServices; if it should be used, inject or
initialize it properly (prefer constructor injection or a singleton accessor)
and replace any direct new usages with that instance, then call its methods
where needed in the class to fulfill its intended role.
| Label overview = new Label(movie.overview()); | ||
| overview.setWrapText(true); | ||
| overview.setMaxWidth(150); | ||
|
|
||
| VBox.setVgrow(title, Priority.NEVER); | ||
|
|
||
| card.getChildren().addAll(poster, title); |
There was a problem hiding this comment.
Unused overview label created but never added to card.
The overview Label is created and configured (lines 101-103) but never added to card.getChildren(). This appears to be either dead code or an incomplete feature.
🔎 If you want to display the overview, add it to the card
- card.getChildren().addAll(poster, title);
+ card.getChildren().addAll(poster, title, overview);Or remove the unused code if the overview shouldn't be displayed.
📝 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.
| Label overview = new Label(movie.overview()); | |
| overview.setWrapText(true); | |
| overview.setMaxWidth(150); | |
| VBox.setVgrow(title, Priority.NEVER); | |
| card.getChildren().addAll(poster, title); | |
| Label overview = new Label(movie.overview()); | |
| overview.setWrapText(true); | |
| overview.setMaxWidth(150); | |
| VBox.setVgrow(title, Priority.NEVER); | |
| card.getChildren().addAll(poster, title, overview); |
🤖 Prompt for AI Agents
In src/main/java/org/example/ui/MainController.java around lines 101 to 107, a
Label named "overview" is created and configured but never added to the card
children; either add the overview to the card (e.g., include it in the
card.getChildren().addAll(...) call so the overview is displayed, ensuring
layout order and that wrapping/maxWidth remain appropriate) or remove the unused
overview creation and its related configuration lines if the overview should not
be shown.
| <property name="jakarta.persistence.jdbc.user" | ||
| value="movieuser"/> | ||
| <property name="jakarta.persistence.jdbc.password" | ||
| value="moviepass"/> |
There was a problem hiding this comment.
Hardcoded credentials are a security risk.
Database credentials should not be stored in version-controlled configuration files. Consider using environment variables or external configuration (e.g., via persistence-unit property overrides at runtime, or a dotenv approach mentioned in the PR description).
🤖 Prompt for AI Agents
In src/main/resources/META-INF/persistence.xml around lines 27 to 30 the JDBC
username/password are hardcoded which is a security risk; remove the literal
values and change the configuration to read credentials from environment or
external configuration at runtime (e.g., replace with placeholders or omit the
properties and pass
jakarta.persistence.jdbc.user/jakarta.persistence.jdbc.password via system
properties, environment variables, or a runtime persistence-unit property
override), store real secrets in environment variables or a secrets manager (or
dotenv loaded only in non-production), and update deployment docs and CI to
supply the credentials securely rather than committing them to source control.
Update to implement GUI through JavaFX. Temporary structure API => DTO => GUI; will modify when ready to implement database structure.
Summary by CodeRabbit
New Features
Documentation
Chores
✏️ Tip: You can customize this high-level summary in your review settings.