Overview

6 Ensuring integrity of state

Many systems exist to change the world’s state, so handling mutability safely is central to secure design. This chapter promotes modeling change as Domain-Driven Design entities—objects with identity whose state evolves under clear, enforced rules. Scattering state across cookies, direct SQL, and ad hoc application code creates “logical cracks” where security failures appear. By concentrating allowed states and transitions inside entities, the model stays comprehensible, constraints become explicit, and security boundaries are easier to defend.

Security begins at creation: entities must be consistent the moment they come into existence. The chapter warns against no-argument constructors and setter-based initialization, which routinely yield partially formed, rule-violating objects and brittle code. With ORMs, prefer private no-arg constructors and field access to avoid exposing unsafe creation paths, or separate persistence and domain models entirely. For construction, start with constructors that require all mandatory attributes and validate inputs; use fluent interfaces for readability when adding optional attributes; and enforce cross-attribute invariants with explicit checks. For advanced constraints and multistep assembly, employ the builder pattern to hide half-built objects and release them only after passing invariant checks; when mapping via ORM, run invariant validation after loading data.

After creation, preserve integrity by preventing external mutation. Replace broad getters/setters with behavior-oriented methods that encode the allowed transitions (for example, markPaid rather than setPaid). Prefer immutable domain primitives for attributes, parameters, and return values; where mutability is unavoidable, use defensive copies to avoid leaking internal state. Collections need special care: keep list/set operations inside the entity, expose read-only copies or unmodifiable views, and make contained items immutable to prevent indirect tampering. Applied together, these practices keep entities consistent, encapsulate business rules at the source of truth, and close the security gaps that arise when mutable state leaks beyond the model’s control.

Figure 6.1. Some different ways to implement state
ch06 ways to implement state small
Figure 6.2. We don’t want half-finished cars to be visible to the outside.
ch06 mandatory arg constructor small
Figure 6.3. Safeguarding a bank account by either a credit limit or a fallback account
ch06 bank accounts small
Figure 6.4. Hiding a half-finished car until it’s finished
ch06 builder pattern car small

 Summary

  • Entities are the preferred way to handle mutable states.
  • Entities must be consistent on creation.
  • No-arg constructors are dangerous.
  • The builder pattern can be used to construct entities with complex constraints.
  • You need to protect the integrity of attributes when those are accessed.
  • A private data field with unrestricted getter and setter methods isn’t more secure than a public data field.
  • You should avoid sharing mutable objects and use immutable domain primitives instead.
  • You shouldn’t expose a collection, but rather expose a useful property of the collection.
  • Collections can be protected by exposing an unmodifiable version.
  • You must take care so that the data in a collection can’t be changed from the outside.

FAQ

Why model mutable state as entities in the DDD style?Entities centralize both state and the rules for changing it. That makes allowed states and transitions explicit, reduces the chance of security gaps caused by scattered logic (cookies, direct SQL, random services), and keeps business invariants close to the data they govern.
What’s wrong with no-arg constructors and setter-based initialization?No-arg constructors allow half-baked objects to escape, and setter sequences are easy to forget or apply inconsistently. This leads to entities created in invalid states, subtle bugs, and security loopholes that compilers and basic tests won’t catch.
How can I use JPA/Hibernate without weakening entity integrity?You have two safe options: (1) Separate domain and persistence models, mapping DB rows to persistence classes and then constructing domain entities safely; or (2) keep a private no-arg constructor and use field access (not setters) so the ORM can hydrate objects without exposing inconsistent instances to callers.
When should I use constructors, fluent interfaces, or the builder pattern?- Mandatory-attribute constructor: for simple cases where only required fields must be set at creation.
- Fluent interface: for readability while adding optional attributes, provided each step leaves the object consistent.
- Builder pattern: for complex, multi-step construction and cross-field constraints that must hold before exposure.
What are invariants and how do I enforce them?Invariants are rules that must hold for an entity whenever it is observable from the outside (for example, “either a credit limit or a fallback account, but not both”). Capture them in a checkInvariants method and call it at the end of public state-changing methods; if using an ORM, also run it on load (for example, with @PostLoad).
Are fluent interfaces safe, and do they conflict with CQS?Fluent interfaces can be safe if each chained step keeps the object valid, but they don’t enforce cross-property constraints on their own. They often return the modified instance, which some see as a mild Command-Query Separation violation; weigh readability benefits against that trade-off.
How does the builder pattern uphold advanced constraints?The builder hides the half-built object and only returns it via build() after validating all invariants. Use a private constructor and a builder (often an inner static class) to assemble state across steps, validate, and then “release” a consistent entity; make the builder short-lived and one-shot.
What’s the secure alternative to unrestricted getters and setters?Encapsulate behavior, not raw data. Replace arbitrary setters like setPaid(boolean) with intention-revealing, rule-enforcing methods such as markPaid(), and expose readers that don’t invite external mutation.
Why avoid sharing mutable objects, and what are safe practices?Exposing references to mutables lets callers change your state behind your back. Prefer immutable domain primitives; if you must use mutables, return defensive copies (for example, clones or copy-constructors) and avoid legacy mutables like java.util.Date in favor of java.time types.
How do I protect the integrity of collections in entities?Don’t expose modifiable collections or provide collection setters. Encapsulate operations (add/remove, totals) inside the entity; if you must expose a view, return an unmodifiable wrapper or a copy, and make the collection’s items immutable to prevent indirect tampering.

pro $24.99 per month

  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose one free eBook per month to keep
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime

lite $19.99 per month

  • access to all Manning books, including MEAPs!

team

5, 10 or 20 seats+ for your team - learn more


choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • Secure by Design ebook for free
choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • Secure by Design ebook for free
choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • Secure by Design ebook for free