Skip to content
Open
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
cd58553
add deadline
github-classroom[bot] Dec 15, 2025
f043eb4
Add Main and Film class.
linneawardalhotmailcom Dec 16, 2025
86c2ac2
Add Director Class with getters and setters.
linneawardalhotmailcom Dec 16, 2025
5c33218
Add entity manager to Main.
linneawardalhotmailcom Dec 16, 2025
c5b0d5f
Add OneToMany in Director Class.
linneawardalhotmailcom Dec 16, 2025
3f3262f
Made yearOfDeath nullable.
linneawardalhotmailcom Dec 16, 2025
5125f3a
Fixed issues according to Coderabbit.
linneawardalhotmailcom Dec 17, 2025
bc6883c
Merge pull request #2 from ithsjava25/feature
linneawardalhotmailcom Dec 17, 2025
4d51d1f
Update README.md
mattiasbarth Dec 18, 2025
be0e7b4
Adds the basic framework for the CLI, printing menus based on the use…
EdvinSandgren Jan 7, 2026
5427500
Add files via upload
JohanHiths Jan 7, 2026
0135fb8
Adds the basic interface for the CRUD operations.
EdvinSandgren Jan 8, 2026
cc6a16e
Add files via upload
JohanHiths Jan 8, 2026
719fa14
Add files via upload
JohanHiths Jan 8, 2026
27cc14b
Add files via upload
JohanHiths Jan 8, 2026
d253f70
Add files via upload
JohanHiths Jan 9, 2026
438577a
Add files via upload
JohanHiths Jan 10, 2026
b27871c
Add files via upload
JohanHiths Jan 10, 2026
41fcca0
fixed issues that CodeRabbit highlighted
mattiasbarth Jan 12, 2026
02a6b0e
Fix some more issues from CodeRabbit, clean up some code.
mattiasbarth Jan 12, 2026
0066a05
Remove Director, Film and Main from Java-root.
mattiasbarth Jan 12, 2026
9bf2aca
update Directory.java and DirectorRepositoryImpl.java
mattiasbarth Jan 12, 2026
55889b0
Fixed problems identified by CodeRabbit
mattiasbarth Jan 12, 2026
887f1e1
Fixed problems identified by CodeRabbit
mattiasbarth Jan 12, 2026
ad87eed
Add FilmDTO, FilmRepository, FilmRepository, FilmService abd update F…
mattiasbarth Jan 12, 2026
daa00c8
Update FilmRepository, FilmRepositoryImpl and FilmService
mattiasbarth Jan 12, 2026
effd2b1
update FilmRepositoryImpl
mattiasbarth Jan 12, 2026
d330599
Updates Director Menu in CLI to implement methods in DirectorService
EdvinSandgren Jan 13, 2026
01bf50a
add and add code to SeriesDTO, SeriesRepository, SeriesRepositoryImpl…
mattiasbarth Jan 13, 2026
3c10c42
Add files via upload
JohanHiths Jan 13, 2026
9b8ceaa
update BaseRepositoryImpl, DirectorRepositoryImpl and SeriesService a…
mattiasbarth Jan 13, 2026
109988c
Updates menus to implement methods in Service classes for CRUD operat…
EdvinSandgren Jan 14, 2026
57b7d4e
Add files via upload
JohanHiths Jan 14, 2026
b043f55
Implements fixes highlighted by CodeRabbit
EdvinSandgren Jan 14, 2026
e2f2c57
Add files via upload
JohanHiths Jan 14, 2026
42d834d
Merge pull request #8 from ithsjava25/feature/CLI
JohanHiths Jan 14, 2026
cfde7f8
Merge pull request #7 from ithsjava25/johan
mattiasbarth Jan 14, 2026
ba087fb
update BaseRepositoryImpl, Director, FilmRepositoryImpl and SeriesRep…
mattiasbarth Jan 14, 2026
a6de7d4
Merge branch 'main' into mattias
mattiasbarth Jan 14, 2026
a1beeb5
Merge pull request #9 from ithsjava25/mattias
EdvinSandgren Jan 14, 2026
e91d463
Fixes various issues related to merges
EdvinSandgren Jan 14, 2026
e9fb1ae
Fixes minor issues identified by CodeRabbit
EdvinSandgren Jan 14, 2026
4929c8f
Adds some missing methods and changes a few field names
EdvinSandgren Jan 14, 2026
1ea47d7
Merge pull request #10 from ithsjava25/feature/merge
mattiasbarth Jan 14, 2026
af12454
Add files via upload
JohanHiths Jan 14, 2026
cff7dee
Add files via upload
JohanHiths Jan 14, 2026
3d148c3
Merge branch 'main' into johan
mattiasbarth Jan 14, 2026
5dff5c6
Add files via upload
JohanHiths Jan 14, 2026
File filter

Filter by extension

Filter by extension

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

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

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

### ✅ Vecka 2 – Funktionalitet och relationer
- [ ] Dela upp funktioner mellan gruppmedlemmar
Expand Down
76 changes: 76 additions & 0 deletions src/main/java/Director.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import jakarta.persistence.*;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Entity
public class Director {
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 all Director entity classes in the codebase
echo "=== Searching for Director entity classes ==="
rg -n "@Entity" --type=java -A2 | grep -B1 "class Director"

echo ""
echo "=== Searching for Film entity classes ==="
rg -n "@Entity" --type=java -A2 | grep -B1 "class Film"

echo ""
echo "=== List all Java files with @Entity annotation ==="
rg -l "@Entity" --type=java

Repository: ithsjava25/ithsjava25-java-project-jpa-maven-java-template

Length of output: 844


🏁 Script executed:

#!/bin/bash
# Check contents of src/main/java/Director.java to see if java.util.List is used
echo "=== Checking src/main/java/Director.java for List usage ==="
cat -n src/main/java/Director.java | head -30

Repository: ithsjava25/ithsjava25-java-project-jpa-maven-java-template

Length of output: 959


🏁 Script executed:

#!/bin/bash
# Check if List is used anywhere in the file
echo "=== Checking for List usage in src/main/java/Director.java ==="
rg "List" src/main/java/Director.java
echo "Exit code: $?"

Repository: ithsjava25/ithsjava25-java-project-jpa-maven-java-template

Length of output: 200


Critical: Duplicate Director entity will cause JPA conflicts.

This Director class in the default package duplicates src/main/java/org/example/Director.java. Having two @Entity classes with the same name will cause JPA/Hibernate mapping conflicts and unpredictable behavior. The same issue exists with Film.java in the default package duplicating src/main/java/org/example/Film.java.

Additionally, the unused import java.util.List (line 4) should be removed.

Both files in the default package should be deleted. The properly organized entities in the org.example package should be used instead.

🤖 Prompt for AI Agents
In @src/main/java/Director.java around lines 1 - 8, There are duplicate JPA
entities defined in the default package (Director and Film) causing mapping
conflicts and an unused import; remove the duplicate classes named Director and
Film in the default package so only the entities in org.example remain, and
delete the unused import java.util.List from the top of the default-package
Director.java (and similarly remove any stray imports in the default-package
Film.java) to resolve the conflicts.


@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@OneToMany(mappedBy = "director")
private Set<Film> films = new HashSet<>();
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

Incomplete relationship mapping compared to org.example.Director.

This version lacks the @ManyToMany relationship with Series and the cascade/orphanRemoval settings present in org.example.Director. If this file is kept (which is not recommended), it will have inconsistent behavior.

🤖 Prompt for AI Agents
In @src/main/java/Director.java around lines 14 - 15, The Director entity is
missing the ManyToMany relationship with Series and the cascade/orphanRemoval
semantics present in org.example.Director; update the Director class to add a
bidirectional @ManyToMany (e.g., a Set<Series> series field) with the same
mappedBy, cascade and orphanRemoval settings as the reference, and ensure the
existing @OneToMany Set<Film> films retains its mapping while keeping collection
initialization and proper equals/hashCode handling to avoid inconsistent
behavior.


private String name;
private String country;
private int birthYear;
@Column(nullable = true)
private Integer yearOfDeath;



public Set<Film> getFilms() {
return films;
}

public void setFilms(Set<Film> films) {
this.films = films;
}

public Integer getYearOfDeath() {
return yearOfDeath;
}

public void setYearOfDeath(Integer yearOfDeath) {
this.yearOfDeath = yearOfDeath;
}

public int getBirthYear() {
return birthYear;
}

public void setBirthYear(int birthYear) {
this.birthYear = birthYear;
}

public String getCountry() {
return country;
}

public void setCountry(String country) {
this.country = country;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public void setId(Long id) {
this.id = id;
}

public Long getId() {
return id;
}


}


39 changes: 39 additions & 0 deletions src/main/java/Film.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import jakarta.persistence.*;

@Entity
public class Film {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String title;
@ManyToOne
@JoinColumn(name = "director_id")
private Director director;

public Director getDirector() {
return director;
}

public void setDirector(Director director) {
this.director = director;
}

public String getTitle() {
return title;
}

public void setTitle(String title) {
this.title = title;
}

public void setId(Long id) {
this.id = id;
}

public Long getId() {
return id;
}


}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
42 changes: 42 additions & 0 deletions src/main/java/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import jakarta.persistence.Entity;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;
import jakarta.persistence.PersistenceConfiguration;
import org.hibernate.jpa.HibernatePersistenceConfiguration;

import java.util.List;

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


final PersistenceConfiguration cfg = new HibernatePersistenceConfiguration("emf")
.jdbcUrl("jdbc:mysql://localhost:3306/film_database")
.jdbcUsername("root")
.jdbcPassword("root")
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

Hardcoded database credentials pose a security risk.

Database credentials should not be committed to source control. Consider using environment variables, configuration files excluded from version control, or a secrets management solution.

♻️ Suggested approach using environment variables
-            .jdbcUrl("jdbc:mysql://localhost:3306/film_database")
-            .jdbcUsername("root")
-            .jdbcPassword("root")
+            .jdbcUrl(System.getenv("DATABASE_URL"))
+            .jdbcUsername(System.getenv("DATABASE_USER"))
+            .jdbcPassword(System.getenv("DATABASE_PASSWORD"))
📝 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
.jdbcUrl("jdbc:mysql://localhost:3306/film_database")
.jdbcUsername("root")
.jdbcPassword("root")
.jdbcUrl(System.getenv("DATABASE_URL"))
.jdbcUsername(System.getenv("DATABASE_USER"))
.jdbcPassword(System.getenv("DATABASE_PASSWORD"))
🤖 Prompt for AI Agents
In @src/main/java/Main.java around lines 14 - 16, The code currently hardcodes
DB credentials in the builder calls (.jdbcUrl, .jdbcUsername, .jdbcPassword);
replace those literals with values read from environment variables (e.g.,
System.getenv("DB_URL"), System.getenv("DB_USER"), System.getenv("DB_PASS")) or
a config/secrets provider, and ensure you handle missing values by providing a
sensible default or throwing a clear exception during startup; update the calls
to .jdbcUrl(...), .jdbcUsername(...), and .jdbcPassword(...) to use these
variables and add minimal validation/error logging so the application fails fast
if credentials are not supplied.

.property("hibernate.hbm2ddl.auto", "update")
.property("hibernate.show_sql", "true")
.property("hibernate.format_sql", "true")
.property("hibernate.highlight_sql", "true")
.managedClasses(Film.class, Director.class);
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

Duplicate entity definitions exist across packages.

Film and Director are defined both in the default package (used here) and in org.example. This duplication will cause confusion and maintenance issues. The default package is also discouraged in Java—consider consolidating all entities in org.example and moving this Main class there as well.

🤖 Prompt for AI Agents
In @src/main/java/Main.java at line 21, The project currently registers entities
Film and Director from the default package in Main.managedClasses(Film.class,
Director.class) while duplicates exist under org.example; move the Main class
into the org.example package and update the managedClasses call to reference the
org.example versions (or remove the default-package entity classes and keep only
org.example.Film and org.example.Director), ensuring all imports in Main refer
to org.example.Film and org.example.Director so there is a single canonical
entity package.

try (EntityManagerFactory emf = cfg.createEntityManagerFactory()) {
emf.runInTransaction(em -> {
//If no Films in database, add some
if (em.createQuery("select count(o) from Film o", Long.class)
.getSingleResult() == 0) {
Film film1 = new Film();
em.persist(film1);
em.flush();
Film film2 = new Film();
em.persist(film2);
}
System.out.println("==== Using select query, N + 1 ====");
em.createQuery("from Film", Film.class)
.getResultList().forEach(System.out::println);
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

Seeded Film entities have no meaningful data and lack a toString() override.

The Film objects are persisted without setting title or director, and Film doesn't override toString(), so the output will be unhelpful (e.g., Film@hashcode). Consider adding data and implementing toString() for useful output.

🤖 Prompt for AI Agents
In @src/main/java/Main.java around lines 27 - 35, The seeded Film instances are
empty and Film lacks a toString(), so update the seeding code to set meaningful
fields (e.g., call film1.setTitle(...); film1.setDirector(...); and same for
film2) before em.persist/em.flush, and implement a Film.toString() override in
the Film class that returns a readable representation (e.g., include title and
director) so the em.createQuery("from Film",
Film.class).getResultList().forEach(System.out::println) prints useful output;
adjust constructors or setters used in the seeding code to match existing Film
APIs.


});

}

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

import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.MappedSuperclass;

@MappedSuperclass
public abstract class BaseEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

public Long getId() {
return id;
}

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

import jakarta.persistence.EntityManager;

import java.util.Optional;

public class BaseRepositoryImpl<T extends org.example.BaseEntity> implements Repository<T> {

protected EntityManager em;
protected Class<T> entityClass;


public BaseRepositoryImpl(EntityManager em, Class<T> entityClass) {
this.em = em;
this.entityClass = entityClass;
}
Comment on lines +7 to +19
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

EntityManager can be null when methods are called.

The em field is only set via setEntityManager(), but all methods use it without null checks. If a caller forgets to set the EntityManager, any operation will throw NullPointerException.

Consider either:

  1. Requiring EntityManager in the constructor, or
  2. Adding a defensive check in methods.
🐛 Option 1: Require EntityManager in constructor
-    public BaseRepositoryImpl(Class<T> entityClass) {
+    public BaseRepositoryImpl(Class<T> entityClass, EntityManager em) {
         this.entityClass = entityClass;
+        this.em = em;
     }
-
-    public void setEntityManager(EntityManager em) {
-        this.em = em;
-    }
📝 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 class BaseRepositoryImpl<T extends org.example.BaseEntity> implements Repository<T> {
protected EntityManager em;
protected Class<T> entityClass;
public BaseRepositoryImpl(Class<T> entityClass) {
this.entityClass = entityClass;
}
public void setEntityManager(EntityManager em) {
this.em = em;
}
public class BaseRepositoryImpl<T extends org.example.BaseEntity> implements Repository<T> {
protected EntityManager em;
protected Class<T> entityClass;
public BaseRepositoryImpl(Class<T> entityClass, EntityManager em) {
this.entityClass = entityClass;
this.em = em;
}
🤖 Prompt for AI Agents
In `@src/main/java/org/example/BaseRepositoryImpl.java` around lines 7 - 19, The
repository currently allows em to be null because it's only set via
setEntityManager; change BaseRepositoryImpl to require an EntityManager in the
constructor so em is always initialized: update the constructor signature of
BaseRepositoryImpl to accept EntityManager (e.g., BaseRepositoryImpl(Class<T>
entityClass, EntityManager em)) and assign this.em and this.entityClass there,
and remove or deprecate setEntityManager; after this change all methods using em
can assume non-null. If you prefer the defensive approach instead, add a private
helper (e.g., checkEntityManager() or requireEntityManager()) called at the
start of every public method to throw IllegalStateException with a clear message
if em == null, referencing the em field and setEntityManager method.



public T save(T entity) {
if (entity == null) {

throw new IllegalArgumentException("Entity cannot be null");
}
if (entity.getId() == null) {
em.persist(entity);
return entity;
}
else {
return em.merge(entity);
}
}



public EntityManager getEntityManager() {
return em;
}

@Override
public Optional<T> findById(Long id) {
return Optional.ofNullable(em.find(entityClass, id));
}

@Override
public void delete(T entity) {
em.remove(em.contains(entity) ? entity : em.merge(entity));
}

@Override
public void deleteById(Long id) {
T entity = em.find(entityClass, id);
if (entity != null) {
em.remove(entity);
}
}

@Override
public Iterable<T> findAll() {
return em.createQuery(
"select e from " + entityClass.getSimpleName() + " e", entityClass
).getResultList();
}

@Override
public boolean existsById(Long id) {
Long count = em.createQuery(
"select count(e) from " + entityClass.getSimpleName() + " e where e.id = :id",
Long.class
).setParameter("id", id).getSingleResult();
return count > 0;

}

@Override
public long count() {

return em.createQuery("select count(e) from " + entityClass.getSimpleName() + " e", Long.class).getSingleResult();
}

@Override
public void flush() {
em.flush();
}

@Override
public void clear() {
em.clear();
}

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

public class BusinessException extends Throwable {
public BusinessException(String s) {
}
Comment on lines +3 to +5
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

Exception message is discarded; consider extending Exception instead of Throwable.

Two issues:

  1. Critical: The constructor parameter s is ignored. Without calling super(s), getMessage() will always return null, making debugging and logging ineffective.

  2. Convention: Extending Throwable directly is unusual. Business exceptions typically extend Exception (checked) or RuntimeException (unchecked). Throwable is the common ancestor of both Exception and Error, and Error is reserved for serious JVM-level problems.

🐛 Proposed fix
-public class BusinessException extends Throwable {
-    public BusinessException(String s) {
-    }
+public class BusinessException extends Exception {
+    public BusinessException(String message) {
+        super(message);
+    }
 }
📝 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 class BusinessException extends Throwable {
public BusinessException(String s) {
}
public class BusinessException extends Exception {
public BusinessException(String message) {
super(message);
}
}
🤖 Prompt for AI Agents
In `@src/main/java/org/example/BusinessException.java` around lines 3 - 5,
BusinessException currently extends Throwable and ignores the constructor
parameter `s`; change the class to extend Exception (or RuntimeException if you
want unchecked) and have the constructor call super(s) so getMessage() returns
the provided message; update any callers/throws declarations if you switch to
RuntimeException.

}
Loading