Skip to content

Paajt/exercise8#215

Open
Paajt wants to merge 34 commits intomainfrom
Paajt/exercise8
Open

Paajt/exercise8#215
Paajt wants to merge 34 commits intomainfrom
Paajt/exercise8

Conversation

@Paajt
Copy link
Copy Markdown

@Paajt Paajt commented Nov 21, 2025

Issue #193

This pull request contains an implementation of a RESTful web service for managing virtual pets using:

  • Spring Boot 3.5
  • Spring Data JPA
  • Spring Security
  • Thymeleaf
  • The service runs on an embedded Tomcat server with MySQL 9.5 database persistence via Docker Compose.

Features

  • Pet Entity with Bean Validation annotations: @ValidName, @ValidSpecies, @ValidHungerLevel, @ValidHappinessLevel
  • Spring Data JPA for database persistence with MySQL 9.5
  • Flyway migrations for database schema versioning and sample data
  • Spring Security with role-based access control (ADMIN & USER roles)

RESTful Endpoints

  • GET /api/pets - List all pets (200 OK, public access)
  • POST /api/pets - Create a new pet (201 Created, ADMIN only)
  • GET /api/pets/{id} - View pet status (200 OK, public access)
  • PUT /api/pets/{id}/feed - Feed the pet (200 OK, authenticated users)
  • PUT /api/pets/{id}/play - Play with pet (200 OK, authenticated users)
  • DELETE /api/pets/{id} - Delete a pet (204 No Content, ADMIN only)

Default values (5) for hungerLevel and happinessLevel when not provided.

Query Features

  • Filtering: GET /api/pets?species=dog
  • Sorting: GET /api/pets?sortBy=happinessLevel&order=desc
    • Supports: name, species, hungerLevel, happinessLevel
  • Pagination: GET /api/pets?offset=0&limit=5
  • Combined: GET /api/pets?species=dog&sortBy=happinessLevel&order=desc&offset=1&limit=4

Note: These features are available via REST API only. The Thymeleaf web interface displays all pets without filtering/sorting/pagination.

Security

  • Form-based authentication for web interface
  • HTTP Basic authentication for REST API
  • In-memory user store with test users:
    • user / password (USER role)
    • admin / admin (ADMIN & USER roles)

Note for @coderabbitai: Hardcoded credentials are used intentionally for educational purposes. In production, credentials would be externalized using environment variables or secrets management.

Exception Handling

  • GlobalExceptionHandler with @ControllerAdvice
  • 400 Bad Request for validation failures and invalid operations
  • 404 Not Found for missing pets

Thymeleaf Web Interface

  • Interactive home page with role-based UI
  • Visual hunger/happiness progress bars
  • Admin panel for creating pets
  • Login/logout functionality
  • Form validation with user-friendly error messages

Note: Filtering, sorting, and pagination are only available via REST API endpoints, not in the Thymeleaf UI.

Testing

  • 14 controller tests using @WebMvcTest
  • Security validation for Anonymous, USER, and ADMIN roles
  • Coverage: 401 Unauthorized, 403 Forbidden, 200 OK, 201 Created, 204 No Content

Sample Data

7 sample pets included via Flyway migration

Technologies

  • Spring Boot 3.5.7
  • Java 25
  • Spring Data JPA
  • Spring Security
  • Thymeleaf
  • MySQL 9.5 (Docker)
  • Flyway
  • JUnit 5 + MockMvc + Mockito

Quick Start

  1. Checkout branch
git checkout Paajt/exercise8
  1. Start Docker Desktop (must be running)

  2. Run PetApplication.java

  3. Access the application:

Tests

Run PetControllerTest.java

Summary by CodeRabbit

  • New Features

    • Full pet management UI and REST API with create/read/update/delete, feed/play actions, filters, sorting, and pagination; role-based access (user/admin) and improved error handling.
  • Documentation

    • Added HTTP request examples and error/test scenarios for API flows.
  • Chores

    • MySQL docker-compose service, Flyway DB migration with seed data, Spring Boot build/dependency updates, app configuration tweaks.
  • Tests

    • Added comprehensive controller tests; removed trivial legacy tests.

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

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Nov 21, 2025

Walkthrough

Replaces the starter app with a Spring Boot Pet Management service: adds application entrypoint, JPA entity/repository, service layer, REST and web controllers, security, Flyway migration, MySQL docker-compose, Thymeleaf templates/CSS, centralized exception handling, HTTP request specs, tests, and a rewritten Maven POM.

Changes

Cohort / File(s) Summary
Infrastructure & Build
docker-compose.yml, pom.xml
Adds MySQL service to docker-compose; replaces/rewrites POM to use spring-boot-starter-parent (3.5.7), Java 25, Spring Boot starters (web, data-jpa, security, thymeleaf), Flyway, MySQL connector, docker-compose support, and reconfigures plugins.
Application Entry
src/main/java/org/example/App.java (deleted), src/main/java/org/example/PetApplication.java
Removes legacy App.java; adds Spring Boot application class PetApplication with public static void main.
Domain & Persistence
src/main/java/org/example/entities/Pet.java, src/main/java/org/example/repositories/PetRepository.java, src/main/resources/db/migration/V1__Initial.sql
New JPA Pet entity with validation, defaults, createdAt, proxy-safe equals/hashCode; repository with case-insensitive queries; Flyway V1 creates pet table with constraints and seed data.
Business Logic
src/main/java/org/example/services/PetService.java
New service implementing retrieval (filter/sort/pagination), add, feed, play, and delete operations with transactional annotations and domain exceptions (NotFound/BadRequest).
REST API
src/main/java/org/example/controllers/PetController.java
New @RestController exposing /api/pets endpoints: list (filters/sort/pagination), get, create (validation), feed, play, delete; uses ResponseEntity where appropriate.
Web UI & Assets
src/main/java/org/example/controllers/WebController.java, src/main/resources/templates/index.html, src/main/resources/static/css/style.css
New web controller for home and form actions; Thymeleaf template and CSS for UI, admin form, pet grid, action buttons and feedback.
Security
src/main/java/org/example/config/SecurityConfig.java
New Spring Security config: SecurityFilterChain with route-based rules, CSRF customizations (ignores /api/**), in-memory users (user/admin), and PasswordEncoder.
Exceptions & Handling
src/main/java/org/example/exceptions/NotFoundException.java, .../BadRequestException.java, .../GlobalExceptionHandler.java
Adds NotFound/BadRequest exceptions and @ControllerAdvice mapping exceptions and validation errors to JSON responses (404/400/500) and logs unexpected exceptions.
Configuration Files
src/main/resources/application.properties, src/main/resources/application-dev.properties
Adds application name and virtual-thread flag; dev properties set docker-compose lifecycle to start_only, JPA validate, SQL logging/formatting, and security debug logging.
HTTP Request Specs
pet.http, petService.http, exceptions.http
Adds HTTP request files documenting API endpoints (filters/sort/pagination), service examples, and exception scenarios.
Tests
src/test/java/org/example/controllers/PetControllerTest.java, src/test/java/org/example/AppTest.java (deleted), src/test/java/org/example/AppIT.java (deleted)
Adds WebMvcTest suite for PetController covering role-based access and payloads; removes trivial legacy unit/integration tests.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant PetController
    participant PetService
    participant PetRepository
    participant DB as MySQL

    Note over User,DB: Feed pet flow (high-level)
    User->>PetController: PUT /api/pets/{id}/feed
    PetController->>PetService: feedPet(id)
    PetService->>PetRepository: findById(id)
    PetRepository->>DB: SELECT pet
    DB-->>PetRepository: pet row
    PetRepository-->>PetService: Optional<Pet>

    alt pet found and hunger>0
        PetService->>PetService: decrement hungerLevel
        PetService->>PetRepository: save(pet)
        PetRepository->>DB: UPDATE pet
        DB-->>PetRepository: updated row
        PetRepository-->>PetService: Pet
        PetService-->>PetController: Pet
        PetController-->>User: 200 OK (Pet)
    else not found
        PetService-->>PetController: NotFoundException
        PetController-->>User: 404 (handled by GlobalExceptionHandler)
    else hunger==0
        PetService-->>PetController: BadRequestException
        PetController-->>User: 400 (handled by GlobalExceptionHandler)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Pay extra attention to:
    • pom.xml: dependency/plugin compatibility with Java 25 and Spring Boot parent changes.
    • SecurityConfig.java: CSRF exclusions, route access rules, and in-memory user role mappings.
    • PetService.java: sorting comparator logic, offset/limit validation, and transactional semantics.
    • Pet entity and V1__Initial.sql: validation annotations vs. DB CHECK constraints alignment and equals/hashCode handling with Hibernate proxies.
    • PetControllerTest.java: security test wiring and mocked service interactions.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch Paajt/exercise8

📜 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 c09f541 and 67cf2b6.

📒 Files selected for processing (1)
  • pom.xml (2 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 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: Mockito 5.x (specifically version 5.19.0 via mockito-junit-jupiter dependency) includes static mocking capabilities without requiring a separate mockito-inline dependency, unlike older Mockito versions.

Applied to files:

  • pom.xml
📚 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:

  • pom.xml
🔇 Additional comments (2)
pom.xml (2)

111-113: ✅ Spring Boot Maven plugin correctly positioned and configured.

The plugin is appropriately placed and inherits version from the Spring Boot parent, which is the correct approach for Spring Boot projects.


114-146: ✅ Standard Maven plugins and failsafe integration testing configuration.

The plugin set is comprehensive and well-versioned. The failsafe plugin with integration-test/verify goals correctly enables integration testing as referenced in the PR objectives.


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 (16)
docker-compose.yml (1)

1-10: Consider adding a volume for data persistence.

While acceptable for a learning exercise, consider adding a volume mount to persist database data across container restarts during development.

   mysql:
     image: 'mysql:9.5.0'
     environment:
       - 'MYSQL_DATABASE=spring'
       - 'MYSQL_PASSWORD=secret'
       - 'MYSQL_ROOT_PASSWORD=verysecret'
       - 'MYSQL_USER=user'
     ports:
       - '3306:3306'
+    volumes:
+      - mysql-data:/var/lib/mysql
+
+volumes:
+  mysql-data:
src/main/resources/db/migration/V1__Initial.sql (1)

14-21: Consider omitting explicit IDs for cleaner AUTO_INCREMENT behavior.

While the current approach works, explicitly setting IDs in sample data can be fragile. If you later modify or re-run migrations, the AUTO_INCREMENT counter behavior might be unexpected.

-INSERT INTO pet (id, name, species, hunger_level, happiness_level, created_at) VALUES
-(1, 'Rex', 'Dog', 6, 9, NOW()),
-(2, 'Garfield', 'Cat', 10, 2, NOW()),
-(3, 'Missy', 'Cat', 8, 5, NOW()),
-(4, 'Quack', 'Bird', 1, 3, NOW()),
-(5, 'Chewy', 'Hamster', 3, 5, NOW()),
-(6, 'Leonardo', 'Turtle', 10, 4, NOW()),
-(7, 'Ricky', 'Dolphin', 1, 7, NOW());
+INSERT INTO pet (name, species, hunger_level, happiness_level, created_at) VALUES
+('Rex', 'Dog', 6, 9, NOW()),
+('Garfield', 'Cat', 10, 2, NOW()),
+('Missy', 'Cat', 8, 5, NOW()),
+('Quack', 'Bird', 1, 3, NOW()),
+('Chewy', 'Hamster', 3, 5, NOW()),
+('Leonardo', 'Turtle', 10, 4, NOW()),
+('Ricky', 'Dolphin', 1, 7, NOW());
pom.xml (1)

17-28: Remove empty metadata elements for cleaner POM.

The empty <license/>, <developer/>, and <scm/> elements serve no purpose and clutter the POM.

-    <url/>
-    <licenses>
-        <license/>
-    </licenses>
-    <developers>
-        <developer/>
-    </developers>
-    <scm>
-        <connection/>
-        <developerConnection/>
-        <tag/>
-        <url/>
-    </scm>
src/main/java/org/example/config/SecurityConfig.java (1)

64-64: Use English for code comments.

The comment is in Swedish, which breaks consistency with the rest of the codebase.

-                        // CSRF enabled för Thymeleaf forms
+                        // CSRF enabled for Thymeleaf forms
src/main/java/org/example/exceptions/NotFoundException.java (1)

1-10: LGTM!

The exception class is correctly implemented and follows the same pattern as BadRequestException. It appropriately extends RuntimeException for use in HTTP 404 scenarios.

Optionally, you could remove the extra blank line at line 3 for consistency:

 package org.example.exceptions;
 
-
 // Exception for when a requested pet is not found - HTTP 404 Not Found
 public class NotFoundException extends RuntimeException {
src/main/java/org/example/repositories/PetRepository.java (1)

1-18: Remove unused findByNameIgnoreCase method

Verification confirms this method has no invocations in the codebase. Remove it to keep the repository interface lean and focused on actually-used query methods.

src/test/java/org/example/controllers/PetControllerTest.java (1)

45-63: Consider adding tests for query parameters and error scenarios

Right now getAllPetsShouldReturnListOfPetsForAnonymousUser only covers the no‑query‑param case, and other tests don’t exercise species, sortBy, order, offset, or limit, nor 4xx paths (e.g. invalid params, not‑found from service). Adding a couple of focused tests that assert the mapping of query parameters to petService.getAllPets(...) and that 404/400 from the service are translated via GlobalExceptionHandler would better lock down the controller contract.

Also applies to: 176-235

src/main/java/org/example/controllers/PetController.java (2)

40-47: Be aware of coupling between REST API and JPA entity

Using Pet directly as the request/response body keeps things simple here but ties the external API to the persistence model (e.g., any future JPA-only fields show up in JSON). If this service grows, consider introducing a separate DTO for create/read to decouple API evolution from the entity.


22-32: Rename method for clarity and optionally add controller-level validation annotations

Method name getAllPetsService is awkward for a controller handler; rename to getAllPets for idiomatic REST naming. While offset/limit validation is performed in the service layer (via BadRequestException), consider adding Spring validation annotations (@Min(0) on offset, @Positive on limit, @Pattern on order) at the controller level for clearer fail-fast semantics and explicit contract documentation. Field whitelisting for sortBy is already implemented in PetService.getComparator().

src/main/java/org/example/entities/Pet.java (1)

88-111: Optionally restrict mutability of id and createdAt

setId and setCreatedAt make two persistence-managed fields mutable from application code. That’s often unnecessary and can lead to accidental changes diverging from DB state. If you don’t need to set these manually (outside tests), consider dropping the setters or reducing their visibility.

src/main/java/org/example/exceptions/GlobalExceptionHandler.java (1)

16-18: Align annotation with REST-only intent

The comment states "Global exception handler for all REST controllers," but the class uses @ControllerAdvice. @RestControllerAdvice automatically serializes exception handler return values to the response body as JSON, whereas @ControllerAdvice requires explicit @responsebody or ResponseEntity to achieve the same. If this handler is strictly for JSON REST APIs, consider using @RestControllerAdvice (or alternatively scope via basePackages / annotations if it must handle both REST and view controllers).

src/main/java/org/example/controllers/WebController.java (2)

27-51: Refactor exception handling to avoid exposing internal error details in flash messages

The current code catches Exception and directly surfaces e.getMessage() to the user:

} catch (Exception e) {
    redirectAttributes.addFlashAttribute("error", "Failed to create pet: " + e.getMessage());
}

This risks leaking database errors, stack trace fragments, or other internal details. Best practice is to catch domain-specific exceptions and map them to stable, user-facing error codes or message keys (e.g., {type: "error", code: "pet.creation.failed"}) via RedirectAttributes, then resolve these keys to localized strings in the template. Log full exception details server-side with correlation IDs, but present only generic or helpful text to users.

Consider:

  • Define a custom exception (e.g., PetCreationException) in your service layer
  • Catch it specifically in addPet and map to a stable error code
  • Centralize exception-to-message mapping in a @ControllerAdvice with @ExceptionHandler methods for consistency across controllers

53-72: Add exception handling with flash attributes to feedPet, playWithPet, and deletePet

The global exception handler returns JSON (ResponseEntity), so if petService.* throws (e.g., NotFoundException for a stale ID), the user sees a JSON error instead of a friendly page. Wrap these methods in try/catch and use RedirectAttributes to add flash error messages, matching the pattern in addPet.

src/main/java/org/example/services/PetService.java (3)

22-52: Pagination & validation behavior are mostly correct but could be clarified

  • Offset/limit validation rejects only negatives, but the message says “must be positive”. Since 0 is allowed, consider rephrasing to “must not be negative” or tightening the check to <= 0 for limit if zero is not meaningful.
  • When only one of offset or limit is provided, pagination is skipped entirely and the full list is returned. If the API is intended to support “offset only” or “limit only”, handling those cases explicitly would avoid surprises.

Otherwise, species filtering, sorting (including order=desc), and sublist bounds (start/end) are implemented safely.


77-89: Feeding logic is correct; consider slightly more defensive bounds

The method correctly:

  • 404s when the pet is missing.
  • Prevents feeding when hungerLevel == 0.
  • Decrements hunger by 1 otherwise.

If there’s any chance of corrupted data (e.g., negative hunger levels from outside this service), changing the guard to <= 0 would be a small defensive hardening; otherwise this is fine as-is.


91-103: Play logic mirrors feeding correctly; same note on upper bound

The happy-path and error-path behavior is consistent with feeding:

  • 404 on missing pet.
  • Prevents play when happinessLevel == 10.
  • Increments by 1 otherwise.

For extra robustness, you might consider checking >= 10 instead of == 10, mirroring the defensive comment on hunger.

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

📒 Files selected for processing (25)
  • docker-compose.yml (1 hunks)
  • exceptions.http (1 hunks)
  • pet.http (1 hunks)
  • petService.http (1 hunks)
  • pom.xml (1 hunks)
  • src/main/java/org/example/App.java (0 hunks)
  • src/main/java/org/example/PetApplication.java (1 hunks)
  • src/main/java/org/example/config/SecurityConfig.java (1 hunks)
  • src/main/java/org/example/controllers/PetController.java (1 hunks)
  • src/main/java/org/example/controllers/WebController.java (1 hunks)
  • src/main/java/org/example/entities/Pet.java (1 hunks)
  • src/main/java/org/example/exceptions/BadRequestException.java (1 hunks)
  • src/main/java/org/example/exceptions/GlobalExceptionHandler.java (1 hunks)
  • src/main/java/org/example/exceptions/NotFoundException.java (1 hunks)
  • src/main/java/org/example/repositories/PetRepository.java (1 hunks)
  • src/main/java/org/example/services/PetService.java (1 hunks)
  • src/main/resources/application-dev.properties (1 hunks)
  • src/main/resources/application.properties (1 hunks)
  • src/main/resources/db/migration/V1__Initial.sql (1 hunks)
  • src/main/resources/static/css/style.css (1 hunks)
  • src/main/resources/templates/index.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/PetApplicationTest.java (1 hunks)
  • src/test/java/org/example/controllers/PetControllerTest.java (1 hunks)
💤 Files with no reviewable changes (3)
  • src/test/java/org/example/AppTest.java
  • src/test/java/org/example/AppIT.java
  • src/main/java/org/example/App.java
🧰 Additional context used
🧠 Learnings (1)
📚 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:

  • pom.xml
  • src/main/resources/application.properties
🧬 Code graph analysis (1)
src/main/java/org/example/services/PetService.java (2)
src/main/java/org/example/exceptions/BadRequestException.java (1)
  • BadRequestException (4-9)
src/main/java/org/example/exceptions/NotFoundException.java (1)
  • NotFoundException (5-10)
🔇 Additional comments (20)
src/main/resources/application.properties (1)

1-2: LGTM! Virtual threads properly enabled.

The configuration correctly enables virtual threads, which are well-suited for I/O-bound workloads like this pet service. This pairs appropriately with Java 25 specified in the POM.

src/main/resources/application-dev.properties (1)

1-5: LGTM! Well-configured development profile.

The configuration appropriately uses validate for Hibernate DDL (letting Flyway manage schema), enables SQL logging for debugging, and sets Docker Compose to start_only mode for convenient development workflow.

src/main/resources/db/migration/V1__Initial.sql (1)

2-11: LGTM! Schema design is appropriate.

The table structure with CHECK constraints, default values, and AUTO_INCREMENT is well-designed for the pet management use case.

pom.xml (1)

5-10: LGTM! Spring Boot migration is well-structured.

The POM correctly migrates to Spring Boot 3.5.7 with appropriate dependencies for the pet service (web, JPA, Flyway, security, Thymeleaf). Dependency management through the Spring Boot parent simplifies version control.

Also applies to: 30-85

src/main/java/org/example/config/SecurityConfig.java (2)

22-68: LGTM! Security configuration is comprehensive and well-structured.

The role-based access control appropriately secures admin operations (create, delete), requires authentication for interactions (feed, play), and permits public read access. CSRF handling correctly distinguishes between REST API and web forms. Based on learnings.


71-83: LGTM! In-memory authentication is appropriate for this exercise project.

The hardcoded credentials and in-memory user store are acceptable for a learning/exercise environment. Based on learnings.

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

6-11: LGTM! Standard Spring Boot context smoke test.

This test verifies that the application context loads successfully, which is valuable for catching configuration issues early.

exceptions.http (1)

1-8: LGTM! Useful manual test scenarios for exception handling.

The HTTP test file provides convenient scenarios for manually verifying NotFoundException and BadRequestException handling.

docker-compose.yml (1)

3-3: MySQL 9.5.0 image exists and is valid—no changes needed.

The verification confirms that MySQL 9.5.0 is available in the Docker registry, along with other versions in the 9.x release series. The image specification in docker-compose.yml is correct and will resolve properly.

src/main/java/org/example/exceptions/BadRequestException.java (1)

1-9: LGTM!

The exception class follows standard Java patterns, properly extends RuntimeException, and is appropriately used for signaling invalid requests that should result in HTTP 400 responses.

src/main/resources/static/css/style.css (1)

1-225: LGTM!

The CSS is well-organized and comprehensive. It provides:

  • Responsive grid layout with proper breakpoints
  • Consistent color theming and visual hierarchy
  • Appropriate hover and disabled states for interactive elements
  • Smooth transitions for status bars
  • Clean, modern styling with good accessibility considerations

The implementation follows CSS best practices and should provide a good user experience.

pet.http (1)

1-113: Excellent API test documentation!

This HTTP test file provides comprehensive coverage of the Pet API, including:

  • All CRUD operations
  • Query parameters (filtering, sorting, pagination)
  • Validation scenarios with expected 400 responses
  • Edge cases with expected 404 responses
  • Combined query examples

This serves as both a testing tool and documentation for API consumers.

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

1-122: Well-implemented Thymeleaf template!

The template demonstrates good practices:

  • Proper use of Spring Security authorization directives
  • XSS protection via th:text for user content
  • CSRF protection via th:action for forms
  • Role-based UI rendering (Admin vs User vs Anonymous)
  • Client-side validation with required and maxlength
  • Confirmation dialog for destructive actions
  • Proper disabled states for action buttons at logical limits
src/test/java/org/example/controllers/PetControllerTest.java (1)

28-271: Solid controller test coverage and security checks

The tests nicely exercise all API endpoints with anonymous/user/admin roles, verify status codes, payloads, and ensure the service is (or is not) invoked as expected. Using csrf() on mutating requests avoids CSRF noise and keeps the focus on authorization semantics.

src/main/java/org/example/entities/Pet.java (1)

12-139: Entity mapping and validation look consistent

JPA mapping, Bean Validation constraints, default levels (5/5), and proxy-safe equals/hashCode are all coherent and match the described domain model. This is a solid base entity for the rest of the stack.

src/main/java/org/example/services/PetService.java (5)

13-20: Service wiring and constructor injection look solid

Using @Service with a final PetRepository and constructor injection is clear and test-friendly. No issues here.


55-63: Comparator switch is clean and matches documented sort fields

The switch on sortBy.toLowerCase() with case‑insensitive comparators for name/species and int comparators for levels is straightforward and safe, with a sensible fallback to id. This aligns well with the advertised sort keys.


65-69: Not-found handling is appropriate and consistent

Wrapping findById with an orElseThrow that produces a clear, id-specific message is a good pattern and keeps callers simple.


71-75: Simple create operation is fine; consider validation location

addPet is a straightforward save within a transaction. As long as Bean Validation is enforced at the controller or entity level (as described in the PR), this is sufficient and doesn’t need extra checks here.


105-113: Delete semantics are clear; minor note on return value vs API

Looking up the pet, throwing 404 if absent, then deleting is clear and safe. Returning the deleted Pet from the service can be useful for logging or UI, even if the REST DELETE endpoint ultimately responds with 204 and no body.

Comment thread petService.http
Comment on lines +1 to +11
### Get all pets via service
GET http://localhost:8080/test/service/pets

### Filter by species
GET http://localhost:8080/test/service/pets?species=Cat

### Sort by name
GET http://localhost:8080/test/service/pets?sortBy=name&order=asc

### Pagination
GET http://localhost:8080/test/service/pets?offset=2&limit=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

🧩 Analysis chain

Verify the endpoint path.

The HTTP requests target /test/service/pets, but according to the PR objectives, the REST API endpoints are under /api/pets. This path discrepancy may indicate a debug/test endpoint not mentioned in the documentation, or it could be a mistake.

Run the following script to verify if this endpoint exists in the codebase:


🏁 Script executed:

#!/bin/bash
# Description: Search for /test/service/pets endpoint mapping in controllers

# Search for the test/service/pets path in controller mappings
rg -nP --type=java -C3 '(RequestMapping|GetMapping|PostMapping|PutMapping|DeleteMapping|PatchMapping)\s*\([^)]*["\'].*?/test/service'

Length of output: 68


Let me fix the script syntax and try a broader search:


---

🏁 Script executed:

```shell
#!/bin/bash
# Description: Search for endpoint paths in controller mappings

# Search for any reference to /test/service or /api/pets paths
echo "=== Searching for /test/service endpoint ==="
rg -nC3 '/test/service' --type=java

echo ""
echo "=== Searching for /api/pets endpoint ==="
rg -nC3 '/api/pets' --type=java

echo ""
echo "=== Searching for controller class that might map to these paths ==="
rg -nC2 'RequestMapping\|GetMapping' --type=java | head -50

Length of output: 13377


Update endpoint paths from /test/service/pets to /api/pets.

The HTTP requests target /test/service/pets, but this endpoint does not exist in the codebase. The actual REST API is mapped at /api/pets in PetController (line 13), as confirmed by the controller definition and all test cases. Update all four requests in the file to use the correct endpoint path.

🤖 Prompt for AI Agents
In petService.http around lines 1 to 11, all four HTTP requests use the wrong
path `/test/service/pets`; update each request URL to use the correct controller
mapping `/api/pets` (i.e., replace `/test/service/pets` with `/api/pets` for the
Get all, Filter by species, Sort by name, and Pagination requests) so they match
PetController's endpoint and existing tests.

Comment thread src/main/java/org/example/exceptions/GlobalExceptionHandler.java
Comment thread src/main/java/org/example/exceptions/GlobalExceptionHandler.java
Comment thread src/main/java/org/example/PetApplication.java Outdated
Comment thread src/main/resources/templates/index.html Outdated
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: 2

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

16-28: Consider filling in or removing placeholder metadata.

Lines 16–28 contain empty or stub values for <url/>, <licenses>, <developers>, and <scm>. While acceptable in a learning project, populating these fields improves project professionalism and is helpful for documentation. For a real project, provide meaningful values; for a learning exercise, consider either filling them in or removing the empty placeholders entirely.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 96f55dc and ec8dfc5.

📒 Files selected for processing (1)
  • pom.xml (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 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:

  • pom.xml
🔇 Additional comments (1)
pom.xml (1)

5-10: Spring Boot dependency management is well-structured.

The POM correctly inherits from spring-boot-starter-parent:3.5.7, which provides transitive dependency version management for Spring Boot libraries. Test dependencies (junit-jupiter, assertj-core, spring-boot-starter-test, spring-security-test) are appropriately scoped to test. Runtime-specific dependencies (mysql-connector-j, spring-boot-docker-compose) are scoped to runtime. All required libraries for the pet service (web, security, JPA, Flyway, Thymeleaf, validation) are present.

Also applies to: 56-106

Comment thread pom.xml
Comment on lines +51 to +54
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>${mockito.version}</version>
</dependency>
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

Add test scope to mockito-junit-jupiter dependency.

The mockito-junit-jupiter dependency is missing the <scope>test</scope> attribute. Testing libraries should not leak into the production classpath; without an explicit scope, Maven defaults to compile, making mockito and its transitive dependencies available at runtime.

         <dependency>
         <groupId>org.mockito</groupId>
         <artifactId>mockito-junit-jupiter</artifactId>
         <version>${mockito.version}</version>
+        <scope>test</scope>
         </dependency>
🤖 Prompt for AI Agents
In pom.xml around lines 51 to 54, the mockito-junit-jupiter dependency is
missing a test scope so it defaults to compile and pollutes the production
classpath; update the dependency declaration to include a <scope>test</scope>
element inside that dependency block so Mockito and its transitive deps are only
on the test classpath.

Comment thread pom.xml Outdated
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