# Org / Springframework / Samples / Petclinic / Model

## Overview

The `org.springframework.samples.petclinic.model` package defines the shared domain model base types used by the Petclinic application. It appears to exist as a small set of mapped superclasses that standardize identifier handling, naming, and person name fields across the domain layer. The package also includes a focused validation test that confirms Bean Validation is wired correctly for these model constraints.

This package is intentionally small, but it plays an important structural role: it provides reusable JPA and validation metadata that other domain objects can inherit instead of repeating the same mapping and constraint declarations.

## Key Classes and Interfaces

### `BaseEntity`

[BaseEntity](src/main/java/org/springframework/samples/petclinic/model/BaseEntity.java:32) is the shared persistence base class for domain objects that need a database identifier. It is marked with `@MappedSuperclass`, which means JPA uses its mapping metadata in subclasses without treating it as a standalone table-backed entity.

#### Purpose

`BaseEntity` centralizes the common `id` field and the logic for deciding whether an object is new. That keeps entity classes consistent and avoids duplicating identifier boilerplate.

#### Key methods

- [BaseEntity.getId()](src/main/java/org/springframework/samples/petclinic/model/BaseEntity.java:39) returns the entity identifier as an `Integer`.
- [BaseEntity.setId(Integer id)](src/main/java/org/springframework/samples/petclinic/model/BaseEntity.java:43) assigns the identifier value. In practice this is typically managed by JPA after persistence.
- [BaseEntity.isNew()](src/main/java/org/springframework/samples/petclinic/model/BaseEntity.java:47) returns `true` when `id` is `null`, which is the package’s simple rule for distinguishing transient objects from persisted ones.

#### Design notes

The class uses `@Id` and `@GeneratedValue(strategy = GenerationType.IDENTITY)`, so subclasses inherit identity generation behavior. Because `isNew()` is purely based on a null `id`, any code that creates new domain objects can rely on this method before persistence has happened.

### `NamedEntity`

[NamedEntity](src/main/java/org/springframework/samples/petclinic/model/NamedEntity.java:30) extends [BaseEntity](src/main/java/org/springframework/samples/petclinic/model/BaseEntity.java:32) and adds a reusable `name` property. It is also a `@MappedSuperclass`, so subclasses inherit both the identifier mapping and the name mapping.

#### Purpose

This class captures the common shape of domain objects that are identified by an internal id but also display a human-readable name. That pattern is useful for lookup-like reference data or catalog-style entities.

#### Key methods

- [NamedEntity.getName()](src/main/java/org/springframework/samples/petclinic/model/NamedEntity.java:37) returns the current name.
- [NamedEntity.setName(String name)](src/main/java/org/springframework/samples/petclinic/model/NamedEntity.java:41) updates the name value.
- [NamedEntity.toString()](src/main/java/org/springframework/samples/petclinic/model/NamedEntity.java:45) returns the current name when present, otherwise it returns `"<null>"`.

#### Design notes

The `name` field is annotated with both `@Column` and `@NotBlank`, so the model layer expresses both persistence mapping and validation constraints. The overridden `toString()` is intentionally minimal and defensive; it avoids returning `null`, which makes logging and debugging safer.

### `Person`

[Person](src/main/java/org/springframework/samples/petclinic/model/Person.java:27) extends [BaseEntity](src/main/java/org/springframework/samples/petclinic/model/BaseEntity.java:32) and represents a person-shaped domain object with separate first and last name fields. Like the other types in this package, it is a `@MappedSuperclass`.

#### Purpose

`Person` is the shared base for domain objects that need first and last name data, such as application actors or owners in the wider Petclinic domain. This class exists to keep that name structure consistent wherever it is needed.

#### Key methods

- [Person.getFirstName()](src/main/java/org/springframework/samples/petclinic/model/Person.java:38) returns the first name.
- [Person.setFirstName(String firstName)](src/main/java/org/springframework/samples/petclinic/model/Person.java:42) updates the first name.
- [Person.getLastName()](src/main/java/org/springframework/samples/petclinic/model/Person.java:46) returns the last name.
- [Person.setLastName(String lastName)](src/main/java/org/springframework/samples/petclinic/model/Person.java:50) updates the last name.

#### Design notes

Both name fields are mapped with `@Column` and constrained with `@NotBlank`. That means validation failures will occur before persistence if either field is empty or whitespace-only.

### `ValidatorTests`

[ValidatorTests](src/test/java/org/springframework/samples/petclinic/model/ValidatorTests.java:35) is a focused JUnit test class that verifies Bean Validation works against the model constraints in this package.

#### Purpose

The test protects the package’s validation assumptions. It appears to be a regression test meant to catch configuration or dependency changes in Hibernate Validator / Bean Validation integration.

#### Key methods

- [ValidatorTests.createValidator()](src/test/java/org/springframework/samples/petclinic/model/ValidatorTests.java:37) builds a `Validator` by creating a `LocalValidatorFactoryBean` and calling `afterPropertiesSet()`.
- [ValidatorTests.shouldNotValidateWhenFirstNameEmpty()](src/test/java/org/springframework/samples/petclinic/model/ValidatorTests.java:43) creates a `Person`, sets `firstName` to an empty string, validates it, and asserts that exactly one violation is produced for `firstName` with the message `"must not be blank"`.

## How It Works

The package uses a simple inheritance model to share JPA identity and validation behavior:

1. `BaseEntity` defines the common persistence identifier and a basic `isNew()` check.
2. `NamedEntity` and `Person` extend `BaseEntity` to inherit the identifier mapping.
3. `NamedEntity` adds a single validated `name` property.
4. `Person` adds validated `firstName` and `lastName` properties.
5. `ValidatorTests` instantiates a real validator and confirms that blank values are rejected with the expected message.

A typical flow for validation looks like this:

- A model object is created in memory.
- Its string fields are populated, or left blank in the test case.
- Bean Validation inspects annotations such as `@NotBlank`.
- Violations are returned with the field path and localized message.
- The test asserts that the violation lands on the expected property.

### Relationship diagram

```mermaid
classDiagram
class BaseEntity
class NamedEntity
class Person
class ValidatorTests
BaseEntity <|-- NamedEntity
BaseEntity <|-- Person
ValidatorTests --> Person
ValidatorTests --> BaseEntity
```

## Data Model

The package contains a small set of reusable domain model shapes rather than a fully independent aggregate.

- `BaseEntity`
  - `id : Integer`
  - persistence identity shared by subclasses
- `NamedEntity`
  - inherits `id`
  - `name : String`
  - non-blank display name
- `Person`
  - inherits `id`
  - `firstName : String`
  - `lastName : String`
  - both name parts are required

Because all three classes are mapped superclasses, they are designed to be embedded into other concrete entities rather than persisted directly on their own.

## Dependencies and Integration

This package integrates with a few core frameworks:

- **JPA / Jakarta Persistence** through `@MappedSuperclass`, `@Id`, `@GeneratedValue`, and `@Column`
- **Jakarta Validation** through `@NotBlank`
- **Spring validation support** in the test via `LocalValidatorFactoryBean`
- **JUnit 5** and **AssertJ** for validation testing
- **LocaleContextHolder** to set the active locale for message resolution during the test

No package dependencies were resolved in the index, so the documentation above is limited to what is visible directly in the source files.

## Notes for Developers

- `isNew()` is a null-check on `id`, so any code that manually assigns identifiers should be aware that it changes the new/existing object classification.
- `NamedEntity.toString()` returns `"<null>"` instead of `null`, which is useful for logging but may hide missing data if overused in UI code.
- `@NotBlank` on the fields means blank strings are invalid, not just `null` values.
- The validation test is intentionally small; if you add new constraints here, consider adding matching regression tests so configuration changes do not silently break validation behavior.
- Since these are mapped superclasses, they are best treated as reusable building blocks for concrete entities elsewhere in the application.
