Skip to content

Vglevel#16

Closed
jesperlarsson1910 wants to merge 8 commits intomainfrom
vglevel
Closed

Vglevel#16
jesperlarsson1910 wants to merge 8 commits intomainfrom
vglevel

Conversation

@jesperlarsson1910
Copy link
Copy Markdown

@jesperlarsson1910 jesperlarsson1910 commented Dec 12, 2025

Summary by CodeRabbit

Release Notes

  • New Features

    • Added login authentication system for user access
    • Introduced interactive menu-driven interface with account management options (create, update password, delete accounts)
    • Added moon mission data querying capabilities (list all missions, retrieve specific mission details, count missions by year)
  • Documentation

    • Updated README with Review Assignment Due Date badge link

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

github-classroom bot and others added 8 commits December 3, 2025 13:53
Signed-off-by: Jesper Larsson <jesper.larsson@iths.se>
Signed-off-by: Jesper Larsson <jesper.larsson@iths.se>
Signed-off-by: Jesper Larsson <jesper.larsson@iths.se>
Signed-off-by: Jesper Larsson <jesper.larsson@iths.se>
Signed-off-by: Jesper Larsson <jesper.larsson@iths.se>
Signed-off-by: Jesper Larsson <jesper.larsson@iths.se>
Signed-off-by: Jesper Larsson <jesper.larsson@iths.se>
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Dec 12, 2025

Walkthrough

The changes introduce a repository pattern architecture replacing direct JDBC calls with a DataSource abstraction. Two new repositories for accounts and missions are added alongside corresponding DTOs. The Main class is substantially refactored to support interactive login and menu-driven operations.

Changes

Cohort / File(s) Summary
Data Transfer Objects
src/main/java/com/repo/DTO/AccountDTO.java, src/main/java/com/repo/DTO/MissionDTO.java
New record classes added for immutable account and mission data representation with their respective fields.
Repository Interfaces
src/main/java/com/repo/AccountRepo.java, src/main/java/com/repo/MoonMissionRepo.java
New interfaces defining contracts for account and mission data access operations (CRUD, lookups, counting).
Repository Implementations
src/main/java/com/repo/AccountRepository.java, src/main/java/com/repo/MoonMissionRepository.java
New JDBC-backed repository classes implementing data access interfaces with SQL queries, prepared statements, and ResultSet-to-DTO mapping.
DataSource Abstraction
src/main/java/com/example/SimpleDriverManagerDataSource.java
New minimal DataSource implementation that wraps DriverManager for connection pooling abstraction.
Main Application
src/main/java/com/example/Main.java
Major refactoring: replaced direct JDBC with repository injection, added instance-based run() method with login flow, interactive menu system, and multiple helper methods for input validation and business logic (CRUD operations, mission queries).
Documentation
README.md
Added Review Assignment Due Date badge link at the top.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Main
    participant Scanner
    participant AccountRepository
    participant MoonMissionRepository

    User->>Main: java Main
    Main->>Scanner: initialize Scanner
    Main->>Main: initialize repositories

    rect rgb(200, 220, 255)
    note over Main,AccountRepository: Login Phase
    Main->>User: prompt username
    User->>Scanner: enter username
    Scanner-->>Main: username
    Main->>User: prompt password
    User->>Scanner: enter password
    Scanner-->>Main: password
    Main->>AccountRepository: matchCredentials(username, password)
    alt Credentials Valid
        AccountRepository-->>Main: true
        Main->>Main: login successful
    else Credentials Invalid
        AccountRepository-->>Main: false
        Main->>User: login failed, retry
    end
    end

    rect rgb(220, 240, 220)
    note over Main,MoonMissionRepository: Menu Operations
    loop until exit
        Main->>User: display menu options
        User->>Scanner: select option
        Scanner-->>Main: menu choice
        
        alt List Missions
            Main->>MoonMissionRepository: getAllMissions()
            MoonMissionRepository-->>Main: List<MissionDTO>
            Main->>User: display missions
        else Get Mission Details
            Main->>User: prompt mission ID
            User->>Scanner: enter ID
            Scanner-->>Main: mission ID
            Main->>MoonMissionRepository: getMissionById(id)
            MoonMissionRepository-->>Main: Optional<MissionDTO>
            Main->>User: display mission details
        else Missions by Year
            Main->>User: prompt year
            User->>Scanner: enter year
            Scanner-->>Main: year
            Main->>MoonMissionRepository: missionCount(year)
            MoonMissionRepository-->>Main: count
            Main->>User: display count
        else Account Operations
            Main->>AccountRepository: CRUD operation
            AccountRepository-->>Main: result
            Main->>User: confirm operation
        end
    end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Main.java: Large refactoring with new login flow, validation helpers, menu system, and multiple repository-backed operations—requires careful review of control flow, input handling, and error paths.
  • Repository implementations: SQL query correctness, prepared statement usage, ResultSet mapping, and exception handling need verification.
  • Architecture integration: Verify DataSource injection, repository initialization, and proper resource cleanup across all data access layers.
  • Input validation methods: Review getValidInt(), getValidName(), getValidSSN(), getValidPassword() for boundary cases and edge conditions.

Poem

🐰 A tale of repositories, clean and bright,
Where DTOs dance in structured light,
Login flows granted with validation's care,
Menu-driven missions float through the air,
From tangled JDBC to patterns so fair! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.08% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'Vglevel' is vague and non-descriptive, providing no meaningful information about the changeset's purpose or main modifications. Replace with a descriptive title summarizing the main change, such as 'Refactor Main to use repository pattern with DataSource and interactive menu' or 'Introduce repository-backed data access layer for accounts and missions'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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: 6

🧹 Nitpick comments (5)
src/main/java/com/repo/MoonMissionRepository.java (1)

63-66: Use an explicit column alias for portability.

rs.getInt("count(*)") relies on the database returning the expression as the column name, which is non-portable across databases. Use an explicit alias for reliability.

              PreparedStatement ps = c.prepareStatement(
-                     "select count(*) from moon_mission where year(launch_date) = ?")) {
+                     "select count(*) as cnt from moon_mission where year(launch_date) = ?")) {
             ps.setInt(1, year);

             ResultSet rs = ps.executeQuery();
             if (rs.next()) {
-                return rs.getInt("count(*)");
+                return rs.getInt("cnt");
             }
src/main/java/com/repo/AccountRepository.java (1)

72-87: Verify INSERT returns generated key if needed.

createAccount doesn't retrieve the auto-generated user_id. If the caller needs the new ID (e.g., for confirmation or further operations), consider using Statement.RETURN_GENERATED_KEYS and returning the created account with its ID.

src/main/java/com/example/SimpleDriverManagerDataSource.java (1)

59-67: unwrap and isWrapperFor don't follow JDBC contract.

Per JDBC spec, unwrap(Class<T>) should throw SQLException if the class is not a wrapper for the requested interface, not return null. Similarly, isWrapperFor should check if this class implements the interface.

     @Override
     public <T> T unwrap(Class<T> iface) throws SQLException {
-        return null;
+        if (isWrapperFor(iface)) {
+            return iface.cast(this);
+        }
+        throw new SQLException("Not a wrapper for " + iface.getName());
     }

     @Override
     public boolean isWrapperFor(Class<?> iface) throws SQLException {
-        return false;
+        return iface != null && iface.isAssignableFrom(getClass());
     }
src/main/java/com/example/Main.java (2)

95-102: Prefer interface type for better abstraction.

The method parameter uses concrete AccountRepository instead of the AccountRepo interface. Using the interface would improve testability and follow dependency inversion.

-    private boolean login(AccountRepository ac) {
+    private boolean login(AccountRepo ac) {

This applies to other methods as well: createAccount, updatePassword, deleteAccount, and similarly MoonMissionRepo for mission methods.


206-208: Address TODO: Help method for account name.

There's a TODO for adding a help method for account name generation. Consider implementing this or creating a tracking issue.

Do you want me to open an issue to track this task?

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e629e94 and c6038c2.

📒 Files selected for processing (9)
  • README.md (1 hunks)
  • src/main/java/com/example/Main.java (2 hunks)
  • src/main/java/com/example/SimpleDriverManagerDataSource.java (1 hunks)
  • src/main/java/com/repo/AccountRepo.java (1 hunks)
  • src/main/java/com/repo/AccountRepository.java (1 hunks)
  • src/main/java/com/repo/DTO/AccountDTO.java (1 hunks)
  • src/main/java/com/repo/DTO/MissionDTO.java (1 hunks)
  • src/main/java/com/repo/MoonMissionRepo.java (1 hunks)
  • src/main/java/com/repo/MoonMissionRepository.java (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/main/java/com/example/Main.java (2)
src/main/java/com/repo/AccountRepository.java (1)
  • AccountRepository (14-145)
src/main/java/com/repo/MoonMissionRepository.java (1)
  • MoonMissionRepository (14-84)
🔇 Additional comments (6)
README.md (1)

1-1: Nice addition—badge provides quick deadline reference.

The GitHub Classroom assignment deadline badge is a standard and helpful addition to assignment repositories. It gives students at-a-glance access to deadline and assignment details.

src/main/java/com/repo/DTO/AccountDTO.java (1)

3-10: Consider security implications for sensitive fields.

The record stores password and ssn as plain strings. While this is acceptable for a DTO, ensure:

  1. Passwords are hashed before storage in the database (not stored plain-text)
  2. This DTO is not inadvertently serialized to logs or API responses, as it contains PII (SSN) and credentials

The record structure itself is clean and appropriate for data transfer.

src/main/java/com/repo/DTO/MissionDTO.java (1)

5-13: LGTM!

Well-structured record with appropriate types. Using LocalDate for launchDate is the correct choice for date-only values.

src/main/java/com/repo/MoonMissionRepo.java (1)

9-16: LGTM!

Clean interface definition that properly abstracts the data access layer. The method signatures are appropriate and use Optional correctly for potentially absent results.

src/main/java/com/example/SimpleDriverManagerDataSource.java (1)

11-32: Acceptable for development, but consider connection pooling for production.

This simple DataSource creates a new connection on each getConnection() call. For production use, consider HikariCP or similar connection pool to avoid connection overhead and manage resources properly.

src/main/java/com/repo/AccountRepo.java (1)

9-28: LGTM!

Well-designed repository interface with clear method signatures. Good use of Optional for potentially absent results and appropriate separation of concerns.

Comment on lines +39 to +43
DataSource ds = new SimpleDriverManagerDataSource(
System.getProperty("APP_JDBC_URL"),
System.getProperty("APP_DB_USER"),
System.getProperty("APP_DB_PASS")
);
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

Resolved configuration values are ignored - environment variables won't work.

The code resolves config with fallback to environment variables (lines 29-31) but then directly uses System.getProperty() instead of the resolved values. This breaks the intended fallback behavior.

         DataSource ds = new SimpleDriverManagerDataSource(
-                System.getProperty("APP_JDBC_URL"),
-                System.getProperty("APP_DB_USER"),
-                System.getProperty("APP_DB_PASS")
+                jdbcUrl,
+                dbUser,
+                dbPass
         );
📝 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
DataSource ds = new SimpleDriverManagerDataSource(
System.getProperty("APP_JDBC_URL"),
System.getProperty("APP_DB_USER"),
System.getProperty("APP_DB_PASS")
);
DataSource ds = new SimpleDriverManagerDataSource(
jdbcUrl,
dbUser,
dbPass
);
🤖 Prompt for AI Agents
In src/main/java/com/example/Main.java around lines 39 to 43, the DataSource is
constructed using System.getProperty(...) directly which ignores the previously
resolved configuration values (with environment-variable fallbacks on lines
29-31); replace the direct System.getProperty calls with the resolved variables
(e.g., jdbcUrl, dbUser, dbPass or whatever local names were computed earlier)
when constructing the SimpleDriverManagerDataSource so the fallback logic is
honored; ensure those resolved variables are final/visible in this scope and
used instead of calling System.getProperty again.

Comment on lines +182 to +194
String accName; //Default accountname is first three letters of first and last name
if(fn.length() <= 3 && ln.length() <=3){ //if both first and last name are 3 or fewer letters
accName = fn + ln;} //accountname is both full combined

else if (fn.length() <= 3){ //if only first name is 3 or fewer letters
accName = fn + ln.substring(0, 2); //accountname is full first name and first 3 from last name
}
else if(ln.length() <= 3){ //if only last name is 3 or fewer letters
accName = fn.substring(0, 2) + ln; //accountname is first 3 from first name and full last name
}
else{ //if both are longer than 3 accountname follows default pattern
accName = fn.substring(0, 2) + ln.substring(0, 2);
}
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

Account name generation uses wrong substring length.

Comments say "first 3 letters" but substring(0, 2) returns only 2 characters. If the intent is 3 characters, use substring(0, 3).

-        if(fn.length() <= 3 && ln.length() <=3){    //if both first and last name are 3 or fewer letters
+        if(fn.length() <= 3 && ln.length() <= 3){   //if both first and last name are 3 or fewer letters
             accName = fn + ln;}                     //accountname is both full combined

         else if (fn.length() <= 3){                 //if only first name is 3 or fewer letters
-            accName = fn + ln.substring(0, 2);      //accountname is full first name and first 3 from last name
+            accName = fn + ln.substring(0, 3);      //accountname is full first name and first 3 from last name
         }
         else if(ln.length() <= 3){                  //if only last name is 3 or fewer letters
-           accName = fn.substring(0, 2) + ln;       //accountname is first 3 from first name and full last name
+           accName = fn.substring(0, 3) + ln;       //accountname is first 3 from first name and full last name
         }
         else{                                       //if both are longer than 3 accountname follows default pattern
-            accName = fn.substring(0, 2) + ln.substring(0, 2);
+            accName = fn.substring(0, 3) + ln.substring(0, 3);
         }
📝 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
String accName; //Default accountname is first three letters of first and last name
if(fn.length() <= 3 && ln.length() <=3){ //if both first and last name are 3 or fewer letters
accName = fn + ln;} //accountname is both full combined
else if (fn.length() <= 3){ //if only first name is 3 or fewer letters
accName = fn + ln.substring(0, 2); //accountname is full first name and first 3 from last name
}
else if(ln.length() <= 3){ //if only last name is 3 or fewer letters
accName = fn.substring(0, 2) + ln; //accountname is first 3 from first name and full last name
}
else{ //if both are longer than 3 accountname follows default pattern
accName = fn.substring(0, 2) + ln.substring(0, 2);
}
String accName; //Default accountname is first three letters of first and last name
if(fn.length() <= 3 && ln.length() <= 3){ //if both first and last name are 3 or fewer letters
accName = fn + ln;} //accountname is both full combined
else if (fn.length() <= 3){ //if only first name is 3 or fewer letters
accName = fn + ln.substring(0, 3); //accountname is full first name and first 3 from last name
}
else if(ln.length() <= 3){ //if only last name is 3 or fewer letters
accName = fn.substring(0, 3) + ln; //accountname is first 3 from first name and full last name
}
else{ //if both are longer than 3 accountname follows default pattern
accName = fn.substring(0, 3) + ln.substring(0, 3);
}
🤖 Prompt for AI Agents
In src/main/java/com/example/Main.java around lines 182 to 194, the code and
comments intend to use the first three characters of first and/or last name but
call substring(0, 2) which returns only two characters; change all substring(0,
2) calls to substring(0, 3) so you extract three characters when the name length
is > 3, and keep the existing checks (fn.length() <= 3 / ln.length() <= 3) to
ensure substring(0, 3) is only called on sufficiently long strings.

Comment on lines +302 to +317
private String getValidName(String prompt){
while(true){
System.out.println("\n" + prompt);
String name = scanner.nextLine().trim();

if (name.isBlank()) {
System.out.println("\nCannot be blank");
}
else if(!Pattern.matches("^[a-zA-Z]+$", name)){
System.out.println("\nMust only contain letters");
}
else{
return name.substring(0, 1).toUpperCase() + name.substring(1).toLowerCase();
}
}
}
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

Edge case: Single-character name produces empty suffix.

If name is exactly 1 character, name.substring(1) returns an empty string, resulting in just the uppercase first character. Consider if this is acceptable or if minimum length validation is needed.

             else{
-                return name.substring(0, 1).toUpperCase() + name.substring(1).toLowerCase();
+                String capitalized = name.substring(0, 1).toUpperCase();
+                if (name.length() > 1) {
+                    capitalized += name.substring(1).toLowerCase();
+                }
+                return capitalized;
             }
📝 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
private String getValidName(String prompt){
while(true){
System.out.println("\n" + prompt);
String name = scanner.nextLine().trim();
if (name.isBlank()) {
System.out.println("\nCannot be blank");
}
else if(!Pattern.matches("^[a-zA-Z]+$", name)){
System.out.println("\nMust only contain letters");
}
else{
return name.substring(0, 1).toUpperCase() + name.substring(1).toLowerCase();
}
}
}
private String getValidName(String prompt){
while(true){
System.out.println("\n" + prompt);
String name = scanner.nextLine().trim();
if (name.isBlank()) {
System.out.println("\nCannot be blank");
}
else if(!Pattern.matches("^[a-zA-Z]+$", name)){
System.out.println("\nMust only contain letters");
}
else{
String capitalized = name.substring(0, 1).toUpperCase();
if (name.length() > 1) {
capitalized += name.substring(1).toLowerCase();
}
return capitalized;
}
}
}
🤖 Prompt for AI Agents
In src/main/java/com/example/Main.java around lines 302 to 317, the current
capitalization logic uses name.substring(1) which yields an empty string for
single-character names; change the method to explicitly handle single-character
names by checking if name.length() == 1 and returning name.toUpperCase() in that
case, otherwise continue to return name.substring(0,1).toUpperCase() +
name.substring(1).toLowerCase(); keep existing blank/letters validation messages
intact.

Comment on lines +65 to +70
@Override
public boolean matchCredentials(String name, String password) {
Optional<AccountDTO> account = getAccountByName(name);

return account.isPresent() && account.get().password().equals(password);
}
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

Plain-text password comparison is a security risk.

matchCredentials compares passwords using String.equals(), which implies passwords are stored in plain text. This is a significant security vulnerability. Passwords should be hashed (e.g., bcrypt, Argon2) and compared using a constant-time comparison to prevent timing attacks.

Consider using a password hashing library:

// Example with BCrypt (add dependency: org.mindrot:jbcrypt)
return account.isPresent() && 
       BCrypt.checkpw(password, account.get().password());
🤖 Prompt for AI Agents
In src/main/java/com/repo/AccountRepository.java around lines 65 to 70, the
method matchCredentials currently compares plaintext passwords with
String.equals which implies plaintext storage and is vulnerable to timing
attacks; update authentication to verify a stored hashed password instead:
ensure account passwords are stored as a secure hash (e.g., bcrypt or Argon2)
when accounts are created/updated, add a vetted hashing library dependency (for
example org.mindrot:jbcrypt or an Argon2 library), and replace the equals check
with the library's verify function (e.g., BCrypt.checkpw or Argon2 verify) which
performs safe comparison; also remove any code paths that store raw passwords
and add unit tests for both successful and failed authentication cases.

Comment on lines +41 to +43
try(Connection c = dataSource.getConnection();
PreparedStatement ps = c.prepareStatement("select * from moon_mission where missionid = ?")){
ps.setInt(1, missionid);
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

Column name mismatch will cause query to fail.

The query uses missionid but mapMission() at line 75 reads mission_id. This inconsistency will cause the query to return no results or fail, depending on the actual database schema.

-            PreparedStatement ps = c.prepareStatement("select * from moon_mission where missionid = ?")){
+            PreparedStatement ps = c.prepareStatement("select * from moon_mission where mission_id = ?")){
📝 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
try(Connection c = dataSource.getConnection();
PreparedStatement ps = c.prepareStatement("select * from moon_mission where missionid = ?")){
ps.setInt(1, missionid);
try(Connection c = dataSource.getConnection();
PreparedStatement ps = c.prepareStatement("select * from moon_mission where mission_id = ?")){
ps.setInt(1, missionid);
🤖 Prompt for AI Agents
In src/main/java/com/repo/MoonMissionRepository.java around lines 41 to 43, the
SQL uses "missionid" while mapMission() expects "mission_id", so update the code
to use the correct column name to match the mapper; change the prepared
statement SQL to use "where mission_id = ?" (or alternatively update mapMission
to read "missionid" if the DB actually uses that name), and keep the parameter
binding as ps.setInt(1, missionid) so the query and mapper use the same column
name.

Comment on lines +73 to +83
private MissionDTO mapMission(ResultSet rs) throws SQLException {
return new MissionDTO(
rs.getInt("mission_id"),
rs.getString("spacecraft"),
rs.getDate("launch_date").toLocalDate(),
rs.getString("carrier_rocket"),
rs.getString("operator"),
rs.getString("mission_type"),
rs.getString("outcome")
);
}
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 NullPointerException if launch_date is null.

If launch_date is NULL in the database, rs.getDate("launch_date") returns null, and calling .toLocalDate() on it will throw NPE.

     private MissionDTO mapMission(ResultSet rs) throws SQLException {
+        java.sql.Date launchDate = rs.getDate("launch_date");
         return new MissionDTO(
                 rs.getInt("mission_id"),
                 rs.getString("spacecraft"),
-                rs.getDate("launch_date").toLocalDate(),
+                launchDate != null ? launchDate.toLocalDate() : null,
                 rs.getString("carrier_rocket"),
                 rs.getString("operator"),
                 rs.getString("mission_type"),
                 rs.getString("outcome")
         );
     }
📝 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
private MissionDTO mapMission(ResultSet rs) throws SQLException {
return new MissionDTO(
rs.getInt("mission_id"),
rs.getString("spacecraft"),
rs.getDate("launch_date").toLocalDate(),
rs.getString("carrier_rocket"),
rs.getString("operator"),
rs.getString("mission_type"),
rs.getString("outcome")
);
}
private MissionDTO mapMission(ResultSet rs) throws SQLException {
java.sql.Date launchDate = rs.getDate("launch_date");
return new MissionDTO(
rs.getInt("mission_id"),
rs.getString("spacecraft"),
launchDate != null ? launchDate.toLocalDate() : null,
rs.getString("carrier_rocket"),
rs.getString("operator"),
rs.getString("mission_type"),
rs.getString("outcome")
);
}
🤖 Prompt for AI Agents
In src/main/java/com/repo/MoonMissionRepository.java around lines 73 to 83, the
code calls rs.getDate("launch_date").toLocalDate() which will throw a
NullPointerException if the DB value is NULL; change the mapping to retrieve the
Date into a local variable, check for null, and pass either null or an
Optional/localDate to the MissionDTO (e.g., Date d = rs.getDate("launch_date");
LocalDate launchDate = (d == null) ? null : d.toLocalDate()), and ensure
MissionDTO's launchDate field/signature accepts null (or an Optional)
accordingly.

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