Standard jakarta.validation annotations, compiled once per type into a flat
check table. No configuration: constraints come from the annotations already on
your types, and ValidationException extends HttpException with status 422 so
the default handler renders it without this extension registering anything.
record CreateUser(@NotBlank @Size(max = 80) String name,
@Email String email,
@Min(18) int age) {}
CreateUser dto = validation.body(req, CreateUser.class);
Annotations only — Hibernate Validator's engine is deliberately absent. It
resolves constraints reflectively per call and pulls ~2 MB plus EL, which is
the per-request cost this module exists to avoid. jakarta.validation-api is
~90 KB of annotations.
The passing path allocates nothing. Constraints resolve at first use into an
opcode plus operands cached in a ClassValue, so there is no map lookup and no
lock. Fields are read through MethodHandles adapted to an exact signature —
(Object)Object for references, (Object)long for primitive integrals — so
invokeExact neither boxes nor builds the argument array Field.get and
Method.invoke allocate. Checks are a flat array walked by a tableswitch rather
than a class hierarchy behind a virtual call. @Size reads a length the object
already knows and @Email scans with indexOf, because Pattern.matcher allocates
a matcher and two int arrays per call. Messages are pre-rendered at compile
time. The violation list and the exception exist only once something fails.
@Pattern is the marked exception: its regex compiles once but matcher()
allocates per call.
Constraints are read from declared fields, so records and plain classes take
one code path — a constraint on a record component propagates to its backing
field.
Jakarta null semantics are exact: only @NotNull rejects null.
flash-ext-openapi now mirrors the same annotations into the generated schema —
minLength, maxLength, minItems, minimum, maximum, pattern, format: email and
required — via an optional jakarta.validation dependency detected at boot. A
type declares its rules once and both the validator and the published contract
read them. An explicit @Schema still wins; the bridge only fills keys nobody
set, and without the annotations on the classpath the bridge class is never
loaded.
flash-ext-jackson is optional too: validate(value) works without it, only
body(req, type) needs a codec.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
151 lines
6.0 KiB
XML
151 lines
6.0 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
<modelVersion>4.0.0</modelVersion>
|
|
|
|
<parent>
|
|
<groupId>dev.relism</groupId>
|
|
<artifactId>flash-parent</artifactId>
|
|
<version>2.1.0-SNAPSHOT</version>
|
|
</parent>
|
|
|
|
<artifactId>flash-extensions</artifactId>
|
|
<packaging>pom</packaging>
|
|
|
|
<modules>
|
|
<module>flash-ext-jackson</module>
|
|
<module>flash-ext-openapi</module>
|
|
<module>flash-ext-oidc</module>
|
|
<module>flash-ext-routeviewer</module>
|
|
<module>flash-ext-view-core</module>
|
|
<module>flash-ext-view-jte</module>
|
|
<module>flash-ext-view-thymeleaf</module>
|
|
<module>flash-ext-limiter</module>
|
|
<module>flash-ext-web-bundler</module>
|
|
<module>flash-ext-mcp</module>
|
|
<module>flash-ext-validation</module>
|
|
<module>flash-ext-data-core</module>
|
|
<module>flash-ext-data-jdbc</module>
|
|
<module>flash-ext-data-hibernate</module>
|
|
</modules>
|
|
|
|
<dependencyManagement>
|
|
<dependencies>
|
|
<dependency>
|
|
<groupId>dev.relism</groupId>
|
|
<artifactId>flash-ext-validation</artifactId>
|
|
<version>${project.version}</version>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>dev.relism</groupId>
|
|
<artifactId>flash-testing</artifactId>
|
|
<version>${project.version}</version>
|
|
<scope>test</scope>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>dev.relism</groupId>
|
|
<artifactId>flash-ext-jackson</artifactId>
|
|
<version>${project.version}</version>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>dev.relism</groupId>
|
|
<artifactId>flash-ext-view-jte</artifactId>
|
|
<version>${project.version}</version>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>com.fasterxml.jackson.core</groupId>
|
|
<artifactId>jackson-databind</artifactId>
|
|
<version>2.17.2</version>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
|
<artifactId>jackson-dataformat-yaml</artifactId>
|
|
<version>2.17.2</version>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>com.fasterxml.jackson.datatype</groupId>
|
|
<artifactId>jackson-datatype-jsr310</artifactId>
|
|
<version>2.17.2</version>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>com.nimbusds</groupId>
|
|
<artifactId>nimbus-jose-jwt</artifactId>
|
|
<version>9.37.3</version>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>net.minidev</groupId>
|
|
<artifactId>json-smart</artifactId>
|
|
<version>2.5.1</version>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>dev.relism</groupId>
|
|
<artifactId>flash-ext-web-bundler</artifactId>
|
|
<version>${project.version}</version>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>dev.relism</groupId>
|
|
<artifactId>flash-ext-data-core</artifactId>
|
|
<version>${project.version}</version>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>dev.relism</groupId>
|
|
<artifactId>flash-ext-data-jdbc</artifactId>
|
|
<version>${project.version}</version>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>dev.relism</groupId>
|
|
<artifactId>flash-ext-data-hibernate</artifactId>
|
|
<version>${project.version}</version>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>com.zaxxer</groupId>
|
|
<artifactId>HikariCP</artifactId>
|
|
<version>6.3.0</version>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>org.hibernate.orm</groupId>
|
|
<artifactId>hibernate-core</artifactId>
|
|
<version>6.6.35.Final</version>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>org.testcontainers</groupId>
|
|
<artifactId>postgresql</artifactId>
|
|
<version>1.21.3</version>
|
|
<scope>test</scope>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>com.h2database</groupId>
|
|
<artifactId>h2</artifactId>
|
|
<version>2.2.224</version>
|
|
<scope>test</scope>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>jakarta.transaction</groupId>
|
|
<artifactId>jakarta.transaction-api</artifactId>
|
|
<version>2.0.1</version>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>jakarta.annotation</groupId>
|
|
<artifactId>jakarta.annotation-api</artifactId>
|
|
<version>3.0.0</version>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>jakarta.validation</groupId>
|
|
<artifactId>jakarta.validation-api</artifactId>
|
|
<version>3.1.1</version>
|
|
</dependency>
|
|
</dependencies>
|
|
</dependencyManagement>
|
|
|
|
<!--
|
|
No maven-deploy-plugin skip here (there used to be one): flash-extensions is a
|
|
pom-packaging aggregator with no jar of its own, but every flash-ext-* submodule's
|
|
effective POM inherits from it via <parent> — skipping its deploy meant remote consumers
|
|
(anything resolving a flash-ext-* artifact from Gitea's Maven registry rather than a
|
|
local ~/.m2 install) couldn't resolve that parent POM at all. See
|
|
pathway/.gitea/workflows/docker-build.yml and pathway/docs/CI-CD.md.
|
|
-->
|
|
|
|
</project>
|