Skip to content

Labb3#9

Open
gitnes94 wants to merge 3 commits intomainfrom
Labb3
Open

Labb3#9
gitnes94 wants to merge 3 commits intomainfrom
Labb3

Conversation

@gitnes94
Copy link

@gitnes94 gitnes94 commented Dec 10, 2025

JDBC Repository Uppgift - Younes Ahmad

Summary by CodeRabbit

  • New Features

    • User authentication and login flow
    • Account management: create accounts, update passwords, delete accounts
    • Moon mission queries: list spacecraft, lookup mission by ID, count missions by year
    • Interactive command-line menu for all operations
  • Documentation

    • Added review assignment due date badge to README

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

@coderabbitai
Copy link

coderabbitai bot commented Dec 10, 2025

Walkthrough

Refactors the application entry point to a dependency-injectable Main with an interactive, login-protected run loop; adds JDBC repository interfaces and implementations for accounts and moon missions, new record models, and a simple DriverManager-backed DataSource. README gains a badge; one file receives a trailing comment.

Changes

Cohort / File(s) Summary
Main & CLI
src/main/java/com/example/Main.java
Makes main public static; adds dependency-injectable and no-arg constructors, a public run() interactive menu with login flow and helper methods for account and mission operations; DB setup moved into no-arg constructor.
DataSource Adapter
src/main/java/com/example/datasource/SimpleDriverManagerDataSource.java
New SimpleDriverManagerDataSource implementing javax.sql.DataSource, delegating connections to DriverManager and providing minimal implementations for other DataSource methods.
Model Records
src/main/java/com/example/model/Account.java, src/main/java/com/example/model/MoonMission.java
New Account and MoonMission records with compact/canonical constructors enforcing non-null / non-blank validation for key fields.
Repository Interfaces
src/main/java/com/example/repository/AccountRepository.java, src/main/java/com/example/repository/MoonMissionRepository.java
New interfaces declaring account and moon-mission data access contracts (find/create/update/delete; findAllSpaceCraftNames/findById/countByYear).
JDBC Repository Implementations
src/main/java/com/example/repository/JdbcAccountRepository.java, src/main/java/com/example/repository/JdbcMoonMissionRepository.java
New DataSource-backed JDBC implementations using prepared statements, try-with-resources, result mapping to records, Optional handling, and SQLException -> RuntimeException wrapping.
Docs & Minor
README.md, src/main/java/com/example/DevDatabaseInitializer.java
README.md: added Review Assignment Due Date badge. DevDatabaseInitializer.java: added a trailing comment (no behavioral change).

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Main
    participant AccountRepo as AccountRepository
    participant MissionRepo as MoonMissionRepository
    participant DataSource
    participant DB as Database

    User->>Main: run()
    Main->>Main: prompt login
    User->>Main: submit credentials
    Main->>AccountRepo: findByUsernameAndPassword(username, password)
    AccountRepo->>DataSource: getConnection()
    DataSource->>DB: DriverManager.getConnection()
    DB-->>DataSource: Connection
    AccountRepo->>DB: SELECT ... (prepared)
    alt account found
        DB-->>AccountRepo: ResultSet -> Account
        AccountRepo->>Main: Optional<Account>
        Main->>User: login success
        loop interactive commands
            User->>Main: choose action
            alt list missions
                Main->>MissionRepo: findAllSpaceCraftNames()
                MissionRepo->>DataSource: getConnection()
                MissionRepo->>DB: SELECT name...
                DB-->>MissionRepo: ResultSet -> List<String>
                MissionRepo->>Main: list
            else get mission by id
                Main->>MissionRepo: findById(id)
                MissionRepo->>DB: SELECT ... WHERE id=?
                DB-->>MissionRepo: ResultSet -> MoonMission?
                MissionRepo->>Main: Optional<MoonMission>
            else count by year
                Main->>MissionRepo: countByYear(year)
                MissionRepo->>DB: SELECT COUNT(...)
                DB-->>MissionRepo: count
            else create account
                Main->>AccountRepo: create(...)
                AccountRepo->>DB: INSERT ...
                DB-->>AccountRepo: generated id
            else update/delete account
                Main->>AccountRepo: updatePassword(...) / delete(...)
                AccountRepo->>DB: UPDATE/DELETE ...
            end
        end
    else account not found
        DB-->>AccountRepo: no rows
        AccountRepo->>Main: Optional.empty()
        Main->>User: invalid login (exit)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Areas needing focused review:
    • SQL statements and parameter ordering in JdbcAccountRepository and JdbcMoonMissionRepository
    • Resource management and exception wrapping to preserve cause and context
    • Authentication/authorization flow in Main.run() (input validation, handling of failed logins)
    • Validation logic and error messages in Account and MoonMission constructors
    • SimpleDriverManagerDataSource behavior for edge cases (login timeout, logging) if relied upon

Poem

🐰 I hopped into code where the missions dwell,
New records to hold each launch and spell.
Repositories stitched with JDBC thread,
A DriverManager bridge to where data's fed.
I nibble badges and menus galore—hop, run, explore! 🚀

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'Labb3' is vague and does not convey meaningful information about the changeset; it appears to be a lab/assignment name rather than a descriptive summary of the actual changes. Revise the title to describe the main changes, such as 'Add JDBC repositories and interactive CLI for account and moon mission management' to clearly communicate what was implemented.
✅ 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

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b9fafaa and 6270258.

📒 Files selected for processing (1)
  • src/main/java/com/example/DevDatabaseInitializer.java (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/main/java/com/example/DevDatabaseInitializer.java

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

@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

♻️ Duplicate comments (2)
src/main/java/com/example/repository/JdbcAccountRepository.java (2)

45-69: Critical: Password stored in plaintext.

The password is inserted into the database without hashing (line 56), exposing user credentials.

This is the same plaintext password issue flagged in findByUsernameAndPassword.


71-87: Critical: Password updated without hashing.

The new password is stored in plaintext (line 78).

This is the same plaintext password issue flagged earlier.

🧹 Nitpick comments (3)
src/main/java/com/example/model/Account.java (1)

3-20: Record structure is appropriate for the domain model.

The validation logic in the compact constructor is good. However, note that Java records automatically generate toString() which will include password and ssn fields. This could inadvertently leak sensitive data to logs.

For a lab/educational context this is acceptable, but in production you'd want to override toString() to exclude sensitive fields or use a dedicated DTO for logging.

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

160-180: Consider input validation for account creation.

The createAccount() method accepts user input directly without validation. Empty strings for firstName, lastName, ssn, or password will be passed to the repository. While the Account record validates some fields, this could result in confusing error messages for users.

Consider adding basic validation before calling the repository:

private void createAccount() {
    System.out.print("First name: ");
    String firstName = scanner.nextLine().trim();
    if (firstName.isEmpty()) {
        System.out.println("First name cannot be empty.");
        return;
    }
    // ... similar for other fields
}
src/main/java/com/example/repository/JdbcAccountRepository.java (1)

72-87: Consider adding password validation.

The method accepts any string as newPassword without validation (e.g., minimum length, complexity requirements, null checks). Adding validation would improve security and user experience.

📜 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 b9fafaa.

📒 Files selected for processing (9)
  • README.md (1 hunks)
  • src/main/java/com/example/Main.java (1 hunks)
  • src/main/java/com/example/datasource/SimpleDriverManagerDataSource.java (1 hunks)
  • src/main/java/com/example/model/Account.java (1 hunks)
  • src/main/java/com/example/model/MoonMission.java (1 hunks)
  • src/main/java/com/example/repository/AccountRepository.java (1 hunks)
  • src/main/java/com/example/repository/JdbcAccountRepository.java (1 hunks)
  • src/main/java/com/example/repository/JdbcMoonMissionRepository.java (1 hunks)
  • src/main/java/com/example/repository/MoonMissionRepository.java (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/main/java/com/example/Main.java (4)
src/main/java/com/example/datasource/SimpleDriverManagerDataSource.java (1)
  • SimpleDriverManagerDataSource (9-51)
src/main/java/com/example/repository/JdbcAccountRepository.java (1)
  • JdbcAccountRepository (9-104)
src/main/java/com/example/repository/JdbcMoonMissionRepository.java (1)
  • JdbcMoonMissionRepository (16-94)
src/main/java/com/example/DevDatabaseInitializer.java (1)
  • DevDatabaseInitializer (6-24)
🔇 Additional comments (14)
README.md (2)

1-1: Badge addition is appropriate for classroom assignment tracking.

The GitHub Classroom deadline badge is a standard and helpful addition for tracking assignment submission deadlines.


2-84: Documentation is clear and comprehensive.

The README provides excellent guidance on:

  • Test execution requirements and Docker setup
  • Development mode configuration options
  • IntelliJ setup for local database connections
  • Clear, explicit G-level and VG-level assignment requirements

The specification aligns well with the architectural approach described in the PR objectives (DataSource abstraction, repository pattern with JDBC implementations, dependency injection in Main).

src/main/java/com/example/repository/MoonMissionRepository.java (1)

8-15: Clean repository interface design.

The interface follows the repository pattern well with appropriate method signatures and return types. Using Optional<MoonMission> for findById is the correct approach.

src/main/java/com/example/model/MoonMission.java (1)

5-22: Well-structured domain model.

The validation for essential fields (spacecraft, launchDate) is appropriate. Allowing other fields to be nullable is reasonable for optional mission metadata.

src/main/java/com/example/repository/AccountRepository.java (1)

7-16: Repository interface follows standard patterns.

The interface design is functional. Note that findByUsernameAndPassword implies plaintext password comparison in the database, which is acceptable for a lab assignment but would require password hashing (e.g., BCrypt) in production.

src/main/java/com/example/repository/JdbcMoonMissionRepository.java (1)

75-93: YEAR() function is MySQL-specific.

The YEAR(launch_date) function works with MySQL but may not be portable to other databases. Since this project uses MySQL via Testcontainers (as seen in DevDatabaseInitializer), this is acceptable for the current scope.

src/main/java/com/example/datasource/SimpleDriverManagerDataSource.java (2)

26-29: getConnection(String, String) ignores provided credentials.

The overloaded getConnection(String username, String password) method ignores the parameters and uses the stored instance credentials instead. This could be confusing to callers.

 @Override
 public Connection getConnection(String username, String password) throws SQLException {
-    return DriverManager.getConnection(url, username, password);
+    return DriverManager.getConnection(url, this.username, this.password);
 }

Wait - looking again, you're actually using the passed parameters. However, this behavior differs from the typical DataSource contract where getConnection() uses default credentials and getConnection(u, p) uses the provided ones. Consider whether you want:

  1. Current behavior: Use provided credentials (correct per interface contract)
  2. Or always use instance credentials (add a comment explaining the deviation)

Current implementation is actually correct per the DataSource contract.


9-51: Simple DataSource implementation is adequate for this use case.

The implementation correctly wraps DriverManager for basic connectivity. Note that this creates a new connection on each getConnection() call without pooling, which is fine for a lab assignment but would need a connection pool (e.g., HikariCP) for production workloads.

src/main/java/com/example/Main.java (3)

27-31: Good use of constructor injection for testability.

The parameterized constructor enables dependency injection of repositories, making the class testable with mocks.


64-91: Well-structured menu loop with clean switch expression.

The run() method has a clear structure with the menu loop and switch expression for handling user choices. Closing the scanner at the end is good practice.


211-220: Robust input handling for integers.

The getIntInput() method properly handles invalid input with a retry loop, providing good user experience.

src/main/java/com/example/repository/JdbcAccountRepository.java (3)

13-15: LGTM!

Constructor correctly accepts and stores the DataSource for dependency injection.


89-103: Ensure cascade delete handling for related account data

The delete method correctly uses PreparedStatement with parameterized queries and proper resource management. However, verify that database foreign key constraints are configured with ON DELETE CASCADE for tables referencing user_id (such as missions or other related entities), or that application logic handles cleanup of associated records before account deletion.


17-43: Critical: Passwords compared and stored in plaintext without hashing.

This method directly compares plaintext passwords (line 19 queries WHERE password = ? with the provided password parameter) and returns the plaintext password in the Account object (line 34). This is a critical security vulnerability—passwords must never be stored or transmitted in plaintext.

Implement password hashing using a strong algorithm (BCrypt, Argon2, or PBKDF2):

  • Hash the password before storing in the database
  • During authentication, hash the provided password and compare the hashes

Comment on lines +10 to +16
import org.testcontainers.shaded.org.checkerframework.checker.units.qual.A;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLOutput;
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Remove unused imports.

Several imports are not used and should be removed:

  • Line 10: org.testcontainers.shaded.org.checkerframework.checker.units.qual.A
  • Line 16: java.sql.SQLOutput
 import com.example.repository.JdbcMoonMissionRepository;
 import com.example.repository.MoonMissionRepository;
-import org.testcontainers.shaded.org.checkerframework.checker.units.qual.A;
 
 import javax.sql.DataSource;
 import java.sql.Connection;
 import java.sql.DriverManager;
 import java.sql.SQLException;
-import java.sql.SQLOutput;
 import java.util.Arrays;
📝 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
import org.testcontainers.shaded.org.checkerframework.checker.units.qual.A;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLOutput;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
🤖 Prompt for AI Agents
In src/main/java/com/example/Main.java around lines 10 to 16, the imports
org.testcontainers.shaded.org.checkerframework.checker.units.qual.A (line 10)
and java.sql.SQLOutput (line 16) are unused; remove those two import lines from
the top of the file and leave the remaining imports as-is (optionally
reformat/sort imports) then recompile to ensure no unused-import warnings
remain.

Comment on lines 46 to 49
throw new IllegalStateException(
"Missing DB configuration. Provide APP_JDBC_URL, APP_DB_USER, APP_DB_PASS " +
"as system properties (-Dkey=value) or environment variables.");
"Missing DB configuration. Provide APP_JDBC_URL, APP_DB_USER, APP_DB_PASS \" +\n" +
"\"as system properties (-Dkey=value) or environment variables.\"");
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Malformed exception message with literal \n.

The string concatenation creates a malformed message with a literal \n appearing in the output instead of an actual newline.

         if (jdbcUrl == null || dbUser == null || dbPass == null) {
             throw new IllegalStateException(
-                    "Missing DB configuration. Provide APP_JDBC_URL, APP_DB_USER, APP_DB_PASS \" +\n" +
-                            "\"as system properties (-Dkey=value) or environment variables.\"");
+                    "Missing DB configuration. Provide APP_JDBC_URL, APP_DB_USER, APP_DB_PASS " +
+                            "as system properties (-Dkey=value) or environment variables.");
         }
📝 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
throw new IllegalStateException(
"Missing DB configuration. Provide APP_JDBC_URL, APP_DB_USER, APP_DB_PASS " +
"as system properties (-Dkey=value) or environment variables.");
"Missing DB configuration. Provide APP_JDBC_URL, APP_DB_USER, APP_DB_PASS \" +\n" +
"\"as system properties (-Dkey=value) or environment variables.\"");
}
throw new IllegalStateException(
"Missing DB configuration. Provide APP_JDBC_URL, APP_DB_USER, APP_DB_PASS " +
"as system properties (-Dkey=value) or environment variables.");
}
🤖 Prompt for AI Agents
In src/main/java/com/example/Main.java around lines 46 to 49, the
IllegalStateException message is built with a string containing a literal "\n"
and an awkward concatenation that causes the backslash-n to appear in the
output; replace the concatenation and escaped sequence with a properly formatted
string (either a single string literal containing a real newline using
System.lineSeparator() or by using two concatenated string literals without the
escaped backslash) so the message reads with an actual newline (or explicit
separator) and clear wording for the required APP_JDBC_URL, APP_DB_USER,
APP_DB_PASS configuration.

@Override
public int create(String firstName, String lastName, String ssn, String password) {

String username = firstName + lastName;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Username generation lacks validation and collision prevention.

The username is created by concatenating firstName and lastName without a separator, which can lead to:

  • Collisions: "John Smith" and "Johns Mith" both produce "JohnSmith"
  • Readability issues
  • No handling for special characters or validation

Consider adding a separator, validation, or using a more robust unique identifier strategy.

🤖 Prompt for AI Agents
In src/main/java/com/example/repository/JdbcAccountRepository.java around line
48, the username is built by concatenating firstName and lastName without
validation or collision handling; change this to construct a normalized,
validated base username (e.g., trim, toLowerCase, replace or remove
non-alphanumeric characters, and insert a separator like '.' or '_'), then check
the database for existing usernames and, on collision, append an incrementing
numeric suffix (or fallback to a generated unique id) until a unique username is
found; also validate input lengths and characters and throw or surface a clear
error for invalid names.

PreparedStatement stmt = conn.prepareStatement(query, Statement.RETURN_GENERATED_KEYS)) {

stmt.setString(1, username);
stmt.setString(2, ssn);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

SSN (PII) stored without encryption.

Social Security Numbers are highly sensitive PII. Storing them in plaintext increases compliance and privacy risks (GDPR, CCPA, etc.).

Consider encrypting SSN values at rest or evaluating whether storing SSN is necessary.

🤖 Prompt for AI Agents
In src/main/java/com/example/repository/JdbcAccountRepository.java around line
55, the code sets the SSN directly on the PreparedStatement which stores PII in
plaintext; instead, encrypt the SSN before binding to the statement (or avoid
storing it entirely if not required). Implement a deterministic or authenticated
encryption step (e.g., AES-GCM) using a securely managed key (KMS/HSM or
environment-backed secret) and store the ciphertext (and IV/nonce/tag if needed)
in the database column (update schema to appropriate binary/varchar and add
columns for iv/tag when required); if only verification is needed, consider
storing a keyed hash (HMAC) or tokenized value rather than raw SSN. Ensure no
plain SSN is logged or kept in memory longer than necessary and update the code
to decrypt only when explicitly required with proper access controls and audit
logging.

Comment on lines +4 to +7
import org.testcontainers.shaded.org.checkerframework.checker.units.qual.A;

import javax.sql.DataSource;
import javax.swing.text.html.Option;
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Remove unused imports.

These imports are not used in the code and should be removed:

  • org.testcontainers.shaded.org.checkerframework.checker.units.qual.A
  • javax.swing.text.html.Option
 package com.example.repository;
 
 import com.example.model.MoonMission;
-import org.testcontainers.shaded.org.checkerframework.checker.units.qual.A;
 
 import javax.sql.DataSource;
-import javax.swing.text.html.Option;
 import java.sql.Connection;
📝 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
import org.testcontainers.shaded.org.checkerframework.checker.units.qual.A;
import javax.sql.DataSource;
import javax.swing.text.html.Option;
package com.example.repository;
import com.example.model.MoonMission;
import javax.sql.DataSource;
import java.sql.Connection;
🤖 Prompt for AI Agents
In src/main/java/com/example/repository/JdbcMoonMissionRepository.java around
lines 4 to 7, remove the two unused import statements
"org.testcontainers.shaded.org.checkerframework.checker.units.qual.A" and
"javax.swing.text.html.Option" from the top of the file; then re-run/organize
imports (or your IDE's auto-import cleanup) to ensure no unused imports remain
and that the class still compiles.

Comment on lines +54 to +63
if (rs.next()) {
MoonMission mission = new MoonMission(
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

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 in the database.

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

             if (rs.next()) {
+                java.sql.Date launchDate = rs.getDate("launch_date");
                 MoonMission mission = new MoonMission(
                         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")
                 );

Note: This would require updating the MoonMission record to accept null for launchDate, or ensure the database column has a NOT NULL constraint.

🤖 Prompt for AI Agents
In src/main/java/com/example/repository/JdbcMoonMissionRepository.java around
lines 54 to 63, the code calls rs.getDate("launch_date").toLocalDate() which
will throw a NullPointerException if the DB value is NULL; change the code to
first retrieve the Date (or directly getObject as LocalDate) into a local
variable, check for null, and pass a nullable LocalDate to MoonMission (or
adjust the MoonMission record/constructor to accept a nullable launchDate);
alternatively use rs.getObject("launch_date", java.time.LocalDate.class) which
may return null and pass that through.

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