… never had (#25595)
Fixes #25559
**behavior deviation** · dev loop · Spring applications using
`vaadin-dev`
**Background — component scanning.** Spring builds its bean definitions
once, while the context starts, from the classes that exist at that
moment, and JPA fixes its metamodel and its schema at startup in the
same
way. A class compiled later is loaded by the JVM but never scanned.
Adding a new Spring bean or a new JPA entity and running `apply`
reported
a successful hot reload, and the application then failed with a Spring
error instead of asking for a restart. A class that did not exist at
startup gets no bean definition and no entity mapping, so a hot reload
can never make it live. `apply` now restarts for such a class.
**Risks:**
- ⚠️ Behavior change: `apply` restarts, instead of reporting a hot
reload, when the change set adds a class the running application never
had that carries a Spring stereotype or a JPA mapping annotation. A
bean or an entity the application started with still hot swaps.
- ✅ No public or protected API change, nothing to migrate, and no
security, memory, serialization, threading or performance impact.
- Escalated `apply` to a restart, with the reason `new Spring bean (X)`,
for a class carrying `@Component`, `@Service`, `@Repository`,
`@Controller`, `@RestController`, `@ControllerAdvice`,
`@RestControllerAdvice` or `@Configuration` that the running
application never had. A brand-new `@Entity` escalates too, because the
new bytes of a class this JVM never loaded are now inspected.
- Read the stereotype off the compiled bytes and reported it in a new
`stereotypes=` field, appended last so an older daemon finds every
existing field of the `REDEFINE` reply where it was.
- Answered whether the application ever had a class from a snapshot of
the classpath taken at each application start, per class and by binary
name. What the JVM has loaded cannot answer it: HotswapAgent defines a
new class as soon as it sees the class file, and its Spring plugin,
which would rescan, is turned off for stability.
- Split `DevLoopRedefiner.redefine` into `inspect` and `reply`, so the
decision is testable without a running application.
- Documented the escalation and its known gap — a stereotype composed
through a project's own meta-annotation — in the daemon `README.md`,
and covered the behavior in `DevLoopRestartIT`, `DevLoopApplyIT` and
unit tests on both sides of the protocol.
---------
Co-authored-by: totally-not-ai[bot] <290682512+totally-not-ai[bot]@users.noreply.github.com>
Co-authored-by: Tomi Virtanen <tltv@vaadin.com>
This PR cherry-picks changes from the original PR #25595 to branch 25.3.
Original PR description