---
# (DD41) Business Logic — PetController.findPet() [13 LOC]

| Field | Value |
|-------|-------|
| Fully Qualified Name | `org.springframework.samples.petclinic.owner.PetController` |
| Layer | Controller |
| Module | `owner` (Package: `org.springframework.samples.petclinic.owner`) |

## 1. Role

### PetController.findPet()

This method acts as the model population entry point for the Pet maintenance flow. It resolves the `pet` model attribute before the controller continues with downstream request handling, so the UI always receives either a fresh pet instance for creation or an existing pet loaded from the current owner’s data set for editing. In business terms, it supports two distinct service paths: pet registration and pet lookup within an owner aggregate. The method follows a routing/dispatch pattern based on the presence of `petId`, which determines whether the request is starting a new pet record or loading an existing one.

When no `petId` is supplied, the method creates a new `Pet` object and returns it immediately, enabling the add-pet screen to bind a blank form. When `petId` is present, it performs an owner-level validation step by loading the owner through the repository and then delegates to the owner aggregate to retrieve the specific pet. If the owner cannot be found, the method fails fast with an `IllegalArgumentException`, preventing the controller from proceeding with an invalid owner context. As a result, this method is a small but critical orchestration point that ensures every subsequent pet form submission works with a properly scoped domain object.

## 2. Processing Pattern (Detailed Business Logic)

```mermaid
flowchart TD
    START(["findPet(ownerId, petId)"])
    DECIDE1{"petId == null"}
    NEWPET["Create new Pet"]
    RETURN_NEW(["Return new Pet"])
    FINDOWNER["owners.findById(ownerId)"]
    OWNEROPT{"Owner present"}
    THROW["Throw IllegalArgumentException"]
    GETPET["owner.getPet(petId)"]
    RETURN_EXISTING(["Return owner.getPet(petId)"])

    START --> DECIDE1
    DECIDE1 -->|Yes| NEWPET
    NEWPET --> RETURN_NEW
    DECIDE1 -->|No| FINDOWNER
    FINDOWNER --> OWNEROPT
    OWNEROPT -->|No| THROW
    OWNEROPT -->|Yes| GETPET
    GETPET --> RETURN_EXISTING
```

**Constant resolution:** No application constants are referenced in this method.

## 3. Parameter Analysis

| No | Parameter Name | Type | Business Description |
|----|---------------|------|---------------------|
| 1 | `ownerId` | `@PathVariable("ownerId") int` | Business identifier of the owner whose pet collection is being accessed. It scopes pet creation or lookup to a specific owner aggregate and is required whenever an existing pet is being loaded. |
| 2 | `petId` | `@PathVariable(name = "petId", required = false) Integer` | Optional business identifier of the pet being edited. If present, the method loads an existing pet from the owner; if absent, the method creates a new blank pet for the add-pet workflow. |

Instance fields and external state read by the method:
- `this.owners` — the `OwnerRepository` used to load the owning customer record.

## 4. CRUD Operations / Called Services

### Pre-computed evidence from code analysis graph:

| CRUD | SC / CBS | SC Code | Entity / DB | Operation Description |
|------|----------|---------|-------------|----------------------|
| R | `OwnerRepository.findById` | OwnerRepository | Owner | Calls `findById` in `OwnerRepository` |

Analyze all method calls within this method and classify each as a CRUD operation.

| CRUD | SC / CBS | SC Code | Entity / DB | Operation Description |
|------|----------|---------|-------------|----------------------|
| C | `new Pet()` | N/A | Pet | Creates a new in-memory pet instance for the add-pet flow when no `petId` is provided. |
| R | `OwnerRepository.findById` | OwnerRepository | Owner | Reads the owner aggregate by owner identifier to validate context before loading an existing pet. |
| R | `owner.getPet(petId)` | Owner | Pet | Retrieves the target pet from the loaded owner aggregate for editing or display. |

## 5. Dependency Trace

Trace who calls this method and what this method ultimately calls.

| # | Caller (Screen/Batch) | Call Chain (Full Path to this Method) | Terminal (SC / CRUD / Entity) |
|---|----------------------|--------------------------------------|-------------------------------|
| 1 | Controller: `PetController` | `PetController.addNewPet` -> `PetController.findPet` | `new Pet() [C] Pet` |
| 2 | Controller: `PetController` | `PetController.processCreationForm` -> `PetController.findPet` | `new Pet() [C] Pet` |
| 3 | Controller: `PetController` | `PetController.initNewPetForm` -> `PetController.findPet` | `OwnerRepository.findById [R] Owner` |
| 4 | Controller: `PetController` | `PetController.processUpdatePetForm` -> `PetController.findPet` | `owner.getPet(petId) [R] Pet` |
| 5 | Controller: `VisitController` | `VisitController.addNewVisitForm` -> `PetController.findPet` | `OwnerRepository.findById [R] Owner` |
| 6 | Controller: `OwnerController` | `OwnerController.showOwner` -> `PetController.findPet` | `OwnerRepository.findById [R] Owner` |

## 6. Per-Branch Detail Blocks

**Block 1** — IF `(petId == null)` (L77)

> Handles the add-pet entry path by creating a fresh domain object with no persisted identity.

| # | Type | Code |
|---|------|------|
| 1 | RETURN | `return new Pet();` |

**Block 2** — ELSE `(petId != null)` (L81)

> Handles the edit/view path by resolving the owner first and then locating the requested pet within that owner.

| # | Type | Code |
|---|------|------|
| 1 | EXEC | `Optional<Owner> optionalOwner = this.owners.findById(ownerId);` |
| 2 | EXEC | `Owner owner = optionalOwner.orElseThrow(() -> new IllegalArgumentException("Owner not found with id: " + ownerId + ". Please ensure the ID is correct "));` |
| 3 | CALL | `owner.getPet(petId);` |
| 4 | RETURN | `return owner.getPet(petId);` |

**Block 2.1** — IF `(optionalOwner is empty)` (L82)

> Prevents pet resolution when the parent owner cannot be found, preserving aggregate integrity.

| # | Type | Code |
|---|------|------|
| 1 | THROW | `throw new IllegalArgumentException("Owner not found with id: " + ownerId + ". Please ensure the ID is correct ");` |

## 7. Glossary

| Term | Type | Business Meaning |
|------|------|-------------------|
| `ownerId` | Field | Identifier of the pet owner whose record scopes the request. |
| `petId` | Field | Identifier of the pet to retrieve for editing or display. |
| `Owner` | Domain entity | Customer who owns one or more pets in the PetClinic domain. |
| `Pet` | Domain entity | Animal record belonging to an owner; this is the object bound to the UI form. |
| `OwnerRepository` | Repository | Persistence access point for owner records. |
| `Optional` | Technical type | Wrapper used to represent that the owner may or may not exist in the database. |
| `IllegalArgumentException` | Exception | Failure raised when the owner identifier does not resolve to an existing owner. |
| Model attribute | MVC concept | Object placed into the view model so Thymeleaf forms can render and bind pet data. |
| Aggregate | Domain term | Group of related objects managed together through the owner root object. |
| Add-pet flow | Business term | Screen flow for creating a new pet for an existing owner. |
| Edit-pet flow | Business term | Screen flow for loading an existing pet so its details can be updated. |
---
