Skip to content

feature/continuationTableRelations#4

Merged
LinusWestling merged 8 commits intomainfrom
feature/continuationTableRelations
Dec 18, 2025
Merged

feature/continuationTableRelations#4
LinusWestling merged 8 commits intomainfrom
feature/continuationTableRelations

Conversation

@LinusWestling
Copy link
Copy Markdown

@LinusWestling LinusWestling commented Dec 17, 2025

Summary by CodeRabbit

Release Notes

  • New Features

    • Added movie rating system allowing users to rate films
    • Introduced favorite movies collection for personalized user preferences
    • Enhanced movie filtering capabilities by release date, length, ranking, and language
  • Refactor

    • Reorganized seeding infrastructure for improved maintainability
    • Simplified internal entity comparison logic

✏️ Tip: You can customize this high-level summary in your review settings.

Linus Westling and others added 8 commits December 17, 2025 09:01
…p-5-d into feature/continuationTableRelations

# Conflicts:
#	src/main/java/org/example/pojo/Actor.java
#	src/main/java/org/example/pojo/Director.java
#	src/main/java/org/example/pojo/Genre.java
#	src/main/java/org/example/pojo/Movie.java
#	src/main/java/org/example/pojo/User.java
…, director, actor, user, ratings and favorites

Co-authored-by: Oscar Nidemar <oscar.nidemar@gmail.com>

Co-authored-by: Oskar Lundqvist <oskar.lundqvist3@icloud.com>

Co-authored-by: Mark Cavric <cavric_123@hotmail.se>

Co-authored-by: Linus Westling <westling.linus@gmail.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Dec 17, 2025

Walkthrough

This PR refactors a JPA-based movie database project by reorganizing seeding classes into a dedicated org.example.seed package, expanding repository interfaces with new filtering and management methods, modifying entity equality logic to be id-based, and introducing comprehensive relationship management for movies, ratings, and user favorites. Multiple unused repository interfaces are removed.

Changes

Cohort / File(s) Summary
Seeding Infrastructure Reorganization
src/main/java/org/example/App.java, src/main/java/org/example/SeedActors.java (deleted), src/main/java/org/example/SeedUsers.java (deleted)
Removed seeding classes from root package; expanded App.main() with comprehensive seed orchestration including genre, actor, director, movie, user seeding and relation attachment; added error handling with RuntimeException rollback.
Seeding Classes (New Package)
src/main/java/org/example/seed/SeedActors.java, src/main/java/org/example/seed/SeedUsers.java, src/main/java/org/example/seed/SeedDirectors.java, src/main/java/org/example/seed/SeedGenres.java, src/main/java/org/example/seed/SeedMovies.java
Relocated and refactored seed classes to org.example.seed package; updated return types (SeedMovies now returns Map<String, Movie>); added actor and user seed data.
Relationship Seeding
src/main/java/org/example/seed/SeedMovieRelations.java, src/main/java/org/example/seed/SeedUserRelations.java
New classes to attach movie-actor/director/genre relationships via MovieRepoJpa and manage user favorites/ratings via UserRepoJpa and UserRatingRepoJpa.
Repository Interface Updates
src/main/java/org/example/repo/MovieRepo.java, src/main/java/org/example/repo/UserRatingRepo.java, src/main/java/org/example/repo/ActorRepo.java, src/main/java/org/example/repo/DirectorRepo.java, src/main/java/org/example/repo/GenreRepo.java, src/main/java/org/example/repo/UserRepo.java
Added filtering methods (by release date, length, ranking, language); added country filtering for actors/directors; refactored user rating and favorite movie methods; removed unused methods.
Repository JPA Implementations
src/main/java/org/example/jpaimpl/MovieRepoJpa.java, src/main/java/org/example/jpaimpl/UserRepoJpa.java, src/main/java/org/example/jpaimpl/UserRatingRepoJpa.java
MovieRepoJpa no longer implements MovieRepo interface; added helper methods for title-based lookups and transactional relation attachment; UserRepoJpa gained favorite movie management; UserRatingRepoJpa added rateMovie() with aggregate recalculation.
POJO Entity Classes
src/main/java/org/example/pojo/Actor.java, src/main/java/org/example/pojo/Director.java, src/main/java/org/example/pojo/Genre.java, src/main/java/org/example/pojo/Movie.java, src/main/java/org/example/pojo/User.java
Modified equals() and hashCode() to be id-based only across all classes; Genre added constructors and accessors; Movie changed ranking from float to double and added rating/relation helper methods; User added favorite movie management.
New Entity Class
src/main/java/org/example/pojo/UserRating.java
Introduced as a proper JPA entity with id, rating (double), and bidirectional relationships to User and Movie; includes standard accessors and id-based equality.
Enum & Cleanup
src/main/java/org/example/enums/Country.java, src/main/java/org/example/jpaimpl/ActorRepoJpa.java
Added KENYA and PUERTO_RICO to Country enum; minor formatting in ActorRepoJpa.
Removed Unused Interfaces
src/main/java/org/example/unusedRepos/MovieActorRepo.java, src/main/java/org/example/unusedRepos/MovieDirectorRepo.java, src/main/java/org/example/unusedRepos/MovieGenreRepo.java, src/main/java/org/example/unusedRepos/UserFavoritesRepo.java
Deleted all four unused repository interfaces and their methods.

Sequence Diagram(s)

sequenceDiagram
    participant App
    participant SeedActors
    participant SeedDirectors
    participant SeedGenres
    participant SeedMovies
    participant MovieRepoJpa
    participant SeedMovieRelations
    participant SeedUsers
    participant UserRepoJpa
    participant SeedUserRelations
    participant UserRatingRepoJpa
    participant EntityManager

    App->>SeedActors: seed()
    SeedActors->>SeedActors: create Map<String, Actor>
    SeedActors-->>App: Map<String, Actor>

    App->>SeedDirectors: seed()
    SeedDirectors-->>App: Map<String, Director>

    App->>SeedGenres: seed()
    SeedGenres-->>App: Map<String, Genre>

    App->>SeedMovies: seedMovies()
    SeedMovies->>MovieRepoJpa: addMovie(...)
    SeedMovies-->>App: Map<String, Movie>

    rect rgb(100, 180, 200)
    Note over App,EntityManager: Attach Relationships
    App->>SeedMovieRelations: attachRelations(actors, directors, genres, movieRepo)
    SeedMovieRelations->>MovieRepoJpa: setDirector(title, director)
    SeedMovieRelations->>MovieRepoJpa: addActors(title, actors)
    SeedMovieRelations->>MovieRepoJpa: addGenres(title, genres)
    SeedMovieRelations->>EntityManager: flush() + clear()
    end

    App->>SeedUsers: seed()
    SeedUsers->>UserRepoJpa: addUser(name, password)
    SeedUsers-->>App: Map<String, User>

    rect rgb(150, 200, 150)
    Note over App,EntityManager: Seed User Relationships
    App->>SeedUserRelations: seedFavoritesAndRatings(users, movies)
    SeedUserRelations->>UserRepoJpa: addFavoriteMovie(userId, movie)
    SeedUserRelations->>UserRatingRepoJpa: rateMovie(user, movie, rating)
    SeedUserRelations->>EntityManager: flush() + clear()
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Areas requiring special attention:

  • Equality and Hashing Semantics: All POJOs now use id-only equality; verify this doesn't break existing business logic or relationship uniqueness checks across the application.
  • Movie Ranking Type Change (floatdouble): Confirm all usages in queries, comparisons, and data migrations are compatible.
  • MovieRepoJpa Interface Removal: Verify all callers handle the interface removal and that the new transactional methods (setDirector, addActors, addGenres) are correctly scoped.
  • UserRating Entity Refactoring: Check bidirectional relationship consistency with Movie.ratings and User; validate cascade behavior and orphan deletion settings.
  • Seeding Orchestration: Review the new seeding order and error handling in App.main(); ensure em.flush() and em.clear() calls don't cause premature transaction termination.
  • Float to Double in UserRating: Verify rating calculations and comparisons respect the new precision.

Possibly related PRs

  • feature/entityImpl #1: Modifies the same core entity POJOs, repository implementations, and seeding infrastructure—directly related at the code level.

Poem

🐰 From scattered seeds to gardens neat,
We organize what's disparate—
Where actors, directors, genres meet,
Their bonds secured, their hashes state.
By id alone we now compare,
Each relationship with tender care! 🌿

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.98% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main objective of expanding table relations in the codebase, which aligns with the extensive changes to entity relationships, seed classes, and repository methods throughout the PR.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/continuationTableRelations

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

❤️ Share

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

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 14

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/java/org/example/App.java (1)

62-66: Add logging or rethrow exception after rollback.

The exception handler catches RuntimeException and rolls back the transaction but silently swallows the exception. This makes debugging seed failures difficult.

Apply this diff:

 } catch (RuntimeException e) {
     if (tx.isActive()) {
         tx.rollback();
     }
+    throw e; // or log the exception
 }
🧹 Nitpick comments (17)
src/main/java/org/example/pojo/Genre.java (1)

4-4: Unused import.

GenreRepo is imported but never used in this entity class.

-import org.example.repo.GenreRepo;
src/main/java/org/example/repo/MovieRepo.java (2)

27-27: Prefer LocalDate over String for date parameters.

LocalDate is already used in addMovie (line 15). Using String for date range parameters loses type safety and pushes parsing responsibility to implementations.

-    List<Movie> getMovieByReleaseDate(String from, String to);
+    List<Movie> getMovieByReleaseDate(LocalDate from, LocalDate to);

27-31: Naming inconsistency: getBy* vs getMovieBy*.

Existing methods use getByDirector, getByActor, while new methods use getMovieByReleaseDate, getMovieByLength, etc. Consider aligning naming for consistency.

src/main/java/org/example/seed/SeedUserRelations.java (1)

41-42: Consider clarifying the need for flush() and clear().

The em.flush() and em.clear() pattern is used here after seeding all user relations. While this can help with memory management during batch operations, it's worth noting that:

  1. flush() synchronizes the persistence context with the database
  2. clear() detaches all managed entities

This is fine for seeding, but ensure this doesn't cause issues if the returned users or moviesMap objects are expected to remain managed after this method returns.

src/main/java/org/example/jpaimpl/UserRatingRepoJpa.java (1)

84-118: Consider adding rating range validation.

The seeding code uses ratings between 1.0 and 5.0, but rateMovie doesn't validate the range. Consider adding validation to ensure data integrity.

Add validation after line 86:

     if (user == null || movie == null) throw new IllegalArgumentException("User or Movie cannot be null");
+    if (rating < 1.0f || rating > 5.0f) throw new IllegalArgumentException("Rating must be between 1.0 and 5.0");
src/main/java/org/example/repo/ActorRepo.java (1)

13-13: Consider renaming getCountry for clarity.

The method name getCountry(Country country) doesn't clearly convey that it returns a list of actors. Consider renaming to findByCountry(Country country) or getActorsByCountry(Country country) to follow standard repository naming conventions and improve readability.

src/main/java/org/example/repo/DirectorRepo.java (1)

13-13: Consider renaming getCountry for clarity.

Same as in ActorRepo, the method name getCountry(Country country) doesn't clearly indicate it returns directors. Consider renaming to findByCountry(Country country) or getDirectorsByCountry(Country country) for consistency and clarity.

src/main/java/org/example/jpaimpl/UserRepoJpa.java (1)

108-115: Consider throwing exception instead of silent failure.

The method silently returns if user or movie is null (line 111), which makes debugging difficult. Consider either:

  1. Throwing IllegalArgumentException for invalid inputs (consistent with UserRatingRepoJpa.rateMovie)
  2. Returning a boolean to indicate success/failure (consistent with removeFavoriteMovie)

Option 1 (preferred for consistency with rateMovie):

     public void addFavoriteMovie(long userId, Movie movie) {
+        if (movie == null) throw new IllegalArgumentException("Movie cannot be null");
         User user = em.find(User.class, userId);
-        if (user == null || movie == null) return;
+        if (user == null) throw new IllegalArgumentException("User not found with id: " + userId);

         user.addFavoriteMovie(movie);
         em.merge(user);
     }
src/main/java/org/example/pojo/Actor.java (1)

49-58: The current implementation is actually safe, but the id-only equals/hashCode pattern remains risky.

While your concern about id-based equality is a valid JPA anti-pattern, verification shows the codebase handles it correctly: actors are persisted via ActorRepoJpa.addActor() (which calls em.persist()) before being added to Movie.actors HashSet. Since actors have non-null IDs when added to collections, the hashCode mutation problem doesn't occur in the current seeding flow.

However, this pattern is fragile and could break if:

  • Future code adds transient actors to collections before persistence
  • The bidirectional relationship (Actor.movies also uses HashSet) is modified

Recommendation: Document the assumption that actors must be persisted before adding to Movie collections, or refactor to use business-key equality (e.g., actorName + country) for robustness. The current code is functional but the pattern should be treated as a technical debt requiring developer discipline.

src/main/java/org/example/seed/SeedUsers.java (1)

79-151: Remove commented-out dead code.

The commented-out alternative implementation (lines 79-151) should be removed to improve maintainability. If this code needs to be preserved for reference, consider using version control history instead.

Apply this diff:

-    /*
-    public void seedUsers() {
-        UserRepoJpa userRepo = new UserRepoJpa(em);
-
-        String[][] users = {
-            {"AliceSmith", "pass123"},
-            {"BobJones", "qwerty"},
-            ...
-        };
-
-        int i = 0;
-        for (String[] u : users) {
-            userRepo.addUser(u[0], u[1]);
-            i++;
-            if (i % 20 == 0) {
-                em.flush();
-                em.clear();
-            }
-        }
-    }
-
-     */
src/main/java/org/example/seed/SeedActors.java (1)

46-46: Consider aligning map key with stored actor name.

The map key is "Ellen Page" while the stored actor name is "Elliot Page". Although this works for immediate map lookups in seeding (Line 115 in SeedMovieRelations uses the key), it creates inconsistency between the lookup key and the persisted entity name. Consider using "Elliot Page" as the key to match the stored name.

Apply this diff:

-        actors.put("Ellen Page", actorRepo.addActor("Elliot Page", Country.CANADA)); // uppdaterat namn
+        actors.put("Elliot Page", actorRepo.addActor("Elliot Page", Country.CANADA)); // uppdaterat namn

And update the corresponding reference in SeedMovieRelations.java (line 115):

-            actors.get("Ellen Page")
+            actors.get("Elliot Page")
src/main/java/org/example/App.java (1)

75-105: Remove or implement the printOptions placeholder.

The printOptions() method contains only commented-out UI planning notes. Either implement the method or remove it to avoid dead code.

src/main/java/org/example/pojo/UserRating.java (1)

27-27: Use consistent type for rating field.

The rating field is declared as double (line 15), but the constructor (line 27) and setter (line 55) accept float parameters. This creates type inconsistency. Consider using double throughout for consistency.

Apply this diff:

-    public UserRating(User user, Movie movie, float rating) {
+    public UserRating(User user, Movie movie, double rating) {
         this.user = user;
         this.movie = movie;
         this.rating = rating;
     }
-    public void setRating(float rating) {
+    public void setRating(double rating) {
         this.rating = rating;
     }

Also applies to: 55-55

src/main/java/org/example/repo/UserRatingRepo.java (2)

12-13: Inconsistent numeric types for rating values.

getRatingForMovieByUser returns Optional<Float> while getAverageRatingForMovie returns Optional<Double>. Consider using a consistent type (preferably Double for averages to avoid precision loss).


20-20: Consider a typed DTO instead of List<Object[]>.

getAverageRatings() returns List<Object[]>, which loses type safety and requires callers to cast elements. A simple record like record MovieRating(Long movieId, Double avgRating) would improve clarity and type safety.

src/main/java/org/example/jpaimpl/MovieRepoJpa.java (1)

4-4: Unused import.

NoResultException is imported but never used since findByTitleOptional uses getResultStream().findFirst().

-import jakarta.persistence.NoResultException;
src/main/java/org/example/pojo/Movie.java (1)

66-69: Defensive copy pattern is good but exposes mutable internal collection via getter.

setActors and setGenres properly clear and re-add, but getActors() and getGenres() return the internal mutable Set directly. Callers can bypass the setter and mutate the collection. For full encapsulation, consider returning an unmodifiable view or a copy.

-    public Set<Actor> getActors() { return actors; }
+    public Set<Actor> getActors() { return Collections.unmodifiableSet(actors); }

Also applies to: 72-75

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6f283fc and 127a358.

📒 Files selected for processing (31)
  • src/main/java/org/example/App.java (3 hunks)
  • src/main/java/org/example/SeedActors.java (0 hunks)
  • src/main/java/org/example/SeedUsers.java (0 hunks)
  • src/main/java/org/example/enums/Country.java (1 hunks)
  • src/main/java/org/example/jpaimpl/ActorRepoJpa.java (0 hunks)
  • src/main/java/org/example/jpaimpl/MovieRepoJpa.java (1 hunks)
  • src/main/java/org/example/jpaimpl/UserRatingRepoJpa.java (1 hunks)
  • src/main/java/org/example/jpaimpl/UserRepoJpa.java (4 hunks)
  • src/main/java/org/example/pojo/Actor.java (1 hunks)
  • src/main/java/org/example/pojo/Director.java (1 hunks)
  • src/main/java/org/example/pojo/Genre.java (2 hunks)
  • src/main/java/org/example/pojo/Movie.java (1 hunks)
  • src/main/java/org/example/pojo/User.java (2 hunks)
  • src/main/java/org/example/pojo/UserRating.java (1 hunks)
  • src/main/java/org/example/repo/ActorRepo.java (1 hunks)
  • src/main/java/org/example/repo/DirectorRepo.java (1 hunks)
  • src/main/java/org/example/repo/GenreRepo.java (1 hunks)
  • src/main/java/org/example/repo/MovieRepo.java (1 hunks)
  • src/main/java/org/example/repo/UserRatingRepo.java (1 hunks)
  • src/main/java/org/example/repo/UserRepo.java (1 hunks)
  • src/main/java/org/example/seed/SeedActors.java (1 hunks)
  • src/main/java/org/example/seed/SeedDirectors.java (3 hunks)
  • src/main/java/org/example/seed/SeedGenres.java (1 hunks)
  • src/main/java/org/example/seed/SeedMovieRelations.java (1 hunks)
  • src/main/java/org/example/seed/SeedMovies.java (3 hunks)
  • src/main/java/org/example/seed/SeedUserRelations.java (1 hunks)
  • src/main/java/org/example/seed/SeedUsers.java (1 hunks)
  • src/main/java/org/example/unusedRepos/MovieActorRepo.java (0 hunks)
  • src/main/java/org/example/unusedRepos/MovieDirectorRepo.java (0 hunks)
  • src/main/java/org/example/unusedRepos/MovieGenreRepo.java (0 hunks)
  • src/main/java/org/example/unusedRepos/UserFavoritesRepo.java (0 hunks)
💤 Files with no reviewable changes (7)
  • src/main/java/org/example/unusedRepos/UserFavoritesRepo.java
  • src/main/java/org/example/unusedRepos/MovieDirectorRepo.java
  • src/main/java/org/example/unusedRepos/MovieActorRepo.java
  • src/main/java/org/example/unusedRepos/MovieGenreRepo.java
  • src/main/java/org/example/jpaimpl/ActorRepoJpa.java
  • src/main/java/org/example/SeedActors.java
  • src/main/java/org/example/SeedUsers.java
🧰 Additional context used
🧬 Code graph analysis (6)
src/main/java/org/example/App.java (1)
src/main/java/org/example/jpaimpl/MovieRepoJpa.java (1)
  • MovieRepoJpa (19-151)
src/main/java/org/example/seed/SeedUserRelations.java (2)
src/main/java/org/example/jpaimpl/UserRatingRepoJpa.java (1)
  • UserRatingRepoJpa (12-120)
src/main/java/org/example/jpaimpl/UserRepoJpa.java (1)
  • UserRepoJpa (13-135)
src/main/java/org/example/seed/SeedActors.java (1)
src/main/java/org/example/jpaimpl/ActorRepoJpa.java (1)
  • ActorRepoJpa (11-85)
src/main/java/org/example/seed/SeedUsers.java (1)
src/main/java/org/example/jpaimpl/UserRepoJpa.java (1)
  • UserRepoJpa (13-135)
src/main/java/org/example/seed/SeedMovieRelations.java (1)
src/main/java/org/example/jpaimpl/MovieRepoJpa.java (1)
  • MovieRepoJpa (19-151)
src/main/java/org/example/pojo/UserRating.java (5)
src/main/java/org/example/pojo/Actor.java (1)
  • Entity (10-59)
src/main/java/org/example/pojo/Director.java (1)
  • Entity (10-52)
src/main/java/org/example/pojo/Genre.java (1)
  • Entity (8-63)
src/main/java/org/example/pojo/Movie.java (1)
  • Entity (10-96)
src/main/java/org/example/pojo/User.java (1)
  • Entity (10-85)
🔇 Additional comments (16)
src/main/java/org/example/pojo/Director.java (1)

43-51: Caution: id-based equals/hashCode can break with transient entities.

When id is null (before persist), all new Director instances will be considered equal and have the same hash code. This breaks HashSet/HashMap behavior if you add multiple unpersisted directors to a collection.

This is a known JPA trade-off. If you use collections of transient entities, consider using a business key or a UUID assigned at construction time instead.

src/main/java/org/example/pojo/User.java (1)

74-84: Same transient entity caveat applies here.

As with the other entities, id-based equals/hashCode will treat all unpersisted User instances as equal. Ensure transient users aren't added to hash-based collections before persistence.

src/main/java/org/example/seed/SeedGenres.java (1)

1-1: Package reorganization looks good.

Moving seed utilities to org.example.seed improves project organization by clearly separating seeding logic from domain and repository code.

src/main/java/org/example/enums/Country.java (1)

17-19: LGTM!

The addition of KENYA and PUERTO_RICO enum constants is clean and follows Java enum conventions. The trailing comma after UK is a good practice for easier future additions.

src/main/java/org/example/seed/SeedMovies.java (2)

1-1: LGTM! Good refactoring.

Moving seed classes to a dedicated org.example.seed package improves code organization and maintainability.


21-21: LGTM! Return type change enables relation seeding.

Returning Map<String, Movie> allows downstream seeding operations (like SeedMovieRelations and SeedUserRelations) to reference the seeded movies, which is a necessary change for the relationship management introduced in this PR.

Also applies to: 100-100

src/main/java/org/example/jpaimpl/UserRepoJpa.java (2)

41-52: LGTM! Clean implementation.

The findByUserName method correctly uses getResultStream().findFirst() to return an Optional<User>, following best practices for nullable results.


108-133: User entity correctly implements favorite movie management methods.

The User entity at line 67-72 contains both addFavoriteMovie() and removeFavoriteMovie() methods that properly manage the favoriteMovies Set. The relationship is correctly defined as a @manytomany mapping with a join table at lines 24-29, allowing the repository methods to safely add and remove movies from the user's favorites.

src/main/java/org/example/seed/SeedDirectors.java (2)

1-1: LGTM! Package reorganization aligns with seeding refactor.

The move to org.example.seed package improves code organization by consolidating all seeding utilities.


45-72: LGTM! Expanded director seed data supports new movie relations.

The additions include both real directors (Jon Watts, the Russo brothers, George Lucas, etc.) and fictional placeholders, which align with the movie seeding strategy visible in SeedMovieRelations.

src/main/java/org/example/repo/GenreRepo.java (1)

12-12: LGTM! Duplicate method declaration removed.

The consolidation of the getAllGenres() declaration improves interface clarity.

src/main/java/org/example/seed/SeedActors.java (1)

19-109: LGTM! Comprehensive actor seeding with proper country associations.

The seed data covers a wide range of real actors and fictional placeholders, properly utilizing the expanded Country enum (including KENYA, PUERTO_RICO, ROMANIA). The structure aligns well with the seeding strategy.

src/main/java/org/example/repo/UserRepo.java (1)

13-14: LGTM! Favorites management API added.

The new methods getFavoriteMovies, addFavoriteMovie, removeFavoriteMovie, and findByUserName provide comprehensive user favorites management functionality that aligns with the relationship-seeding workflow introduced in this PR.

Also applies to: 18-18, 22-22

src/main/java/org/example/App.java (1)

35-58: LGTM! Well-structured seeding workflow.

The seeding sequence logically seeds base entities first (genres, actors, directors, movies, users), then establishes relationships (movie relations, user favorites/ratings). The use of maps returned by seed methods enables efficient relation attachment.

src/main/java/org/example/seed/SeedMovieRelations.java (1)

20-445: LGTM! Comprehensive movie relation attachment with proper EntityManager management.

The method systematically attaches directors, actors, and genres to movies using the provided repository. The em.flush() and em.clear() at the end properly manage the persistence context. The structure is clear and maintainable despite the repetitive nature.

src/main/java/org/example/pojo/UserRating.java (1)

12-24: LGTM! UserRating entity properly implements JPA relationships and identity.

The entity correctly maps the many-to-one relationships with User and Movie, and implements id-based equality consistent with other entities in the codebase. The JPA annotations are appropriate for the relationship structure.

Also applies to: 34-69

public class App {
public static void main(String[] args) {

static void main(String[] args) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Check the current main method signature
cat -n src/main/java/org/example/App.java | head -20

# Search for any invocations of App.main()
rg "App\.main|\.main\(" --type java

Repository: ithsjava25/project-jpa-grupp-5-d

Length of output: 901


🏁 Script executed:

# Check if there are any other main methods or entry points
rg "void main\(" --type java

# Look at project structure to understand the context
cat -n pom.xml | head -50

# Check for any build configuration that specifies the main class
rg "<mainClass>" --type xml

Repository: ithsjava25/project-jpa-grupp-5-d

Length of output: 2413


Restore public modifier to main method entry point.

The main method at line 15 is missing the public modifier, deviating from Java entry point convention. This should be public static void main(String[] args) to follow standard practice.

-    static void main(String[] args) {
+    public static void main(String[] args) {
📝 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
static void main(String[] args) {
public static void main(String[] args) {
🤖 Prompt for AI Agents
In src/main/java/org/example/App.java around line 15, the main method is
declared as "static void main(String[] args)" but must be the standard public
entry point; change the method signature to include the public modifier so it
reads "public static void main(String[] args)" to restore the proper Java
application entry point.

Comment on lines +64 to 93
public Movie addMovie(String title,
LocalDate releaseDate,
int length,
Country country,
Language language,
Director director,
List<Actor> actors,
List<Genre> genres) {
Optional<Movie> existing = findByTitleOptional(title);

if (existing.isPresent()) {
Movie movie = existing.get();
movie.setDirector(director);
movie.setActors(Set.copyOf(actors));
movie.setGenres(Set.copyOf(genres));
return movie;
} else {
Movie movie = new Movie();
movie.setTitle(title);
movie.setReleaseDate(date);
movie.setTitle(title.trim());
movie.setReleaseDate(releaseDate);
movie.setLength(length);
movie.setCountry(country);
movie.setLanguage(language);
movie.setDirector(director);
movie.setActors(Set.copyOf(actors));
movie.setGenres(Set.copyOf(genres));
em.persist(movie);
return movie;
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Inconsistent update behavior between addMovie overloads.

The first addMovie overload (lines 28-61) updates metadata (releaseDate, length, country, language) when a movie exists. This overload only updates relations (director, actors, genres) but ignores metadata fields. This inconsistency may lead to unexpected behavior.

Consider aligning the update logic:

         if (existing.isPresent()) {
             Movie movie = existing.get();
+            movie.setReleaseDate(releaseDate);
+            movie.setLength(length);
+            movie.setCountry(country);
+            movie.setLanguage(language);
             movie.setDirector(director);
             movie.setActors(Set.copyOf(actors));
             movie.setGenres(Set.copyOf(genres));
             return movie;
📝 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
public Movie addMovie(String title,
LocalDate releaseDate,
int length,
Country country,
Language language,
Director director,
List<Actor> actors,
List<Genre> genres) {
Optional<Movie> existing = findByTitleOptional(title);
if (existing.isPresent()) {
Movie movie = existing.get();
movie.setDirector(director);
movie.setActors(Set.copyOf(actors));
movie.setGenres(Set.copyOf(genres));
return movie;
} else {
Movie movie = new Movie();
movie.setTitle(title);
movie.setReleaseDate(date);
movie.setTitle(title.trim());
movie.setReleaseDate(releaseDate);
movie.setLength(length);
movie.setCountry(country);
movie.setLanguage(language);
movie.setDirector(director);
movie.setActors(Set.copyOf(actors));
movie.setGenres(Set.copyOf(genres));
em.persist(movie);
return movie;
}
}
public Movie addMovie(String title,
LocalDate releaseDate,
int length,
Country country,
Language language,
Director director,
List<Actor> actors,
List<Genre> genres) {
Optional<Movie> existing = findByTitleOptional(title);
if (existing.isPresent()) {
Movie movie = existing.get();
movie.setReleaseDate(releaseDate);
movie.setLength(length);
movie.setCountry(country);
movie.setLanguage(language);
movie.setDirector(director);
movie.setActors(Set.copyOf(actors));
movie.setGenres(Set.copyOf(genres));
return movie;
} else {
Movie movie = new Movie();
movie.setTitle(title.trim());
movie.setReleaseDate(releaseDate);
movie.setLength(length);
movie.setCountry(country);
movie.setLanguage(language);
movie.setDirector(director);
movie.setActors(Set.copyOf(actors));
movie.setGenres(Set.copyOf(genres));
em.persist(movie);
return movie;
}
}
🤖 Prompt for AI Agents
In src/main/java/org/example/jpaimpl/MovieRepoJpa.java around lines 64 to 93,
the addMovie overload updates only relations for an existing Movie but not
metadata (releaseDate, length, country, language), causing inconsistent behavior
with the other overload; update the existing Movie to also set releaseDate,
length, country, language (and trim/set title if appropriate) before returning,
and keep em.persist only for the new-movie branch so you consistently update
both metadata and relations on existing entities.

Comment on lines +114 to 122
@Transactional
public boolean deleteMovie(long id) {
Movie movie = em.find(Movie.class, id);
if (movie != null) {
em.remove(movie);
return true;
}
return false;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for MovieRepoJpa instantiation patterns
echo "=== Looking for direct instantiation with 'new' ==="
rg -n "new MovieRepoJpa" --type java

echo "=== Looking for DI annotations with MovieRepoJpa ==="
rg -n "@Inject|@Autowired" --type java -A 3 | grep -B 3 -A 3 "MovieRepoJpa"

echo "=== Checking MovieRepoJpa class definition and scope ==="
fd "MovieRepoJpa.java" --type f -x cat -n {}

Repository: ithsjava25/project-jpa-grupp-5-d

Length of output: 6197


@transactional annotations are ineffective—MovieRepoJpa is instantiated directly.

MovieRepoJpa is instantiated directly (not via dependency injection) in src/main/java/org/example/App.java:53 and src/main/java/org/example/seed/SeedMovies.java:22. Container interception is required for @Transactional to work; direct instantiation via new MovieRepoJpa(em) bypasses this interception, causing these annotations to have no effect:

  • deleteMovie (line 114)
  • setDirector (line 125)
  • addActors (line 134)
  • addGenres (line 143)

Remove the @Transactional annotations or refactor to inject the repository as a CDI/Spring bean.

🤖 Prompt for AI Agents
In src/main/java/org/example/jpaimpl/MovieRepoJpa.java around lines 114-122,
@Transactional on deleteMovie is ineffective because MovieRepoJpa is created
directly with new (bypassing container interception). Fix by either (A) removing
@Transactional from the methods and manage transactions manually in callers, or
(B) make MovieRepoJpa a managed bean (e.g., annotate the class with the
appropriate CDI/Spring stereotype such as @ApplicationScoped/@Repository) and
replace the direct instantiations in src/main/java/org/example/App.java and
src/main/java/org/example/seed/SeedMovies.java with container injection
(@Inject/@Autowired), ensuring the persistence context is injected and
transactions are enabled so @Transactional will be honored.

Comment on lines +126 to 131
public void setDirector(String title, Director director) {
Movie m = findByTitleOptional(title).orElse(null);
if (m != null) {
m.setDirector(director);
em.merge(m);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Silent failure when movie is not found.

setDirector, addActors, and addGenres silently do nothing if the movie title doesn't exist. Consider throwing an exception or returning a boolean to indicate success/failure, allowing callers to handle missing movies appropriately.

     @Transactional
     public void setDirector(String title, Director director) {
-        Movie m = findByTitleOptional(title).orElse(null);
-        if (m != null) {
-            m.setDirector(director);
-            em.merge(m);
-        }
+        Movie m = findByTitleOptional(title)
+            .orElseThrow(() -> new IllegalArgumentException("Movie not found: " + title));
+        m.setDirector(director);
+        em.merge(m);
     }

Also applies to: 135-140, 144-149

🤖 Prompt for AI Agents
In src/main/java/org/example/jpaimpl/MovieRepoJpa.java around lines 126-131 (and
similarly at 135-140 and 144-149), the mutator methods silently return when the
movie title is not found; change them to fail-fast by throwing a specific
exception (e.g., EntityNotFoundException or a custom MovieNotFoundException)
with a clear message when findByTitleOptional(title) is empty, and remove the
silent null-check branch; ensure the method signatures and callers are updated
to either propagate or handle the exception (alternatively, if you prefer a
non-exception approach, change the return type to boolean and return true on
success / false when movie not found, updating all callers accordingly).

Comment on lines +84 to +118
@Override
public void rateMovie(User user, Movie movie, float rating) {
if (user == null || movie == null) throw new IllegalArgumentException("User or Movie cannot be null");

// Check if rating already exists
Optional<UserRating> existing = em.createQuery(
"SELECT ur FROM UserRating ur WHERE ur.user = :user AND ur.movie = :movie",
UserRating.class)
.setParameter("user", user)
.setParameter("movie", movie)
.getResultStream()
.findFirst();

// If already rated, update rating
UserRating userRating;
if (existing.isPresent()) {
userRating = existing.get();
userRating.setRating(rating);
em.merge(userRating);
} else {
userRating = new UserRating(user, movie, rating);
em.persist(userRating);
}

// Update movie ranking
Double avg = em.createQuery(
"SELECT AVG(ur.rating) FROM UserRating ur WHERE ur.movie = :movie",
Double.class)
.setParameter("movie", movie)
.getSingleResult();

movie.setRanking(avg);
em.merge(movie);

}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Potential NoResultException when rating a movie for the first time.

At line 113, getSingleResult() may throw NoResultException if this is the first rating for a movie and the aggregate query returns no rows (depending on JPA provider behavior). Additionally, if avg is null, line 115 could fail.

Apply this diff to handle the edge case safely:

     // Update movie ranking
-    Double avg = em.createQuery(
+    Double avg = em.createQuery(
             "SELECT AVG(ur.rating) FROM UserRating ur WHERE ur.movie = :movie",
             Double.class)
         .setParameter("movie", movie)
-        .getSingleResult();
+        .getResultStream()
+        .findFirst()
+        .orElse(null);

-    movie.setRanking(avg);
+    if (avg != null) {
+        movie.setRanking(avg);
+    }
     em.merge(movie);
📝 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
@Override
public void rateMovie(User user, Movie movie, float rating) {
if (user == null || movie == null) throw new IllegalArgumentException("User or Movie cannot be null");
// Check if rating already exists
Optional<UserRating> existing = em.createQuery(
"SELECT ur FROM UserRating ur WHERE ur.user = :user AND ur.movie = :movie",
UserRating.class)
.setParameter("user", user)
.setParameter("movie", movie)
.getResultStream()
.findFirst();
// If already rated, update rating
UserRating userRating;
if (existing.isPresent()) {
userRating = existing.get();
userRating.setRating(rating);
em.merge(userRating);
} else {
userRating = new UserRating(user, movie, rating);
em.persist(userRating);
}
// Update movie ranking
Double avg = em.createQuery(
"SELECT AVG(ur.rating) FROM UserRating ur WHERE ur.movie = :movie",
Double.class)
.setParameter("movie", movie)
.getSingleResult();
movie.setRanking(avg);
em.merge(movie);
}
@Override
public void rateMovie(User user, Movie movie, float rating) {
if (user == null || movie == null) throw new IllegalArgumentException("User or Movie cannot be null");
// Check if rating already exists
Optional<UserRating> existing = em.createQuery(
"SELECT ur FROM UserRating ur WHERE ur.user = :user AND ur.movie = :movie",
UserRating.class)
.setParameter("user", user)
.setParameter("movie", movie)
.getResultStream()
.findFirst();
// If already rated, update rating
UserRating userRating;
if (existing.isPresent()) {
userRating = existing.get();
userRating.setRating(rating);
em.merge(userRating);
} else {
userRating = new UserRating(user, movie, rating);
em.persist(userRating);
}
// Update movie ranking
Double avg = em.createQuery(
"SELECT AVG(ur.rating) FROM UserRating ur WHERE ur.movie = :movie",
Double.class)
.setParameter("movie", movie)
.getResultStream()
.findFirst()
.orElse(null);
if (avg != null) {
movie.setRanking(avg);
}
em.merge(movie);
}
🤖 Prompt for AI Agents
In src/main/java/org/example/jpaimpl/UserRatingRepoJpa.java around lines 84 to
118, the AVG query uses getSingleResult() which can throw NoResultException or
return null when there are no ratings; update the code to safely obtain the
average by using a non-exception approach (e.g., use getResultList() and extract
the first element or wrap the query in a try/catch for NoResultException), then
treat a null avg as 0.0 (or the desired default) before calling
movie.setRanking(avg) and merging the movie so the method never throws on first
rating and always sets a valid ranking.

Comment on lines +66 to +72
// For user_rating table
public void addFavoriteMovie(Movie movie) {
favoriteMovies.add(movie);
}
public void removeFavoriteMovie(Movie movie) {
favoriteMovies.remove(movie);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Misleading comment: methods manage favorites, not ratings.

The comment says "For user_rating table" but addFavoriteMovie and removeFavoriteMovie manage the favoriteMovies relationship (which maps to User_favorites table per line 26), not ratings.

-    // For user_rating table
+    // For managing favorite movies
     public void addFavoriteMovie(Movie movie) {
📝 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
// For user_rating table
public void addFavoriteMovie(Movie movie) {
favoriteMovies.add(movie);
}
public void removeFavoriteMovie(Movie movie) {
favoriteMovies.remove(movie);
}
// For managing favorite movies
public void addFavoriteMovie(Movie movie) {
favoriteMovies.add(movie);
}
public void removeFavoriteMovie(Movie movie) {
favoriteMovies.remove(movie);
}
🤖 Prompt for AI Agents
In src/main/java/org/example/pojo/User.java around lines 66–72, the inline
comment "For user_rating table" is incorrect for the
addFavoriteMovie/removeFavoriteMovie methods which manage the favoriteMovies
relationship (mapped to the User_favorites table per line 26); update or remove
the comment so it accurately describes these methods (e.g., "For User_favorites
relationship" or "Manage favoriteMovies relationship") to avoid confusion.

));

// The Matrix
movieRepo.setDirector("The Matrix", directors.get("Lana Wachowski")); // lägg till i SeedDirectors
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Add missing director "Lana Wachowski" to SeedDirectors.

Line 64 references directors.get("Lana Wachowski"), but this director is not present in SeedDirectors.java. This will cause a NullPointerException when movieRepo.setDirector is called with a null director.

Add the missing director to SeedDirectors.java:

         directors.put("David Slade", directorRepo.addDirector("David Slade", Country.UK));

+        directors.put("Lana Wachowski", directorRepo.addDirector("Lana Wachowski", Country.USA));
+
         // Nya fiktiva placeholders

Alternatively, if this is intentional, remove or update the movie relation setup for "The Matrix" in SeedMovieRelations.java.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/main/java/org/example/seed/SeedMovieRelations.java around line 64, the
code calls directors.get("Lana Wachowski") but "Lana Wachowski" is not defined
in SeedDirectors.java which will return null; fix by adding a matching director
entry for "Lana Wachowski" in SeedDirectors.java (create the Director object
with the correct data and put it into the directors map with key "Lana
Wachowski"), or if the omission was intentional, remove or change the movie
relation in SeedMovieRelations.java so it uses an existing director key instead.

Comment on lines +24 to +31
for (User user : users.values()) {
// Assign favorite movies
List<Movie> movieList = new ArrayList<>(moviesMap.values());
Collections.shuffle(movieList);
int favoritesCount = 2 + random.nextInt(4);
for (int i = 0; i < favoritesCount; i++){
userRepo.addFavoriteMovie(user.getId(), movieList.get(i));
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Risk of IndexOutOfBoundsException when assigning favorites.

If moviesMap contains fewer movies than favoritesCount (which can be up to 6 with 2 + random.nextInt(4)), line 30 will throw IndexOutOfBoundsException.

Apply this diff to add bounds checking:

         // Assign favorite movies
         List<Movie> movieList = new ArrayList<>(moviesMap.values());
+        if (movieList.isEmpty()) continue;
+        
         Collections.shuffle(movieList);
-        int favoritesCount = 2 + random.nextInt(4);
+        int favoritesCount = Math.min(2 + random.nextInt(4), movieList.size());
         for (int i = 0; i < favoritesCount; i++){
             userRepo.addFavoriteMovie(user.getId(), movieList.get(i));
         }
📝 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
for (User user : users.values()) {
// Assign favorite movies
List<Movie> movieList = new ArrayList<>(moviesMap.values());
Collections.shuffle(movieList);
int favoritesCount = 2 + random.nextInt(4);
for (int i = 0; i < favoritesCount; i++){
userRepo.addFavoriteMovie(user.getId(), movieList.get(i));
}
for (User user : users.values()) {
// Assign favorite movies
List<Movie> movieList = new ArrayList<>(moviesMap.values());
if (movieList.isEmpty()) continue;
Collections.shuffle(movieList);
int favoritesCount = Math.min(2 + random.nextInt(4), movieList.size());
for (int i = 0; i < favoritesCount; i++){
userRepo.addFavoriteMovie(user.getId(), movieList.get(i));
}
🤖 Prompt for AI Agents
In src/main/java/org/example/seed/SeedUserRelations.java around lines 24 to 31,
the code can throw IndexOutOfBoundsException when moviesMap has fewer entries
than the randomly chosen favoritesCount; compute the desired favoritesCount as
before, then clamp it to movieList.size() (e.g., int maxFavorites =
Math.min(favoritesCount, movieList.size())), and iterate up to maxFavorites when
calling userRepo.addFavoriteMovie so you never index past the end of movieList;
keep the Collections.shuffle behavior so chosen favorites remain random.

Comment on lines +33 to +39
// Assign ratings on movies
Collections.shuffle(movieList);
int ratingsCount = 1 + random.nextInt(5);
for (int i = 0; i < ratingsCount; i++){
float rating = 1.0f + random.nextFloat() * 4.0f;
ratingRepo.rateMovie(user, movieList.get(i), rating);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Risk of IndexOutOfBoundsException when assigning ratings.

Similar to the favorites issue, if ratingsCount (up to 6 with 1 + random.nextInt(5)) exceeds the movieList size, line 38 will throw IndexOutOfBoundsException.

Apply this diff to add bounds checking:

         // Assign ratings on movies
         Collections.shuffle(movieList);
-        int ratingsCount = 1 + random.nextInt(5);
+        int ratingsCount = Math.min(1 + random.nextInt(5), movieList.size());
         for (int i = 0; i < ratingsCount; i++){
             float rating = 1.0f + random.nextFloat() * 4.0f;
             ratingRepo.rateMovie(user, movieList.get(i), rating);
         }
📝 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
// Assign ratings on movies
Collections.shuffle(movieList);
int ratingsCount = 1 + random.nextInt(5);
for (int i = 0; i < ratingsCount; i++){
float rating = 1.0f + random.nextFloat() * 4.0f;
ratingRepo.rateMovie(user, movieList.get(i), rating);
}
// Assign ratings on movies
Collections.shuffle(movieList);
int ratingsCount = Math.min(1 + random.nextInt(5), movieList.size());
for (int i = 0; i < ratingsCount; i++){
float rating = 1.0f + random.nextFloat() * 4.0f;
ratingRepo.rateMovie(user, movieList.get(i), rating);
}
🤖 Prompt for AI Agents
In src/main/java/org/example/seed/SeedUserRelations.java around lines 33 to 39,
the loop that assigns random ratings can exceed movieList size and cause
IndexOutOfBoundsException; ensure ratingsCount is bounded by the list size or
guard the loop. Change the code so ratingsCount = Math.min(movieList.size(), 1 +
random.nextInt(5)) or keep ratingsCount but iterate with for (int i = 0; i <
ratingsCount && i < movieList.size(); i++) so you never access movieList beyond
its length.

Comment on lines +21 to +74
users.put("AliceSmith", userRepo.addUser("AliceSmith", "pass123"));
users.put("BobJones", userRepo.addUser("BobJones", "qwerty"));
users.put("CharlieBrown", userRepo.addUser("CharlieBrown", "abc123"));
users.put("DavidMiller", userRepo.addUser("DavidMiller", "password1"));
users.put("EvaJohnson", userRepo.addUser("EvaJohnson", "123456"));
users.put("FrankWilson", userRepo.addUser("FrankWilson", "letmein"));
users.put("GraceLee", userRepo.addUser("GraceLee", "mypassword"));
users.put("HannahClark", userRepo.addUser("HannahClark", "passw0rd"));
users.put("IanWalker", userRepo.addUser("IanWalker", "admin123"));
users.put("JackHall", userRepo.addUser("JackHall", "welcome1"));

users.put("KarenYoung", userRepo.addUser("KarenYoung", "hello123"));
users.put("LeoKing", userRepo.addUser("LeoKing", "sunshine"));
users.put("MiaScott", userRepo.addUser("MiaScott", "flower99"));
users.put("NathanAdams", userRepo.addUser("NathanAdams", "moonlight"));
users.put("OliviaBaker", userRepo.addUser("OliviaBaker", "star123"));
users.put("PeterWright", userRepo.addUser("PeterWright", "dragon1"));
users.put("QuinnHarris", userRepo.addUser("QuinnHarris", "blueSky"));
users.put("RachelGreen", userRepo.addUser("RachelGreen", "green123"));
users.put("SamRoberts", userRepo.addUser("SamRoberts", "robot2025"));
users.put("TinaEvans", userRepo.addUser("TinaEvans", "tiger12"));

users.put("UmaCarter", userRepo.addUser("UmaCarter", "queen99"));
users.put("VictorMitchell", userRepo.addUser("VictorMitchell", "viking1"));
users.put("WendyPerez", userRepo.addUser("WendyPerez", "wonder12"));
users.put("XanderCooper", userRepo.addUser("XanderCooper", "xmen123"));
users.put("YaraReed", userRepo.addUser("YaraReed", "yellow22"));
users.put("ZacharyBell", userRepo.addUser("ZacharyBell", "zebra99"));
users.put("AmberRussell", userRepo.addUser("AmberRussell", "apple12"));
users.put("BrandonWard", userRepo.addUser("BrandonWard", "banana34"));
users.put("CaitlynBennett", userRepo.addUser("CaitlynBennett", "catDog1"));
users.put("DerekCook", userRepo.addUser("DerekCook", "delta99"));

users.put("EllaFoster", userRepo.addUser("EllaFoster", "echo2025"));
users.put("FelixGray", userRepo.addUser("FelixGray", "falcon1"));
users.put("GabriellaHunt", userRepo.addUser("GabriellaHunt", "galaxy9"));
users.put("HenryJames", userRepo.addUser("HenryJames", "harbor12"));
users.put("IslaKnight", userRepo.addUser("IslaKnight", "icecream"));
users.put("JasonLong", userRepo.addUser("JasonLong", "joker99"));
users.put("KylieMorgan", userRepo.addUser("KylieMorgan", "kangaroo"));
users.put("LiamNelson", userRepo.addUser("LiamNelson", "lion123"));
users.put("MeganOwens", userRepo.addUser("MeganOwens", "mountain"));
users.put("NoahPerry", userRepo.addUser("NoahPerry", "nova99"));

users.put("OlgaQuinn", userRepo.addUser("OlgaQuinn", "olive123"));
users.put("PaulRoss", userRepo.addUser("PaulRoss", "panda1"));
users.put("QuincySims", userRepo.addUser("QuincySims", "queenBee"));
users.put("RileyTurner", userRepo.addUser("RileyTurner", "river12"));
users.put("SophiaUnderwood", userRepo.addUser("SophiaUnderwood", "sunset"));
users.put("ThomasVega", userRepo.addUser("ThomasVega", "tornado"));
users.put("UlyssesWhite", userRepo.addUser("UlyssesWhite", "unicorn"));
users.put("VanessaXavier", userRepo.addUser("VanessaXavier", "volcano"));
users.put("WilliamYoung", userRepo.addUser("WilliamYoung", "whale99"));
users.put("XimenaZimmer", userRepo.addUser("XimenaZimmer", "xylophone"));
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find and examine UserRepoJpa.addUser implementation
find . -type f -name "UserRepoJpa.java" | head -5

Repository: ithsjava25/project-jpa-grupp-5-d

Length of output: 128


🏁 Script executed:

#!/bin/bash
# Search for addUser method implementation with context
rg -n -A 15 "public User addUser\(" --type java

Repository: ithsjava25/project-jpa-grupp-5-d

Length of output: 1478


🏁 Script executed:

#!/bin/bash
# Look for password hashing imports and methods
rg -n "encrypt|hash|bcrypt|argon|password.*encode" --type java | head -20

Repository: ithsjava25/project-jpa-grupp-5-d

Length of output: 1316


Implement password hashing before persistence.

Passwords are stored in plain text in the database. The UserRepoJpa.addUser() method at line 35 directly persists the password without encryption: user.setPassword(password). This is a critical security vulnerability.

Implement password hashing using bcrypt, Argon2, or PBKDF2 in the User entity or repository layer before persistence. Update both SeedUsers.java and UserRepoJpa.addUser() to use hashed passwords.

@LinusWestling LinusWestling merged commit a48098b into main Dec 18, 2025
2 checks passed
@LinusWestling LinusWestling deleted the feature/continuationTableRelations branch December 18, 2025 07:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant