Conversation
…old HTTP-requests
WalkthroughReplaces 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
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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
✨ Finishing touches🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🧰 Additional context used🧠 Learnings (2)📚 Learning: 2025-09-10T14:02:54.365ZApplied to files:
📚 Learning: 2025-11-16T13:56:11.263ZApplied to files:
🔇 Additional comments (2)
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. Comment |
There was a problem hiding this comment.
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 formssrc/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 extendsRuntimeExceptionfor 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 unusedfindByNameIgnoreCasemethodVerification 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 scenariosRight now
getAllPetsShouldReturnListOfPetsForAnonymousUseronly covers the no‑query‑param case, and other tests don’t exercisespecies,sortBy,order,offset, orlimit, nor 4xx paths (e.g. invalid params, not‑found from service). Adding a couple of focused tests that assert the mapping of query parameters topetService.getAllPets(...)and that 404/400 from the service are translated viaGlobalExceptionHandlerwould 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 entityUsing
Petdirectly 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 annotationsMethod name
getAllPetsServiceis awkward for a controller handler; rename togetAllPetsfor idiomatic REST naming. While offset/limit validation is performed in the service layer (viaBadRequestException), consider adding Spring validation annotations (@Min(0)on offset,@Positiveon limit,@Patternon order) at the controller level for clearer fail-fast semantics and explicit contract documentation. Field whitelisting forsortByis already implemented inPetService.getComparator().src/main/java/org/example/entities/Pet.java (1)
88-111: Optionally restrict mutability ofidandcreatedAt
setIdandsetCreatedAtmake 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 intentThe 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 viabasePackages/annotationsif 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 messagesThe current code catches
Exceptionand directly surfacese.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
addPetand map to a stable error code- Centralize exception-to-message mapping in a
@ControllerAdvicewith@ExceptionHandlermethods for consistency across controllers
53-72: Add exception handling with flash attributes tofeedPet,playWithPet, anddeletePetThe global exception handler returns JSON (ResponseEntity), so if
petService.*throws (e.g.,NotFoundExceptionfor a stale ID), the user sees a JSON error instead of a friendly page. Wrap these methods in try/catch and useRedirectAttributesto add flash error messages, matching the pattern inaddPet.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
0is allowed, consider rephrasing to “must not be negative” or tightening the check to<= 0forlimitif zero is not meaningful.- When only one of
offsetorlimitis 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 boundsThe 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
<= 0would be a small defensive hardening; otherwise this is fine as-is.
91-103: Play logic mirrors feeding correctly; same note on upper boundThe 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
>= 10instead of== 10, mirroring the defensive comment on hunger.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 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.xmlsrc/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
validatefor Hibernate DDL (letting Flyway manage schema), enables SQL logging for debugging, and sets Docker Compose tostart_onlymode 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:textfor user content- CSRF protection via
th:actionfor forms- Role-based UI rendering (Admin vs User vs Anonymous)
- Client-side validation with
requiredandmaxlength- 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 checksThe 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 consistentJPA mapping, Bean Validation constraints, default levels (5/5), and proxy-safe
equals/hashCodeare 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 solidUsing
@Servicewith afinalPetRepositoryand constructor injection is clear and test-friendly. No issues here.
55-63: Comparator switch is clean and matches documented sort fieldsThe
switchonsortBy.toLowerCase()with case‑insensitive comparators forname/speciesand int comparators for levels is straightforward and safe, with a sensible fallback toid. This aligns well with the advertised sort keys.
65-69: Not-found handling is appropriate and consistentWrapping
findByIdwith anorElseThrowthat produces a clear, id-specific message is a good pattern and keeps callers simple.
71-75: Simple create operation is fine; consider validation location
addPetis a straightforwardsavewithin 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 APILooking up the pet, throwing 404 if absent, then deleting is clear and safe. Returning the deleted
Petfrom the service can be useful for logging or UI, even if the REST DELETE endpoint ultimately responds with 204 and no body.
| ### 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 |
There was a problem hiding this comment.
🧩 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.
There was a problem hiding this comment.
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
📒 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 totest. Runtime-specific dependencies (mysql-connector-j, spring-boot-docker-compose) are scoped toruntime. All required libraries for the pet service (web, security, JPA, Flyway, Thymeleaf, validation) are present.Also applies to: 56-106
| <groupId>org.mockito</groupId> | ||
| <artifactId>mockito-junit-jupiter</artifactId> | ||
| <version>${mockito.version}</version> | ||
| </dependency> |
There was a problem hiding this comment.
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.
Issue #193
This pull request contains an implementation of a RESTful web service for managing virtual pets using:
Features
@ValidName,@ValidSpecies,@ValidHungerLevel,@ValidHappinessLevelRESTful 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
GET /api/pets?species=dogGET /api/pets?sortBy=happinessLevel&order=descGET /api/pets?offset=0&limit=5GET /api/pets?species=dog&sortBy=happinessLevel&order=desc&offset=1&limit=4Note: These features are available via REST API only. The Thymeleaf web interface displays all pets without filtering/sorting/pagination.
Security
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
GlobalExceptionHandlerwith@ControllerAdviceThymeleaf Web Interface
Note: Filtering, sorting, and pagination are only available via REST API endpoints, not in the Thymeleaf UI.
Testing
@WebMvcTestSample Data
7 sample pets included via Flyway migration
Technologies
Quick Start
Start Docker Desktop (must be running)
Run PetApplication.java
Access the application:
Web UI: http://localhost:8080/
user/passwordfor (USER) oradmin/adminfor (ADMIN)REST API: http://localhost:8080/api/pets
Tests
Run PetControllerTest.java
Summary by CodeRabbit
New Features
Documentation
Chores
Tests
✏️ Tip: You can customize this high-level summary in your review settings.