---
# (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 is the controller-side lookup and fallback entry point used to resolve a `Pet` object for owner-related web interactions. Its primary business responsibility is to support the owner/pet maintenance flow by either returning a brand-new `Pet` instance when no pet identifier has been supplied, or loading the existing pet that belongs to the specified owner when a pet identifier is present. In effect, it acts as a routing method that decides whether the request is creating a new pet record or editing an existing one.

The method implements a simple dispatch pattern based on the presence of `petId`. One branch handles the create-flow placeholder by producing an empty domain object, while the other branch performs owner validation and delegates to the owner aggregate to retrieve the pet. This method sits at the boundary of the web layer and protects downstream logic from having to handle a missing pet identifier directly.

In the larger system, this method supports the owner management UI by preparing the correct domain object for the form lifecycle. It does not persist data itself, but it determines whether the rest of the request will proceed with a new pet shell or with an existing pet loaded from the owner context. The method also enforces a business rule that an owner must exist before an existing pet can be resolved.

## 2. Processing Pattern (Detailed Business Logic)

```mermaid
flowchart TD
    START(["findPet(ownerId, petId)"])
    CHECK_PET_ID{"petId == null?"}
    NEW_PET["Create new Pet()"]
    FIND_OWNER["Call owners.findById(ownerId)"]
    OR_ELSE_THROW["Call optionalOwner.orElseThrow(...) and validate owner exists"]
    GET_PET["Call owner.getPet(petId)"]
    RETURN_NEW["Return new Pet"]
    RETURN_EXISTING["Return existing Pet"]
    END_NODE(["End"])

    START --> CHECK_PET_ID
    CHECK_PET_ID -->|Yes| NEW_PET
    NEW_PET --> RETURN_NEW
    RETURN_NEW --> END_NODE
    CHECK_PET_ID -->|No| FIND_OWNER
    FIND_OWNER --> OR_ELSE_THROW
    OR_ELSE_THROW --> GET_PET
    GET_PET --> RETURN_EXISTING
    RETURN_EXISTING --> END_NODE
```

## 3. Parameter Analysis

| No | Parameter Name | Type | Business Description |
|----|---------------|------|---------------------|
| 1 | `ownerId` | `@PathVariable("ownerId") int` | The owner identifier from the request path. It identifies which owner record must be used when resolving an existing pet, and it is required for the existing-pet branch. If the owner does not exist, the method raises an error instead of returning a pet. |
| 2 | `petId` | `@PathVariable(name = "petId", required = false) Integer` | The optional pet identifier from the request path. When absent, the method assumes the user is starting a new pet registration flow and returns an empty `Pet`. When present, it instructs the method to load the corresponding pet from the owner aggregate. |

Instance fields and external state read by the method:
- `this.owners` — the injected repository used to locate the owner record.
- `ownerId` path state — used to validate the owner and build the error message.
- `petId` path state — determines whether the method creates a new pet or loads an existing one.

## 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 |
|------|----------|---------|-------------|----------------------|
| R | `OwnerRepository.findById` | OwnerRepository | Owner | Looks up the owner by identifier before resolving an existing pet. |
| R | `Optional.orElseThrow` | Java Optional | N/A | Validates that the owner lookup succeeded and throws an exception if no owner is present. |
| R | `Owner.getPet` | Owner aggregate | Pet | Retrieves the pet associated with the owner for the supplied pet identifier. |
| C | `new Pet()` | Pet entity | Pet | Creates a blank pet instance for the new-pet form flow when no pet identifier is provided. |

## 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 | `PetController` | `PetController` -> `PetController.findPet` | `new Pet() [C] Pet` |
| 2 | `PetController` | `PetController` -> `PetController.findPet` | `OwnerRepository.findById [R] Owner` |
| 3 | `PetController` | `PetController` -> `PetController.findPet` | `Optional.orElseThrow [R] N/A` |
| 4 | `PetController` | `PetController` -> `PetController.findPet` | `Owner.getPet [R] Pet` |

## 6. Per-Branch Detail Blocks

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

> Handles the new-pet preparation path when the request does not contain a pet identifier.

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

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

> Handles the existing-pet lookup path for editing or viewing a pet that belongs to an owner.

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

**Block 2.1** — [CALLBACK / LAMBDA] `(owner missing)` (L82)

> Raises a business validation error when the owner cannot be located.

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

## 7. Glossary

| Term | Type | Business Meaning |
|------|------|------------------|
| `ownerId` | Field | Owner identifier used to locate the customer record that owns the pet. |
| `petId` | Field | Optional pet identifier used to distinguish new-pet entry from existing-pet editing. |
| `Pet` | Domain object | Business entity representing an animal registered in the clinic system. |
| `Owner` | Domain object | Customer or pet owner record that holds one or more pets. |
| `Optional` | Technical term | Wrapper that indicates whether the owner lookup returned a value. |
| `orElseThrow` | Technical term | Optional control method that converts a missing owner into an exception. |
| `IllegalArgumentException` | Technical term | Runtime exception used here to indicate that the supplied owner identifier is invalid. |
| Controller | Layer | Web layer component that receives request parameters and prepares domain objects for the UI. |
| `owner` | Module | Package area for owner and pet management functions. |
| Repository | Technical term | Persistence abstraction used to retrieve domain records from storage. |
