Skip to content

Moon mission db#3

Open
johanbriger wants to merge 4 commits intomainfrom
moonMissionDb
Open

Moon mission db#3
johanbriger wants to merge 4 commits intomainfrom
moonMissionDb

Conversation

@johanbriger
Copy link
Copy Markdown
Collaborator

@johanbriger johanbriger commented Dec 10, 2025

Summary by CodeRabbit

  • New Features

    • User authentication with username/password login
    • Account management: create accounts, update passwords, delete accounts
    • Moon mission browsing and queries: list spacecraft, view mission details, count missions by year
    • Interactive menu-driven interface for navigating app features
  • Chores

    • Added a logging library dependency to project configuration

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

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Dec 10, 2025

Walkthrough

Adds JDBC repository interfaces and implementations, a DataSource abstraction with a DriverManager-backed implementation, refactors Main to use these components with environment-configured DB access and interactive login/menu operations, and adds the Maven dependency org.slf4j:slf4j-nop:2.0.17.

Changes

Cohort / File(s) Summary
Build
pom.xml
Added dependency org.slf4j:slf4j-nop:2.0.17.
Repository Interfaces
src/main/java/com/example/AccountRepository.java, src/main/java/com/example/MoonMissionRepository.java
New interfaces declaring account- and mission-related data access methods (authentication, account CRUD, list spacecraft, find mission by ID, count by year).
Repository Implementations
src/main/java/com/example/JdbcAccountRepository.java, src/main/java/com/example/JdbcMoonMissionRepository.java
New JDBC implementations using parameterized SQL and try-with-resources: authentication, create/update/delete account; list spacecraft, find mission by ID (accepts Connection), count missions by year.
DataSource Abstraction & Impl
src/main/java/com/example/DataSource.java, src/main/java/com/example/SimpleDriverManagerDataSource.java
New DataSource interface with getConnection() and concrete SimpleDriverManagerDataSource delegating to DriverManager with URL/user/password.
Application Entry / UI
src/main/java/com/example/Main.java
Refactored to initialize DataSource and repositories from APP_JDBC_URL/APP_DB_USER/APP_DB_PASS, test DB connectivity, implement login via AccountRepository, and provide an interactive menu for mission queries and account management.

Sequence Diagram

sequenceDiagram
    participant User
    participant Main
    participant AccountRepo as AccountRepository
    participant MoonRepo as MoonMissionRepository
    participant DS as DataSource
    participant DB as Database

    User->>Main: start app
    Main->>DS: init SimpleDriverManagerDataSource (env vars)
    Main->>DB: test connection
    Main->>User: prompt username/password
    User->>Main: submit credentials
    Main->>AccountRepo: findByNameAndPassword(username, password)
    AccountRepo->>DS: getConnection()
    DS->>DB: open connection
    AccountRepo->>DB: SELECT user_id WHERE username=? AND password=?
    DB-->>AccountRepo: result
    AccountRepo-->>Main: auth result

    alt authenticated
        Main->>User: show menu
        User->>Main: choose action
        alt list missions
            Main->>MoonRepo: findAllSpacecraftNames()
            MoonRepo->>DS: getConnection()
            DS->>DB: open connection
            MoonRepo->>DB: SELECT spacecraft FROM moon_mission
            DB-->>MoonRepo: rows
            MoonRepo-->>Main: names
            Main->>User: display
        else get mission by id
            Main->>DS: getConnection()
            Main->>MoonRepo: findMissionById(id, connection)
            MoonRepo->>DB: SELECT * FROM moon_mission WHERE mission_id=?
            DB-->>MoonRepo: row (ResultSet)
            MoonRepo-->>Main: result
            Main->>User: display
        else account create/update/delete
            Main->>AccountRepo: create/updatePassword/delete(...)
            AccountRepo->>DS: getConnection()
            DS->>DB: open connection
            AccountRepo->>DB: INSERT/UPDATE/DELETE
            DB-->>AccountRepo: update count
            AccountRepo-->>Main: result
            Main->>User: confirm
        end
    else authentication failed
        Main->>User: show failure
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Pay attention to SQL parameter binding and correctness in JdbcAccountRepository and JdbcMoonMissionRepository
  • Verify try-with-resources cover Connection, PreparedStatement, ResultSet lifecycles (including when ResultSet is returned)
  • Review Main.java interactive flow, input handling, and environment-variable validation
  • Confirm responsibility for Connection lifecycle when findMissionById accepts an external Connection

Poem

🐰 In a burrow of code I gently hop,
New DataSources sprout and connections swap,
Repositories hum where raw SQL lay,
Menus and logins now guide the fray,
I twiddle my whiskers—deploy, hooray! 🍃

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 43.48% 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 'Moon mission db' accurately reflects the main changes in the pull request, which add moon mission database functionality through new repository interfaces and implementations.
✨ Finishing touches
  • 📝 Docstrings were successfully generated.
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch moonMissionDb

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

🧹 Nitpick comments (4)
pom.xml (1)

49-58: Consider adding <scope>test</scope> to test-only dependencies.

The testcontainers:mysql dependency (lines 49-53) and slf4j-nop (lines 54-58) appear to be used only during development/testing via DevDatabaseInitializer. Without a <scope>test</scope>, these will be bundled in the production artifact.

         <dependency>
             <groupId>org.testcontainers</groupId>
             <artifactId>mysql</artifactId>
             <version>1.21.3</version>
+            <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-nop</artifactId>
             <version>2.0.17</version>
+            <scope>test</scope>
         </dependency>
src/main/java/com/example/MoonMissionRepository.java (1)

8-11: Returning ResultSet from repository breaks the abstraction.

findMissionById returns a ResultSet and requires the caller to pass a Connection, leaking JDBC internals. This creates lifecycle management issues—the ResultSet is tied to the PreparedStatement which isn't closed in the implementation (see JdbcMoonMissionRepository).

Consider returning a domain object (e.g., Optional<MoonMission>) and managing the connection internally:

// Example domain object
public record MoonMission(long missionId, String spacecraft, LocalDate launchDate, String outcome) {}

// Revised interface method
Optional<MoonMission> findMissionById(long missionId) throws SQLException;
src/main/java/com/example/JdbcAccountRepository.java (2)

31-43: Handle sensitive PII and consider returning generated keys from inserts

Two points about create:

  1. ssn and password (or password hash) are very sensitive fields. If these are real values, consider:
    • Storing only password hashes, never raw passwords.
    • Encrypting or otherwise protecting SSNs at rest, and minimizing where they are read in the codebase.
  2. The method returns only executeUpdate() (rows affected). If callers need the new user_id, it might be more ergonomic to request generated keys (prepareStatement(sql, Statement.RETURN_GENERATED_KEYS) + getGeneratedKeys()) or use a RETURNING clause if your DB supports it.

If you don’t need the ID or this is just for a lab exercise, the current implementation is functionally fine.


46-66: Optional: reduce duplication and make update/delete semantics explicit

updatePassword and delete are straightforward and correct, but you might consider:

  • Checking the returned int and documenting the expected value (e.g. “returns 1 if a row was updated/deleted, 0 if no such user exists”) so callers know how to handle “user not found”.
  • Extracting a small private helper for simple UPDATE/DELETE statements to avoid repeating the same try-with-resources pattern if you add more similar methods later.

Not required, but would improve clarity and reduce future duplication.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 49602b4 and e55a38f.

📒 Files selected for processing (8)
  • pom.xml (1 hunks)
  • src/main/java/com/example/AccountRepository.java (1 hunks)
  • src/main/java/com/example/DataSource.java (1 hunks)
  • src/main/java/com/example/JdbcAccountRepository.java (1 hunks)
  • src/main/java/com/example/JdbcMoonMissionRepository.java (1 hunks)
  • src/main/java/com/example/Main.java (2 hunks)
  • src/main/java/com/example/MoonMissionRepository.java (1 hunks)
  • src/main/java/com/example/SimpleDriverManagerDataSource.java (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/main/java/com/example/Main.java (1)
src/main/java/com/example/DevDatabaseInitializer.java (1)
  • DevDatabaseInitializer (6-24)
🔇 Additional comments (8)
src/main/java/com/example/DataSource.java (1)

6-8: LGTM - Simple DataSource abstraction.

The interface cleanly abstracts connection provisioning. For broader compatibility (e.g., connection pooling libraries), consider extending or replacing with javax.sql.DataSource, but this custom interface works well for the current scope.

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

5-10: LGTM - Clean repository interface.

The interface follows standard repository conventions. Minor consideration: findByNameAndPassword returning boolean limits flexibility—returning Optional<Account> would allow retrieving user details upon successful authentication.

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

7-23: LGTM - Simple DataSource implementation.

The implementation correctly delegates to DriverManager. Creating a new connection per call is fine for low-traffic scenarios. For production workloads, consider a connection pool (e.g., HikariCP) to avoid connection overhead.

src/main/java/com/example/JdbcMoonMissionRepository.java (2)

19-31: LGTM - Proper resource management.

Good use of try-with-resources for Connection, Statement, and ResultSet.


42-55: LGTM - Proper resource management.

Good use of nested try-with-resources for connection, statement, and result set.

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

23-59: LGTM - Repository initialization and connection test.

Good separation of concerns with configuration resolution and repository pattern setup. The connection test (lines 45-47) validates database connectivity before proceeding.


87-129: LGTM - Menu loop with proper exception handling.

Good handling of InputMismatchException with scanner reset (line 124) and SQLException logging. The switch-based menu is clear and maintainable.

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

8-14: Good use of constructor injection and DataSource abstraction

Using a final DataSource with constructor injection keeps the repository easy to test and swap implementations, and centralizes connection configuration nicely. Nothing to change here.

Comment on lines +16 to +28
@Override
public boolean findByNameAndPassword(String username, String password) throws SQLException {
String sql = "SELECT user_id FROM account WHERE name = ? AND password = ?";
// Använder try-with-resources för att säkerställa att Connection stängs
try (Connection connection = dataSource.getConnection();
PreparedStatement stmt = connection.prepareStatement(sql)) {
stmt.setString(1, username);
stmt.setString(2, password);
try (ResultSet rs = stmt.executeQuery()) {
return rs.next();
}
}
}
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:

# First, let's understand the repository structure and find schema files
git ls-files | grep -E "(schema|migration|\.sql)" | head -20

Repository: ithsjava25/databas-jdbc-johanbriger

Length of output: 106


🏁 Script executed:

# Search for database schema definitions
find . -type f \( -name "*.sql" -o -name "*schema*" -o -name "*migration*" \) 2>/dev/null | head -20

Repository: ithsjava25/databas-jdbc-johanbriger

Length of output: 108


🏁 Script executed:

# Look for password hashing related imports and methods in the codebase
rg -i "(bcrypt|argon|hash|password)" --type java -B 2 -A 2 | head -100

Repository: ithsjava25/databas-jdbc-johanbriger

Length of output: 7764


🏁 Script executed:

# Find the JdbcAccountRepository class and examine the full context
fd -e java | xargs rg "JdbcAccountRepository" -l

Repository: ithsjava25/databas-jdbc-johanbriger

Length of output: 167


🏁 Script executed:

# Search for where findByNameAndPassword is called from
rg "findByNameAndPassword" --type java -B 3 -A 3

Repository: ithsjava25/databas-jdbc-johanbriger

Length of output: 1967


🏁 Script executed:

# Read the schema file to check for UNIQUE constraints on name column
cat src/main/resources/init.sql

Repository: ithsjava25/databas-jdbc-johanbriger

Length of output: 4833


🏁 Script executed:

# Check the Main.java file for complete authentication flow
cat src/main/java/com/example/Main.java

Repository: ithsjava25/databas-jdbc-johanbriger

Length of output: 10100


🏁 Script executed:

# Search for any password hashing or encoding utilities in the codebase
rg -i "(MessageDigest|encode|decode|hash|cipher)" --type java | head -50

Repository: ithsjava25/databas-jdbc-johanbriger

Length of output: 61


🏁 Script executed:

# Check project dependencies (pom.xml or build.gradle)
fd -e pom.xml -o -e build.gradle | xargs cat 2>/dev/null | head -100

Repository: ithsjava25/databas-jdbc-johanbriger

Length of output: 195


🏁 Script executed:

# Find and read pom.xml or build.gradle to check dependencies
find . -name "pom.xml" -o -name "build.gradle" | xargs cat 2>/dev/null

Repository: ithsjava25/databas-jdbc-johanbriger

Length of output: 2940


🏁 Script executed:

# Read the complete JdbcAccountRepository implementation
cat src/main/java/com/example/JdbcAccountRepository.java

Repository: ithsjava25/databas-jdbc-johanbriger

Length of output: 2521


Store and compare password hashes, not plaintext values; enforce unique constraint on name column

  1. Password hashing: The codebase stores and compares passwords as plaintext (no bcrypt, argon2, or similar in dependencies). Passwords are inserted directly in create() and compared directly in findByNameAndPassword(). This is a critical security vulnerability. Before any password reaches the repository, hash and salt it (e.g., using Spring Security's BCryptPasswordEncoder or similar), and store only the hash. Update findByNameAndPassword() to accept a hashed password or implement a separate verification method that hashes the input before comparison. At minimum, rename the password parameter and column to passwordHash to signal that hashed values are expected.

  2. Name column uniqueness: The schema (init.sql) defines name as VARCHAR(255) with no UNIQUE constraint. Multiple users can have identical names, and login would succeed for any matching account without indication of duplicates. Add a UNIQUE constraint to the name column at the database level: ALTER TABLE account ADD UNIQUE (name);

Comment on lines +34 to +40
@Override
public ResultSet findMissionById(long missionId, Connection connection) throws SQLException {
String sql = "SELECT * FROM moon_mission WHERE mission_id = ?";
PreparedStatement stmt = connection.prepareStatement(sql);
stmt.setLong(1, missionId);
return stmt.executeQuery();
}
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

Resource leak: PreparedStatement is never closed.

The PreparedStatement created on line 37 is not managed by try-with-resources. When the caller closes the ResultSet, the statement remains open, leading to resource exhaustion over time.

This is another reason to avoid returning ResultSet. Refactor to return a domain object:

-    @Override
-    public ResultSet findMissionById(long missionId, Connection connection) throws SQLException {
-        String sql = "SELECT * FROM moon_mission WHERE mission_id = ?";
-        PreparedStatement stmt = connection.prepareStatement(sql);
-        stmt.setLong(1, missionId);
-        return stmt.executeQuery();
-    }
+    @Override
+    public Optional<MoonMission> findMissionById(long missionId) throws SQLException {
+        String sql = "SELECT * FROM moon_mission WHERE mission_id = ?";
+        try (Connection connection = dataSource.getConnection();
+             PreparedStatement stmt = connection.prepareStatement(sql)) {
+            stmt.setLong(1, missionId);
+            try (ResultSet rs = stmt.executeQuery()) {
+                if (rs.next()) {
+                    return Optional.of(new MoonMission(
+                        rs.getLong("mission_id"),
+                        rs.getString("spacecraft"),
+                        rs.getDate("launch_date").toLocalDate(),
+                        rs.getString("outcome")
+                    ));
+                }
+                return Optional.empty();
+            }
+        }
+    }

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

🤖 Prompt for AI Agents
In src/main/java/com/example/JdbcMoonMissionRepository.java around lines 34 to
40, the PreparedStatement created for the query is never closed and the method
returns a ResultSet (causing the statement to remain open); change the method to
not return ResultSet but instead use try-with-resources to open the
PreparedStatement and ResultSet, map the single-row result to a MoonMission
domain object (or Optional<MoonMission>) and return that, ensuring both
ResultSet and PreparedStatement are closed automatically; update method
signature and callers accordingly (or if you cannot change callers, document and
close the statement before returning by wrapping ResultSet consumption inside
the method and returning a materialized object).

Comment on lines +63 to +71
private boolean login() throws SQLException {
System.out.print("Username: ");
String username = scanner.nextLine();
System.out.print("Password: ");
String password = scanner.nextLine();

// Använder AccountRepository
return accountRepository.findByNameAndPassword(username, 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 | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check how passwords are handled in JdbcAccountRepository
ast-grep --pattern $'class JdbcAccountRepository {
  $$$
  findByNameAndPassword($_, $_) {
    $$$
  }
  $$$
}'

Repository: ithsjava25/databas-jdbc-johanbriger

Length of output: 61


🏁 Script executed:

#!/bin/bash
# First, find files containing JdbcAccountRepository
echo "=== Searching for JdbcAccountRepository class ==="
fd -t f "AccountRepository" 

echo -e "\n=== Searching for findByNameAndPassword method ==="
rg "findByNameAndPassword" -A 10 -B 2

Repository: ithsjava25/databas-jdbc-johanbriger

Length of output: 3193


🏁 Script executed:

#!/bin/bash
# Check the full JdbcAccountRepository implementation
cat -n src/main/java/com/example/JdbcAccountRepository.java

echo -e "\n=== Searching for bcrypt or hashing libraries ==="
rg "bcrypt|hash|Hash|PASSWORD_ENCODER|PasswordEncoder" src/

Repository: ithsjava25/databas-jdbc-johanbriger

Length of output: 3041


Implement password hashing for all password operations.

Passwords are stored and compared in plaintext across all methods in JdbcAccountRepository. The findByNameAndPassword() method compares passwords directly in the SQL query (WHERE password = ?), and both create() and updatePassword() methods store passwords without hashing. This violates security best practices and exposes user credentials. Implement proper password hashing using bcrypt (or similar) before storing and when authenticating users.

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

♻️ Duplicate comments (5)
src/main/java/com/example/Main.java (5)

63-71: Plaintext password handling remains unaddressed.

The password security concern flagged in the previous review is still present - passwords are stored and compared in plaintext.


181-189: InputMismatchException handling still missing.

As noted in the previous review, scanner.nextInt() on line 183 can throw InputMismatchException for non-numeric input. While the exception will propagate to mainMenu() which handles it, adding local handling would provide a more specific error message.


221-235: InputMismatchException handling still missing.

scanner.nextLong() on line 223 lacks the same try-catch handling that was added to getMoonMissionById.


237-251: InputMismatchException handling still missing.

scanner.nextLong() on line 240 lacks the same try-catch handling that was added to getMoonMissionById.


158-164: Missing scanner.nextLine() in catch block leaves invalid input in buffer.

When InputMismatchException is thrown, nextLong() does not consume the invalid token. Returning without clearing the buffer causes the next scanner.nextInt() call in mainMenu() to immediately fail with the same invalid input.

 }catch (InputMismatchException e){
+    scanner.nextLine(); // Clear invalid input from buffer
     System.out.println("Please enter a number");
     return;
 }
🧹 Nitpick comments (1)
src/main/java/com/example/Main.java (1)

166-177: Returning ResultSet from repository method is an anti-pattern.

ResultSet is tied to Statement and Connection lifecycle. When the Connection closes (via try-with-resources), behavior depends on how the repository manages the Statement. This leaks JDBC implementation details and complicates resource management.

Consider returning a domain object or Optional<MoonMission> from the repository instead:

// In repository:
Optional<MoonMission> findMissionById(long missionId);

// In Main:
moonMissionRepository.findMissionById(missionId).ifPresentOrElse(
    mission -> {
        System.out.println("Spacecraft: " + mission.getSpacecraft());
        // ...
    },
    () -> System.out.println("Mission not found.")
);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e55a38f and 739e517.

📒 Files selected for processing (1)
  • src/main/java/com/example/Main.java (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/main/java/com/example/Main.java (1)
src/main/java/com/example/DevDatabaseInitializer.java (1)
  • DevDatabaseInitializer (6-24)
🔇 Additional comments (3)
src/main/java/com/example/Main.java (3)

23-59: Good implementation of configuration and initialization flow.

The configuration resolution with fallback from system properties to environment variables, null validation, and connection test before proceeding is well-structured. The repository pattern initialization cleanly separates concerns.


87-129: Well-structured menu loop with proper error handling.

The centralized InputMismatchException and SQLException handling in the main menu loop ensures graceful recovery from both input errors and database failures.


202-208: Empty username validation implemented correctly.

The check for empty username addresses the edge case where both names could be empty, with a clear user message.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Dec 10, 2025

Note

Docstrings generation - SUCCESS
Generated docstrings for this pull request at #4

coderabbitai bot added a commit that referenced this pull request Dec 10, 2025
Docstrings generation was requested by @johanbriger.

* #3 (comment)

The following files were modified:

* `src/main/java/com/example/AccountRepository.java`
* `src/main/java/com/example/DataSource.java`
* `src/main/java/com/example/JdbcAccountRepository.java`
* `src/main/java/com/example/JdbcMoonMissionRepository.java`
* `src/main/java/com/example/Main.java`
* `src/main/java/com/example/MoonMissionRepository.java`
* `src/main/java/com/example/SimpleDriverManagerDataSource.java`
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