Skip to content

Tarupotter/exercise8#210

Open
Tarupotter wants to merge 29 commits intomainfrom
tarupotter/exercise8
Open

Tarupotter/exercise8#210
Tarupotter wants to merge 29 commits intomainfrom
tarupotter/exercise8

Conversation

@Tarupotter
Copy link
Copy Markdown

@Tarupotter Tarupotter commented Nov 20, 2025

  • Added User and Workout entities.

  • Controllers for User and Workout to handle GET, POST, and DELETE requests

  • Basic login implemented with Spring Security.

  • Security tests ensure only authorized users can access endpoints.

  • Controller tests for GET, POST, and DELETE endpoints.

  • Thymeleaf views and simple CSS for frontend.

Summary by CodeRabbit

Release Notes

  • New Features

    • User management system with authentication and role-based access control
    • Workout tracking with automatic calorie calculations
    • Web-based dashboard for viewing and managing users and workouts
    • REST API endpoints for user and workout data operations
  • Infrastructure

    • MySQL database integration via Docker Compose
    • Spring Boot application framework
  • Tests

    • Added security and controller test coverage

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

kappsegla and others added 29 commits October 8, 2025 15:56
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Nov 20, 2025

Walkthrough

A basic Java template project is transformed into a Spring Boot 3.5.6 application featuring MySQL persistence, Spring Security authentication with in-memory users, REST and MVC controllers for user and workout management, a complete service/repository layer pattern, and HTML templates with Thymeleaf. Build configuration is migrated to Spring Boot conventions with simplified Maven plugins. Legacy test files are replaced with Spring Boot test classes.

Changes

Cohort / File(s) Summary
Infrastructure & Build
docker-compose.yml, pom.xml
New MySQL 9.5.0 service configuration; POM migration to Spring Boot parent with spring-boot-starter dependencies (web, data-jpa, test, thymeleaf, security), MySQL connector, Docker Compose support, and simplified spring-boot-maven-plugin replacing legacy multi-plugin setup
Application Entry Point
src/main/java/org/example/Exercise2025Application.java, src/main/java/org/example/App.java
Removed legacy App.java class; added new @SpringBootApplication-annotated entry point Exercise2025Application
Security
src/main/java/org/example/config/SecurityConfig.java
New @Configuration class defining SecurityFilterChain bean with form login and HTTP Basic auth; InMemoryUserDetailsManager bean registering two hardcoded users (user/admin with respective roles)
Domain Models
src/main/java/org/example/model/User.java, src/main/java/org/example/model/Workout.java
New JPA @Entity classes; User has id, username, email, password; Workout has id, name, duration, caloriesBurned, date; includes constructors and getters/setters
Data Access
src/main/java/org/example/repository/UserRepository.java, src/main/java/org/example/repository/WorkoutRepository.java
New JpaRepository interfaces providing standard CRUD operations for User and Workout entities
Service Layer
src/main/java/org/example/service/user/UserService.java, src/main/java/org/example/service/user/UserServiceImpl.java, src/main/java/org/example/service/workout/WorkoutService.java, src/main/java/org/example/service/workout/WorkoutServiceImpl.java
New service interfaces and @Service-annotated implementations; UserServiceImpl delegates CRUD to UserRepository; WorkoutServiceImpl calculates caloriesBurned as duration × 10 before persisting
REST Controllers
src/main/java/org/example/controller/UserController.java, src/main/java/org/example/controller/WorkoutController.java
New @RestController classes exposing CRUD endpoints at /api/users and /api/workouts with constructor-injected services; no validation or error handling in controllers
MVC Controllers
src/main/java/org/example/controller/UserViewController.java, src/main/java/org/example/controller/WorkoutViewController.java
New @Controller classes for view rendering; UserViewController and WorkoutViewController expose GET endpoints for view pages and POST endpoints for deletion/creation with redirects
Configuration
src/main/resources/application.properties
Database URL, credentials (user/secret), driver, Hibernate DDL auto-update, SQL logging, and MySQL dialect configured
Frontend
src/main/resources/templates/users.html, src/main/resources/templates/workouts.html, src/main/resources/static/css/style.css
New Thymeleaf templates displaying users and workouts in tables with delete/add forms; accompanying CSS with flexbox layout, table styling, zebra striping, and hover effects
Tests
src/test/java/org/example/Exercise2025ApplicationTest.java, src/test/java/org/example/controller/WorkoutControllerTest.java, src/test/java/org/example/security/SecurityAccessTest.java
Added @SpringBootTest context-loading test; @WebMvcTest with mocked WorkoutService covering authenticated/unauthenticated scenarios; security integration tests verifying HTTP Basic auth and 401 responses
Tests (Removed)
src/test/java/org/example/AppIT.java, src/test/java/org/example/AppTest.java
Removed legacy minimal test files containing trivial assertions

Sequence Diagram(s)

sequenceDiagram
    actor User as User/Browser
    participant MVC as MVC Controller<br/>(UserViewController)
    participant Service as Service<br/>(UserService)
    participant Repo as Repository<br/>(UserRepository)
    participant DB as MySQL DB

    User->>MVC: GET /users
    MVC->>Service: getAllUsers()
    Service->>Repo: findAll()
    Repo->>DB: SELECT * FROM users
    DB-->>Repo: User records
    Repo-->>Service: List<User>
    Service-->>MVC: List<User>
    MVC-->>User: Render users.html with table

    User->>MVC: POST /users/delete/{id}
    MVC->>Service: deleteUser(id)
    Service->>Repo: deleteById(id)
    Repo->>DB: DELETE FROM users
    DB-->>Repo: Success
    Repo-->>Service: void
    Service-->>MVC: void
    MVC-->>User: Redirect to /users
Loading
sequenceDiagram
    actor Client as REST Client
    participant Sec as Security Filter<br/>(HTTP Basic)
    participant API as REST Controller<br/>(WorkoutController)
    participant Service as Service<br/>(WorkoutService)
    participant Repo as Repository<br/>(WorkoutRepository)
    participant DB as MySQL DB

    Client->>Sec: GET /api/workouts<br/>(with credentials)
    Sec->>Sec: Authenticate via<br/>InMemoryUserDetailsManager
    alt Authenticated
        Sec->>API: Proceed
        API->>Service: getAllWorkouts()
        Service->>Repo: findAll()
        Repo->>DB: SELECT * FROM workouts
        DB-->>Repo: Workout records
        Repo-->>Service: List<Workout>
        Service-->>API: List<Workout>
        API-->>Client: HTTP 200 + JSON array
    else Unauthenticated
        Sec-->>Client: HTTP 401 Unauthorized
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

  • Security configuration scrutiny needed: In-memory user credentials hardcoded in code; default password encoder used; ROLE assignments and HTTP Basic vs. form-login security posture require validation against requirements
  • Service logic verification: WorkoutServiceImpl.createWorkout() implements business logic (caloriesBurned = duration × 10); assumption-based calculation needs confirmation against business rules
  • Test mock coverage: WorkoutControllerTest uses @WebMvcTest with manual TestConfiguration; verify mock setup completeness and Jackson serialization of LocalDate fields
  • Database & ORM configuration: Hibernate DDL auto-update and MySQL dialect settings; connection pooling and transaction management not explicitly configured; verify defaults are acceptable
  • Template binding & form submission: Thymeleaf template variable binding, CSRF token handling (if applicable), and form action URL correctness require validation
  • Cross-cutting concerns: No explicit exception handling, validation annotations, or logging visible; confirm architectural expectations for error responses and observability
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch tarupotter/exercise8

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


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

🧹 Nitpick comments (18)
src/main/java/org/example/model/User.java (2)

15-17: Consider adding validation and unique constraints.

The entity fields lack validation annotations and unique constraints. Consider adding:

  • @Column(unique = true, nullable = false) for username and email
  • @NotBlank or @NotNull validation annotations
  • @Email for email field validation

This would prevent duplicate usernames/emails and ensure data integrity at both the database and application levels.

Example:

@Column(unique = true, nullable = false)
@NotBlank
private String username;

@Column(unique = true, nullable = false)
@Email
@NotBlank
private String email;

@Column(nullable = false)
@NotBlank
private String password;

8-54: Consider implementing equals(), hashCode(), and toString().

JPA entities benefit from properly implemented equals(), hashCode(), and toString() methods. This ensures correct behavior when using entities in collections, comparing instances, and debugging. Consider using the id field for equals/hashCode or IDE-generated implementations.

pom.xml (2)

55-59: Remove explicit version for mysql-connector-j.

The Spring Boot parent POM manages dependency versions, including mysql-connector-j. Explicitly specifying the version can lead to conflicts and prevents automatic updates through Spring Boot version upgrades.

Apply this diff:

 <dependency>
     <groupId>com.mysql</groupId>
     <artifactId>mysql-connector-j</artifactId>
-    <version>9.5.0</version>
 </dependency>

16-28: Remove or populate empty metadata tags.

The POM contains empty tags for <url/>, <license/>, <developer/>, and <scm/>. Either populate these with actual information or remove them to keep the POM clean.

Apply this diff to remove them:

-    <url/>
-    <licenses>
-        <license/>
-    </licenses>
-    <developers>
-        <developer/>
-    </developers>
-    <scm>
-        <connection/>
-        <developerConnection/>
-        <tag/>
-        <url/>
-    </scm>
src/main/resources/static/css/style.css (1)

2-57: LGTM! CSS provides clean and functional styling.

The styles create a responsive, visually appealing interface with good hover effects and spacing. The implementation is appropriate for this project.

Optional: Consider using CSS custom properties (variables) for repeated color values to improve maintainability:

:root {
    --primary-color: #aa69f5;
    --hover-color: #d6eaf8;
    --background-color: #f5f6fa;
    --text-color: #2c3e50;
}
src/main/resources/templates/users.html (1)

11-25: Align table headers with columns and consider CSRF token

You render three data columns (username, email, delete button) but only define two headers; adding an “Actions” header will keep the table aligned and clearer. Also, if CSRF protection is enabled in Spring Security, you should include the CSRF token in this POST delete form to avoid 403 errors.

Example diff:

-    <tr>
-        <th>Username</th>
-        <th>Email</th>
-    </tr>
+    <tr>
+        <th>Username</th>
+        <th>Email</th>
+        <th>Actions</th>
+    </tr>
@@
-        <td>
-            <form th:action="@{/users/delete/{id}(id=${user.id})}" method="post">
-                <button type="submit" class="button" onclick="return confirm('Are you sure?')">Delete</button>
-            </form>
-        </td>
+        <td>
+            <form th:action="@{/users/delete/{id}(id=${user.id})}" method="post">
+                <!-- Uncomment/adapt if CSRF is enabled -->
+                <!-- <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" /> -->
+                <button type="submit" class="button" onclick="return confirm('Are you sure?')">Delete</button>
+            </form>
+        </td>
src/main/resources/application.properties (1)

2-9: Treat these datasource and JPA settings as dev-only defaults

For this exercise repo, hard-coded DB creds and ddl-auto=update/show-sql=true are fine, but in a more realistic setup you’d typically:

  • Move spring.datasource.username/password to external config (env vars, profiles).
  • Restrict spring.jpa.hibernate.ddl-auto=update and spring.jpa.show-sql=true to a local/dev profile.
  • Optionally rely on Spring Boot’s auto-detected driver and dialect instead of configuring driver-class-name and hibernate.dialect explicitly.

This isn’t blocking here, but worth keeping in mind if the app is ever promoted beyond training use. Based on learnings

src/main/java/org/example/service/workout/WorkoutService.java (1)

7-12: Clarify service contract and consider using a common language for comments

The interface is straightforward, but two small improvements could help:

  • Document what happens when getWorkoutById(Long id) is called with a non‑existing id (exception vs null, etc.), so callers know what to expect.
  • Consider rewriting the Swedish comment to English (or the team’s agreed language) to keep the codebase consistent for all contributors.
src/test/java/org/example/security/SecurityAccessTest.java (1)

20-31: Consider expanding security test coverage to include User endpoints.

The security tests for /api/workouts are well-structured and cover both authenticated and unauthenticated scenarios. However, the /api/users endpoint (introduced in UserController) also requires security validation.

Consider adding similar tests for /api/users:

+    @Test
+    void adminShouldAccessUsersPage() throws Exception {
+        mockMvc.perform(get("/api/users")
+                        .with(httpBasic("admin", "adminpass")))
+                .andExpect(status().isOk());
+    }
+
+    @Test
+    public void testGetAllUsers_unauthenticated_shouldReturn401() throws Exception {
+        mockMvc.perform(get("/api/users"))
+                .andExpect(status().isUnauthorized());
+    }
src/main/java/org/example/service/user/UserService.java (1)

7-13: Interface looks good.

The service interface follows standard Spring conventions with appropriate CRUD method signatures. The Swedish comment is understandable given the learning context, though maintaining consistent language (English) throughout the codebase can improve maintainability.

src/main/java/org/example/controller/UserViewController.java (1)

22-32: Consider adding a POST endpoint for creating users.

The controller handles listing and deleting users, but lacks the ability to add new users via the UI. WorkoutViewController includes a /add endpoint for creating workouts. Adding a similar endpoint here would provide consistent functionality across both entities.

Consider adding:

@PostMapping("/add")
public String addUser(@ModelAttribute User user) {
    userService.createUser(user);
    return "redirect:/users";
}

This would align with the pattern established in WorkoutViewController and require a corresponding form in the users.html template.

src/main/java/org/example/controller/UserController.java (1)

18-36: Consider enhancing error handling and HTTP status codes.

The REST endpoints implement basic CRUD operations correctly. For a more robust API, consider these improvements:

  1. getUserById (Line 29-31): Returns null when user not found. Consider returning ResponseEntity<User> with a 404 status for missing users.
  2. createUser (Line 24-26): Could return 201 Created status and validate input.
  3. deleteUser (Line 34-36): Returns void. Consider returning 204 No Content or handling non-existent IDs with a 404.

Example for getUserById:

@GetMapping("/{id}")
public ResponseEntity<User> getUserById(@PathVariable Long id) {
    User user = userService.getUserById(id);
    return user != null ? ResponseEntity.ok(user) : ResponseEntity.notFound().build();
}
src/main/java/org/example/controller/WorkoutController.java (1)

21-42: Consider enhancing error handling and maintaining language consistency.

Similar to UserController, the REST endpoints would benefit from proper error handling:

  1. getWorkoutById (Line 35-37): Returns null when workout not found. Consider using ResponseEntity<Workout> with 404 status.
  2. createWorkout (Line 29-31): Could return 201 Created status.
  3. deleteWorkout (Line 40-42): Returns void. Consider returning 204 No Content or handling non-existent IDs.

Additionally, the Swedish comments (lines 21, 27, 33) are understandable in a learning context, but maintaining consistent language throughout the codebase improves maintainability.

src/main/java/org/example/service/user/UserServiceImpl.java (1)

27-30: Consider returning Optional instead of null.

Line 29 uses orElse(null), which forces callers to perform null checks. Returning Optional<User> would provide a more expressive API and align with modern Java practices.

 @Override
-public User getUserById(Long id) {
-    return userRepository.findById(id).orElse(null);
+public Optional<User> getUserById(Long id) {
+    return userRepository.findById(id);
 }

This would require updating the service interface and controller accordingly.

src/test/java/org/example/controller/WorkoutControllerTest.java (1)

28-97: Excellent test coverage for WorkoutController.

The test class demonstrates good practices:

  • Proper use of @WebMvcTest to test only the controller layer
  • Mock bean configuration through @TestConfiguration
  • Security testing for both authenticated and unauthenticated scenarios
  • CSRF token handling for state-changing operations
  • JSON response validation with appropriate date serialization

Consider adding similar test coverage for UserController to ensure consistent testing across all REST endpoints.

src/main/java/org/example/service/workout/WorkoutServiceImpl.java (1)

34-37: Consider returning Optional instead of null.

Returning null via orElse(null) can lead to NPE in calling code. Consider returning Optional<Workout> from the service method to make the absence of a value explicit.

If you'd like to refactor:

 @Override
-public Workout getWorkoutById(Long id) {
-    return workoutRepository.findById(id).orElse(null);
+public Optional<Workout> getWorkoutById(Long id) {
+    return workoutRepository.findById(id);
 }

Note: This would require updating the service interface and any calling code.

src/main/java/org/example/model/Workout.java (2)

10-19: Consider adding validation constraints.

The entity fields lack validation annotations. For a more robust implementation, consider adding constraints like @NotBlank for name and @NotNull or @Min for numeric fields to ensure data integrity.

Example:

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

    @NotBlank(message = "Name is required")
    private String name;
    
    @NotNull(message = "Duration is required")
    @Min(value = 1, message = "Duration must be positive")
    private Integer duration;
    
    private Integer caloriesBurned;
    
    @NotNull(message = "Date is required")
    private LocalDate date;
    // ...
}

33-67: Consider adding equals, hashCode, and toString methods.

For JPA entities, it's good practice to override equals(), hashCode(), and toString() methods. This helps with entity comparison, collection usage, and debugging.

Example (focusing on business key):

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (!(o instanceof Workout)) return false;
    Workout workout = (Workout) o;
    return Objects.equals(id, workout.id);
}

@Override
public int hashCode() {
    return Objects.hash(id);
}

@Override
public String toString() {
    return "Workout{" +
           "id=" + id +
           ", name='" + name + '\'' +
           ", duration=" + duration +
           ", caloriesBurned=" + caloriesBurned +
           ", date=" + date +
           '}';
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8618163 and 296bbf8.

📒 Files selected for processing (26)
  • docker-compose.yml (1 hunks)
  • pom.xml (1 hunks)
  • src/main/java/org/example/App.java (0 hunks)
  • src/main/java/org/example/Exercise2025Application.java (1 hunks)
  • src/main/java/org/example/config/SecurityConfig.java (1 hunks)
  • src/main/java/org/example/controller/UserController.java (1 hunks)
  • src/main/java/org/example/controller/UserViewController.java (1 hunks)
  • src/main/java/org/example/controller/WorkoutController.java (1 hunks)
  • src/main/java/org/example/controller/WorkoutViewController.java (1 hunks)
  • src/main/java/org/example/model/User.java (1 hunks)
  • src/main/java/org/example/model/Workout.java (1 hunks)
  • src/main/java/org/example/repository/UserRepository.java (1 hunks)
  • src/main/java/org/example/repository/WorkoutRepository.java (1 hunks)
  • src/main/java/org/example/service/user/UserService.java (1 hunks)
  • src/main/java/org/example/service/user/UserServiceImpl.java (1 hunks)
  • src/main/java/org/example/service/workout/WorkoutService.java (1 hunks)
  • src/main/java/org/example/service/workout/WorkoutServiceImpl.java (1 hunks)
  • src/main/resources/application.properties (1 hunks)
  • src/main/resources/static/css/style.css (1 hunks)
  • src/main/resources/templates/users.html (1 hunks)
  • src/main/resources/templates/workouts.html (1 hunks)
  • src/test/java/org/example/AppIT.java (0 hunks)
  • src/test/java/org/example/AppTest.java (0 hunks)
  • src/test/java/org/example/Exercise2025ApplicationTest.java (1 hunks)
  • src/test/java/org/example/controller/WorkoutControllerTest.java (1 hunks)
  • src/test/java/org/example/security/SecurityAccessTest.java (1 hunks)
💤 Files with no reviewable changes (3)
  • src/test/java/org/example/AppIT.java
  • src/test/java/org/example/AppTest.java
  • src/main/java/org/example/App.java
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: jennymakki
Repo: fungover/exercise2025 PR: 204
File: src/main/java/org/example/config/SecurityConfig.java:19-24
Timestamp: 2025-11-16T13:56:11.263Z
Learning: The repository fungover/exercise2025 is an exercise/learning project where hard-coded credentials and other shortcuts for ease of testing are acceptable and intentional.
📚 Learning: 2025-09-10T14:02:54.365Z
Learnt from: alfredbrannare
Repo: fungover/exercise2025 PR: 66
File: src/test/java/org/example/service/WarehouseTest.java:1-21
Timestamp: 2025-09-10T14:02:54.365Z
Learning: In the fungover/exercise2025 project, static mocking of LocalDateTime.now() works successfully with the existing Mockito setup without requiring mockito-inline dependency.

Applied to files:

  • src/test/java/org/example/Exercise2025ApplicationTest.java
📚 Learning: 2025-11-16T13:56:11.263Z
Learnt from: jennymakki
Repo: fungover/exercise2025 PR: 204
File: src/main/java/org/example/config/SecurityConfig.java:19-24
Timestamp: 2025-11-16T13:56:11.263Z
Learning: The repository fungover/exercise2025 is an exercise/learning project where hard-coded credentials and other shortcuts for ease of testing are acceptable and intentional.

Applied to files:

  • src/test/java/org/example/Exercise2025ApplicationTest.java
  • src/main/resources/application.properties
  • src/main/java/org/example/Exercise2025Application.java
  • pom.xml
🧬 Code graph analysis (6)
src/main/java/org/example/service/user/UserServiceImpl.java (1)
src/main/java/org/example/service/workout/WorkoutServiceImpl.java (1)
  • Service (10-44)
src/main/java/org/example/controller/UserViewController.java (1)
src/main/java/org/example/controller/WorkoutViewController.java (1)
  • Controller (9-36)
src/main/java/org/example/controller/UserController.java (1)
src/main/java/org/example/controller/WorkoutController.java (1)
  • RestController (10-43)
src/main/java/org/example/service/workout/WorkoutServiceImpl.java (1)
src/main/java/org/example/service/user/UserServiceImpl.java (1)
  • Service (9-36)
src/main/java/org/example/controller/WorkoutViewController.java (1)
src/main/java/org/example/controller/UserViewController.java (1)
  • Controller (12-33)
src/main/java/org/example/controller/WorkoutController.java (1)
src/main/java/org/example/controller/UserController.java (1)
  • RestController (9-37)
🔇 Additional comments (12)
src/main/java/org/example/config/SecurityConfig.java (2)

19-30: LGTM! Security configuration is appropriate for this exercise project.

The security filter chain correctly enforces authentication on all requests, enables form login, and configures HTTP Basic authentication. The configuration is well-structured and follows Spring Security best practices.


34-48: LGTM! In-memory users are appropriate for this exercise project.

The use of withDefaultPasswordEncoder() and hard-coded credentials is acceptable for this learning/exercise project context.

Based on learnings.

docker-compose.yml (1)

1-10: LGTM! Docker Compose configuration is appropriate for development.

The MySQL service configuration is well-structured with appropriate environment variables and port mapping. The hard-coded credentials are acceptable for this exercise/development environment.

Based on learnings.

src/main/java/org/example/repository/WorkoutRepository.java (1)

1-7: LGTM! Standard Spring Data JPA repository.

The repository interface follows Spring Data JPA conventions correctly and will provide all standard CRUD operations for the Workout entity.

src/main/resources/templates/workouts.html (1)

1-40: LGTM! Template structure and Thymeleaf integration look good.

The template properly uses Thymeleaf syntax for rendering workouts, includes proper CSRF protection (automatically handled by Spring Security with Thymeleaf), and provides good user experience with confirmation dialogs for deletion.

pom.xml (1)

30-30: Java 25 is released and generally available. Java 25 reached General Availability on September 16, 2025, and production-ready builds are available from Microsoft and other vendors. The specified version is appropriate for development and CI/CD environments.

src/main/java/org/example/repository/UserRepository.java (1)

1-7: Repository definition looks good

The UserRepository correctly extends the Spring Data JpaRepository with User and Long and keeps the interface minimal. No changes needed here.

src/test/java/org/example/Exercise2025ApplicationTest.java (1)

6-11: Good use of a context load smoke test

The @SpringBootTest + contextLoads() pattern is a solid way to verify the full application context starts with the new Spring Boot setup. Looks fine as-is.

src/main/java/org/example/controller/WorkoutViewController.java (1)

19-35: LGTM!

The controller provides a complete set of operations for managing workouts through the UI. Constructor injection, proper delegation to the service layer, and consistent redirect patterns are all well-implemented.

src/main/java/org/example/service/workout/WorkoutServiceImpl.java (2)

10-17: LGTM!

Constructor injection and service setup follow Spring best practices.


20-23: LGTM!

Simple delegation pattern is appropriate here.

src/main/java/org/example/model/Workout.java (1)

21-31: LGTM!

The constructors are correctly designed for JPA: a no-arg constructor for the framework and a parameterized constructor excluding the auto-generated ID.

Comment on lines +9 to +11
void main(String[] args) {
SpringApplication.run(Exercise2025Application.class, args);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: Main method must be public static.

The main method signature is incorrect. Java requires the entry point to be public static void main(String[] args). Without the public static modifiers, the JVM cannot locate or execute this method, preventing the application from starting.

Apply this diff to fix the signature:

-    void main(String[] args) {
+    public static void main(String[] args) {
         SpringApplication.run(Exercise2025Application.class, args);
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
void main(String[] args) {
SpringApplication.run(Exercise2025Application.class, args);
}
public static void main(String[] args) {
SpringApplication.run(Exercise2025Application.class, args);
}
🤖 Prompt for AI Agents
In src/main/java/org/example/Exercise2025Application.java around lines 9 to 11,
the main method is missing the required modifiers — change the method signature
to public static void main(String[] args) so the JVM can find and execute the
entry point, leaving the existing SpringApplication.run(...) call intact.


private String username;
private String email;
private String 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

Password should be hashed, not stored as plain text.

The password field stores credentials as plain text, which is a security risk. Even in an exercise project, it's good practice to hash passwords using BCrypt or a similar algorithm before storing them in the database.

Consider adding password encoding in the service layer before persisting users, or use Spring Security's PasswordEncoder bean to hash passwords.

🤖 Prompt for AI Agents
In src/main/java/org/example/model/User.java around line 17 the password field
is stored in plain text; change handling so passwords are hashed before
persistence: keep the String field but do not save raw values — inject a
PasswordEncoder (e.g. BCryptPasswordEncoder via Spring Security) into the
service that creates/updates users and call encoder.encode(rawPassword) before
setting the entity’s password, use encoder.matches(rawPassword, storedHash) for
authentication, ensure the password getter is not serialized/exposed (e.g.
@JsonIgnore or remove from DTOs) and never log plain passwords.

Comment on lines +26 to +32
public Workout createWorkout(Workout workout) {

int calories = workout.getDuration() * 10;
workout.setCaloriesBurned(calories);

return workoutRepository.save(workout);
}
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

Guard against NPE when duration is null.

If workout.getDuration() returns null, line 28 will throw a NullPointerException during unboxing. Add validation or a null check before the calculation.

Apply this diff to add a null check:

 @Override
 public Workout createWorkout(Workout workout) {
-
-    int calories = workout.getDuration() * 10;
+    Integer duration = workout.getDuration();
+    int calories = (duration != null) ? duration * 10 : 0;
     workout.setCaloriesBurned(calories);
 
     return workoutRepository.save(workout);
 }

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

🤖 Prompt for AI Agents
In src/main/java/org/example/service/workout/WorkoutServiceImpl.java around
lines 26 to 32, guard against a NullPointerException when calling
workout.getDuration(): check if workout.getDuration() == null before computing
calories; if null, either throw an IllegalArgumentException with a clear message
(e.g., "duration must not be null") or treat it as 0 (set calories to 0), then
proceed to setCaloriesBurned and save; ensure you do not perform arithmetic on a
null Integer.

Comment on lines +33 to +38
<form th:action="@{/workouts/add}" method="post">
Activity: <input type="text" name="name" required/>
Duration (min): <input type="number" name="duration" required/>
Date: <input type="date" name="date" required/>
<button type="submit" class="button">Add</button>
</form>
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

Missing caloriesBurned input field in the add form.

The table displays a "Calories" column (line 14) and shows workout.caloriesBurned (line 22), but the add workout form doesn't include an input field for this value. This inconsistency will likely result in workouts being created with null or default calorie values.

Apply this diff to add the missing field:

 <form th:action="@{/workouts/add}" method="post">
     Activity: <input type="text" name="name" required/>
     Duration (min): <input type="number" name="duration" required/>
+    Calories Burned: <input type="number" name="caloriesBurned" required/>
     Date: <input type="date" name="date" required/>
     <button type="submit" class="button">Add</button>
 </form>
📝 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
<form th:action="@{/workouts/add}" method="post">
Activity: <input type="text" name="name" required/>
Duration (min): <input type="number" name="duration" required/>
Date: <input type="date" name="date" required/>
<button type="submit" class="button">Add</button>
</form>
<form th:action="@{/workouts/add}" method="post">
Activity: <input type="text" name="name" required/>
Duration (min): <input type="number" name="duration" required/>
Calories Burned: <input type="number" name="caloriesBurned" required/>
Date: <input type="date" name="date" required/>
<button type="submit" class="button">Add</button>
</form>
🤖 Prompt for AI Agents
In src/main/resources/templates/workouts.html around lines 33 to 38, the
add-workout form is missing an input for caloriesBurned which causes new
workouts to lack calorie data; update the form to include a numeric input named
"caloriesBurned" (e.g., label "Calories:" with <input type="number"
name="caloriesBurned" required min="0" step="1">) placed with the other fields
before the submit button so the calories value is submitted with the form and
matches the table's Calories column.

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.

2 participants