feat(core): Aggregate all JPA entity/schema mismatches in one audit run#7
feat(core): Aggregate all JPA entity/schema mismatches in one audit run#7jeffjensen wants to merge 1 commit into
Conversation
|
Warning Review limit reached
Next review available in: 30 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (8)
📝 WalkthroughWalkthroughThis PR adds a Hibernate ChangesSchema mapping audit
Sequence Diagram(s)sequenceDiagram
participant Caller
participant SchemaEntityValidationAudit
participant MappingMetadataIntegrator
participant Hibernate
participant Database
Hibernate->>MappingMetadataIntegrator: integrate(metadata, sessionFactory)
MappingMetadataIntegrator->>MappingMetadataIntegrator: store metadata by factory UUID
Caller->>SchemaEntityValidationAudit: forEntityManagerFactory(emf, dataSource)
SchemaEntityValidationAudit->>MappingMetadataIntegrator: metadataFor(emf)
MappingMetadataIntegrator-->>SchemaEntityValidationAudit: captured Metadata
Caller->>SchemaEntityValidationAudit: audit(excludedRelations)
SchemaEntityValidationAudit->>Database: readColumns via DatabaseMetaData
Database-->>SchemaEntityValidationAudit: column metadata
SchemaEntityValidationAudit->>SchemaEntityValidationAudit: compare mapped tables/columns/types
SchemaEntityValidationAudit-->>Caller: list of violations
Hibernate->>MappingMetadataIntegrator: disintegrate(sessionFactory)
MappingMetadataIntegrator->>MappingMetadataIntegrator: remove entry by UUID
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
PR Summary by QodoAggregate JPA entity/schema validation mismatches in one audit run
AI Description
Diagram
High-Level Assessment
Files changed (5)
|
Code Review by Qodo
Context used✅ Compliance rules (platform):
22 rules 1. SchemaEntityValidationAudit missing exclusion set
|
| public class SchemaEntityValidationAudit { | ||
| private final EntityManagerFactory entityManagerFactory; | ||
| private final Supplier<Metadata> metadataSupplier; | ||
| private final DataSource dataSource; | ||
|
|
||
| /** | ||
| * Constructs the audit around the boot mapping model and the datasource whose | ||
| * live schema it is checked against. | ||
| * | ||
| * @param metadataSupplier | ||
| * supplies the boot {@link Metadata} for the | ||
| * persistence unit, resolved when {@link #audit()} | ||
| * runs; see | ||
| * {@link #forEntityManagerFactory(EntityManagerFactory, DataSource)}. | ||
| * @param dataSource | ||
| * the datasource whose schema the mappings are | ||
| * validated against. | ||
| */ | ||
| public SchemaEntityValidationAudit(final Supplier<Metadata> metadataSupplier, | ||
| final DataSource dataSource) { | ||
| this.metadataSupplier = metadataSupplier; | ||
| this.dataSource = dataSource; | ||
| } | ||
|
|
||
| /** | ||
| * Builds an audit for a JPA {@link EntityManagerFactory}, resolving its boot | ||
| * {@link Metadata} from {@link MappingMetadataIntegrator} when the audit runs. | ||
| * | ||
| * @param entityManagerFactory | ||
| * the factory whose mappings to validate. | ||
| * @param dataSource | ||
| * the datasource whose schema to validate | ||
| * against. | ||
| * @return the audit. | ||
| */ | ||
| public static SchemaEntityValidationAudit forEntityManagerFactory( | ||
| final EntityManagerFactory entityManagerFactory, | ||
| final DataSource dataSource) { | ||
| return new SchemaEntityValidationAudit( | ||
| () -> MappingMetadataIntegrator | ||
| .metadataFor(entityManagerFactory), | ||
| dataSource); | ||
| } | ||
|
|
||
| /** | ||
| * Returns a single violation when the {@link EntityManagerFactory} was not | ||
| * built (so startup validation never ran); an empty list when it was — | ||
| * which, under {@code ddl-auto=validate}, means the mappings matched the | ||
| * schema. | ||
| * Validates every mapped physical table against the live schema. | ||
| * | ||
| * @return A single violation when the {@link EntityManagerFactory} is | ||
| * {@code null}; otherwise an empty list. | ||
| * @return one violation per missing table, missing column, and incompatible | ||
| * column type; an empty list when the mappings match the schema. | ||
| * @throws IllegalStateException | ||
| * if the boot mapping model was never | ||
| * captured (so the audit cannot run), or the | ||
| * database metadata cannot be read. | ||
| */ | ||
| public List<String> audit() { | ||
| if (entityManagerFactory == null) { | ||
| return List.of( | ||
| "EntityManagerFactory should have been built under ddl-auto=validate."); | ||
| final Metadata metadata = metadataSupplier.get(); | ||
| if (metadata == null) { | ||
| throw new IllegalStateException( | ||
| "JPA mapping metadata was not captured for this EntityManagerFactory; ensure " | ||
| + "database-audits-core is on the test classpath (it registers a Hibernate " | ||
| + "Integrator that records the boot metadata) and that the EntityManagerFactory " | ||
| + "has been built."); | ||
| } | ||
| final Database database = metadata.getDatabase(); | ||
| final Dialect dialect = database.getDialect(); | ||
| final JdbcTypeRegistry jdbcTypeRegistry = | ||
| database.getTypeConfiguration().getJdbcTypeRegistry(); | ||
|
|
||
| final List<String> violations = new ArrayList<>(); | ||
| try (Connection connection = dataSource.getConnection()) { | ||
| final DatabaseMetaData databaseMetaData = connection.getMetaData(); | ||
| final String catalog = connection.getCatalog(); | ||
| final String defaultSchema = connection.getSchema(); | ||
| final Map<String, Map<String, Map<String, DatabaseColumn>>> columnsBySchema = | ||
| new HashMap<>(); | ||
|
|
||
| for (final Table table : metadata.collectTableMappings()) { | ||
| if (!table.isPhysicalTable()) { | ||
| continue; | ||
| } | ||
| final String schema = | ||
| table.getSchema() != null ? table.getSchema() | ||
| : defaultSchema; | ||
| final Map<String, DatabaseColumn> databaseColumns = | ||
| columnsBySchema | ||
| .computeIfAbsent(schema, | ||
| s -> readColumns(databaseMetaData, | ||
| catalog, s)) | ||
| .get(canonical(table.getName())); | ||
| if (databaseColumns == null) { | ||
| violations.add("missing table [" | ||
| + qualifiedName(schema, table.getName()) + "]"); | ||
| continue; | ||
| } | ||
| for (final Column column : table.getColumns()) { | ||
| final DatabaseColumn databaseColumn = | ||
| databaseColumns.get(canonical(column.getName())); | ||
| if (databaseColumn == null) { | ||
| violations.add("missing column [" + column.getName() | ||
| + "] in table [" | ||
| + qualifiedName(schema, table.getName()) + "]"); | ||
| } else if (!hasMatchingType(column, databaseColumn, metadata, | ||
| dialect, jdbcTypeRegistry)) { | ||
| violations.add("wrong column type in column [" | ||
| + column.getName() + "] in table [" | ||
| + qualifiedName(schema, table.getName()) | ||
| + "]; found [" | ||
| + databaseColumn.typeName() | ||
| .toLowerCase(Locale.ROOT) | ||
| + "], but expecting [" | ||
| + column.getSqlType(metadata) | ||
| .toLowerCase(Locale.ROOT) | ||
| + "]"); | ||
| } | ||
| } | ||
| } | ||
| } catch (final SQLException e) { | ||
| throw new IllegalStateException( | ||
| "Failed to read database metadata for JPA entity/schema validation.", | ||
| e); | ||
| } | ||
| return violations; | ||
| } |
There was a problem hiding this comment.
1. schemaentityvalidationaudit missing exclusion set 📘 Rule violation ⚙ Maintainability
SchemaEntityValidationAudit always reports every detected mismatch and provides no configurable exclusion set to suppress known/accepted violations. This violates the audit-class requirement for externally configurable suppression and limits safe adoption in real systems.
Agent Prompt
## Issue description
`SchemaEntityValidationAudit` reports all detected table/column/type mismatches unconditionally, with no way to configure exclusions for known/acceptable drift. Compliance requires audit classes to support configurable exclusion sets and apply them before reporting.
## Issue Context
The audit currently only accepts `Supplier<Metadata>` and `DataSource` and then unconditionally adds strings to `violations` while iterating tables/columns.
## Fix Focus Areas
- src/main/java/io/github/databaseaudits/audit/jpa/SchemaEntityValidationAudit.java[51-172]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| /** | ||
| * Returns the boot {@link Metadata} captured for the given factory. | ||
| * | ||
| * @param entityManagerFactory | ||
| * the factory whose mapping model is wanted; | ||
| * may be a proxy over the native factory. | ||
| * @return the captured {@link Metadata}, or {@code null} if none was recorded | ||
| * — for instance when the factory was built without this module on | ||
| * its classpath, or after the factory has been closed. | ||
| */ | ||
| public static Metadata metadataFor( | ||
| final EntityManagerFactory entityManagerFactory) { | ||
| return METADATA_BY_UUID.get(entityManagerFactory | ||
| .unwrap(SessionFactoryImplementor.class).getUuid()); | ||
| } |
There was a problem hiding this comment.
2. metadatafor() missing @nullable 📘 Rule violation ≡ Correctness
MappingMetadataIntegrator.metadataFor(...) is documented to return null when no metadata was recorded, but the return type is not annotated with JSpecify @Nullable. This creates an incorrect nullability contract for callers and static analysis.
Agent Prompt
## Issue description
`MappingMetadataIntegrator.metadataFor(...)` can return `null` (per its Javadoc) but the method signature is not annotated with `@org.jspecify.annotations.Nullable`.
## Issue Context
The repository uses JSpecify, and this method explicitly documents `null` as a valid return value.
## Fix Focus Areas
- src/main/java/io/github/databaseaudits/audit/jpa/MappingMetadataIntegrator.java[75-89]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| private static String normalize(final String typeName) { | ||
| if (typeName == null) { | ||
| return null; | ||
| } | ||
| final String lowercase = typeName.toLowerCase(Locale.ROOT); | ||
| return switch (lowercase) { | ||
| case "int" -> "integer"; | ||
| case "character" -> "char"; | ||
| case "character varying" -> "varchar"; | ||
| case "binary varying" -> "varbinary"; | ||
| case "character large object" -> "clob"; | ||
| case "binary large object" -> "blob"; | ||
| case "interval second" -> "interval"; | ||
| case "double precision" -> "double"; | ||
| default -> lowercase; | ||
| }; | ||
| } | ||
|
|
||
| private static String stripArguments(final String typeExpression) { | ||
| if (typeExpression == null) { | ||
| return null; | ||
| } | ||
| final int parenthesis = typeExpression.indexOf('('); | ||
| return parenthesis > 0 ? typeExpression.substring(0, parenthesis).trim() | ||
| : typeExpression; | ||
| } | ||
|
|
||
| private static String qualifiedName(final String schema, final String name) { | ||
| return schema == null ? name : schema + "." + name; | ||
| } | ||
|
|
||
| private static String canonical(final String identifier) { | ||
| return identifier == null ? null : identifier.toLowerCase(Locale.ROOT); | ||
| } |
There was a problem hiding this comment.
3. Helper methods return null unannotated 📘 Rule violation ≡ Correctness
Several new helper methods explicitly accept/return null (via if (x == null) return null / ternary null returns) but do not annotate those parameters/returns with JSpecify @Nullable. This violates the project's nullability annotation requirement and weakens static checking.
Agent Prompt
## Issue description
New helpers in `SchemaEntityValidationAudit` (`normalize`, `stripArguments`, `canonical`) explicitly treat inputs/outputs as nullable but lack `@org.jspecify.annotations.Nullable` on those parameters/return types.
## Issue Context
The code contains explicit null checks and returns `null` in these methods, which is evidence that null is part of the contract.
## Fix Focus Areas
- src/main/java/io/github/databaseaudits/audit/jpa/SchemaEntityValidationAudit.java[224-257]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| void testAudit_MissingTable_ReportsMissingTable() throws SQLException { | ||
| assertThat(auditAgainst(CLEAN_PARENT)) | ||
| .as("Entity with no table should be reported as a missing table.") | ||
| .anySatisfy(violation -> assertThat(violation) | ||
| .contains("missing table").contains("child")); | ||
| } | ||
|
|
||
| @Test | ||
| void testAudit_MissingColumn_ReportsMissingColumn() throws SQLException { | ||
| assertThat(auditAgainst( | ||
| "CREATE TABLE parent (id BIGINT PRIMARY KEY, name VARCHAR(255))", | ||
| CLEAN_CHILD)) | ||
| .as("Mapped column absent from the table should be reported.") | ||
| .anySatisfy(violation -> assertThat(violation) | ||
| .contains("missing column").contains("quantity") | ||
| .contains("parent")); | ||
| } | ||
|
|
||
| @Test | ||
| void testAudit_WrongColumnType_ReportsTypeMismatch() throws SQLException { | ||
| assertThat(auditAgainst( | ||
| "CREATE TABLE parent (id BIGINT PRIMARY KEY, name INTEGER, quantity INTEGER)", | ||
| CLEAN_CHILD)) | ||
| .as("Column whose type differs from the mapping should be reported.") | ||
| .anySatisfy(violation -> assertThat(violation) | ||
| .contains("wrong column type").contains("name") | ||
| .contains("varchar")); | ||
| } | ||
|
|
||
| @Test | ||
| void testAudit_MultipleDriftsInOneSchema_ReportsThemAllAtOnce() | ||
| throws SQLException { | ||
| final List<String> violations = auditAgainst( | ||
| "CREATE TABLE parent (id BIGINT PRIMARY KEY, name INTEGER)"); | ||
|
|
||
| assertThat(violations) | ||
| .as("Every mismatch should surface in a single run: child's " | ||
| + "missing table, parent's missing quantity column, and " | ||
| + "parent.name's wrong type.") | ||
| .hasSize(3) | ||
| .anySatisfy(violation -> assertThat(violation) | ||
| .contains("missing table").contains("child")) | ||
| .anySatisfy(violation -> assertThat(violation) | ||
| .contains("missing column").contains("quantity")) | ||
| .anySatisfy(violation -> assertThat(violation) | ||
| .contains("wrong column type").contains("name")); |
There was a problem hiding this comment.
4. assertthat(violation) missing .as() 📘 Rule violation ⚙ Maintainability
Multiple AssertJ assertion chains inside anySatisfy(...) omit .as("...".) descriptions. This
violates the requirement that each AssertJ assertion include a description ending with a period.
Agent Prompt
## Issue description
AssertJ assertions inside the `anySatisfy(...)` lambdas do not include `.as("...".)` descriptions.
## Issue Context
The rule requires a non-empty string literal description ending with `.` for each AssertJ assertion chain.
## Fix Focus Areas
- src/test/java/io/github/databaseaudits/audit/jpa/SchemaEntityValidationAuditIT.java[48-93]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| final Map<String, DatabaseColumn> databaseColumns = | ||
| columnsBySchema | ||
| .computeIfAbsent(schema, | ||
| s -> readColumns(databaseMetaData, | ||
| catalog, s)) | ||
| .get(canonical(table.getName())); |
There was a problem hiding this comment.
5. Complex computeifabsent().get() chain 📘 Rule violation ⚙ Maintainability
The statement computing databaseColumns chains multiple operations (computeIfAbsent(...) + lambda + .get(...)) in a single expression. This exceeds the maximum expression complexity per statement and reduces readability/maintainability.
Agent Prompt
## Issue description
A multi-step map lookup/build is implemented as a single chained expression, increasing per-statement expression complexity.
## Issue Context
The code both creates/fetches the schema map and then fetches the table entry in the same statement.
## Fix Focus Areas
- src/main/java/io/github/databaseaudits/audit/jpa/SchemaEntityValidationAudit.java[133-138]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| public class SchemaEntityValidationAudit { | ||
| private final EntityManagerFactory entityManagerFactory; | ||
| private final Supplier<Metadata> metadataSupplier; | ||
| private final DataSource dataSource; | ||
|
|
||
| /** | ||
| * Constructs the audit around the boot mapping model and the datasource whose | ||
| * live schema it is checked against. | ||
| * | ||
| * @param metadataSupplier | ||
| * supplies the boot {@link Metadata} for the | ||
| * persistence unit, resolved when {@link #audit()} | ||
| * runs; see | ||
| * {@link #forEntityManagerFactory(EntityManagerFactory, DataSource)}. | ||
| * @param dataSource | ||
| * the datasource whose schema the mappings are | ||
| * validated against. | ||
| */ | ||
| public SchemaEntityValidationAudit(final Supplier<Metadata> metadataSupplier, | ||
| final DataSource dataSource) { | ||
| this.metadataSupplier = metadataSupplier; | ||
| this.dataSource = dataSource; | ||
| } | ||
|
|
||
| /** | ||
| * Builds an audit for a JPA {@link EntityManagerFactory}, resolving its boot | ||
| * {@link Metadata} from {@link MappingMetadataIntegrator} when the audit runs. | ||
| * | ||
| * @param entityManagerFactory | ||
| * the factory whose mappings to validate. | ||
| * @param dataSource | ||
| * the datasource whose schema to validate | ||
| * against. | ||
| * @return the audit. | ||
| */ | ||
| public static SchemaEntityValidationAudit forEntityManagerFactory( | ||
| final EntityManagerFactory entityManagerFactory, | ||
| final DataSource dataSource) { | ||
| return new SchemaEntityValidationAudit( | ||
| () -> MappingMetadataIntegrator | ||
| .metadataFor(entityManagerFactory), | ||
| dataSource); | ||
| } |
There was a problem hiding this comment.
6. Docs now incorrect 🐞 Bug ⚙ Maintainability
The site docs/examples still use the removed new SchemaEntityValidationAudit(entityManagerFactory) constructor and describe relying on ddl-auto=validate, but the class now requires Supplier<Metadata> + DataSource and explicitly expects ddl-auto=none, so users following the docs will not compile or will run the audit with the wrong configuration.
Agent Prompt
### Issue description
The published Asciidoc documentation is stale after the SchemaEntityValidationAudit API/behavior change. It still shows the old constructor and `ddl-auto=validate` guidance, which no longer matches the implementation.
### Issue Context
The PR changes SchemaEntityValidationAudit to require a `DataSource` and a boot `Metadata` supplier (via `forEntityManagerFactory` / MappingMetadataIntegrator), and recommends running with `ddl-auto=none`.
### Fix Focus Areas
- src/site/asciidoc/audits.adoc[235-251]
- src/site/asciidoc/usage.adoc[91-105]
- src/main/java/io/github/databaseaudits/audit/jpa/SchemaEntityValidationAudit.java[51-92]
### Suggested changes
- Replace `new SchemaEntityValidationAudit(entityManagerFactory)` examples with `SchemaEntityValidationAudit.forEntityManagerFactory(emf, dataSource)` (or show constructing with `(Supplier<Metadata>, DataSource)` where appropriate).
- Update narrative to reflect that this audit does **not** rely on `ddl-auto=validate` and should be run with `ddl-auto=none` (per the new class Javadoc).
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| public static Metadata metadataFor( | ||
| final EntityManagerFactory entityManagerFactory) { | ||
| return METADATA_BY_UUID.get(entityManagerFactory | ||
| .unwrap(SessionFactoryImplementor.class).getUuid()); | ||
| } |
There was a problem hiding this comment.
7. Unwrap failures unhandled 🐞 Bug ☼ Reliability
MappingMetadataIntegrator.metadataFor unconditionally calls entityManagerFactory.unwrap(SessionFactoryImplementor.class); if unwrap is unsupported or fails, the audit throws an unrelated runtime exception instead of the intended “metadata was not captured” IllegalStateException.
Agent Prompt
### Issue description
`MappingMetadataIntegrator.metadataFor(...)` can throw during `unwrap(SessionFactoryImplementor.class)` before SchemaEntityValidationAudit can handle the “metadata missing” case, producing confusing failures.
### Issue Context
SchemaEntityValidationAudit.audit() expects `metadataSupplier.get()` to either return Metadata or `null` so it can throw a clear `IllegalStateException` explaining how to enable metadata capture.
### Fix Focus Areas
- src/main/java/io/github/databaseaudits/audit/jpa/MappingMetadataIntegrator.java[85-89]
- src/main/java/io/github/databaseaudits/audit/jpa/SchemaEntityValidationAudit.java[104-112]
### Suggested changes
- In `MappingMetadataIntegrator.metadataFor(...)`:
- Validate `entityManagerFactory != null`.
- Wrap `unwrap(...)` in a try/catch (e.g., `RuntimeException`) and either:
- return `null` (so the audit emits its existing “metadata not captured” message), or
- throw a new `IllegalStateException` with a targeted message (“EntityManagerFactory is not a Hibernate SessionFactory; cannot resolve UUID for metadata lookup”) and include the caught exception as the cause.
- Optionally, in `SchemaEntityValidationAudit.audit()` catch exceptions thrown by `metadataSupplier.get()` and rethrow as an `IllegalStateException` that preserves the current actionable guidance plus the original cause.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
96e3ddc to
0f893ab
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/site/asciidoc/usage.adoc (1)
96-100: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueMinor:
emfabbreviation breaks naming consistency with other docs pages.
audits.adocandarchitecture.adocboth spell outentityManagerFactory; this snippet abbreviates toemf. Purely cosmetic, but consistent naming across pages reads better.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/site/asciidoc/usage.adoc` around lines 96 - 100, The snippet uses the abbreviated variable name emf, which is inconsistent with the rest of the docs. Update the example in SchemaEntityValidationAudit.forEntityManagerFactory usage to spell out entityManagerFactory instead of emf so it matches audits.adoc and architecture.adoc and keeps naming consistent across pages.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/main/java/io/github/databaseaudits/audit/jpa/SchemaEntityValidationAudit.java`:
- Around line 165-186: The schema validation audit only checks unqualified
exclusion keys in SchemaEntityValidationAudit, so schema-specific suppressions
are ignored and same-named tables/columns in other schemas can be hidden
accidentally. Update the exclusion handling in the audit loop to recognize both
table and column exclusions with schema-qualified variants, using the existing
qualifiedName(schema, tableName) flow and the canonical(...) matching logic, so
users can exclude schema.table and schema.table.column precisely.
---
Nitpick comments:
In `@src/site/asciidoc/usage.adoc`:
- Around line 96-100: The snippet uses the abbreviated variable name emf, which
is inconsistent with the rest of the docs. Update the example in
SchemaEntityValidationAudit.forEntityManagerFactory usage to spell out
entityManagerFactory instead of emf so it matches audits.adoc and
architecture.adoc and keeps naming consistent across pages.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 806d2e30-ff55-4d6b-9d87-88d2377860f1
📒 Files selected for processing (8)
src/main/java/io/github/databaseaudits/audit/jpa/MappingMetadataIntegrator.javasrc/main/java/io/github/databaseaudits/audit/jpa/SchemaEntityValidationAudit.javasrc/main/resources/META-INF/services/org.hibernate.integrator.spi.Integratorsrc/site/asciidoc/architecture.adocsrc/site/asciidoc/audits.adocsrc/site/asciidoc/usage.adocsrc/test/java/io/github/databaseaudits/audit/jpa/SchemaEntityValidationAuditIT.javasrc/test/java/io/github/databaseaudits/audit/jpa/SchemaEntityValidationAuditTest.java
70bfeee to
0f893ab
Compare
SchemaEntityValidationAudit previously only confirmed the EntityManagerFactory was built, leaning on Hibernate's fail-fast ddl-auto=validate startup check that aborts on the first mismatch. It now validates every mapped physical table and column against the live schema itself and returns one finding per missing table, missing column, and incompatible column type, reproducing Hibernate's own type-compatibility rule so a mapping Hibernate accepts is never flagged. A ServiceLoader-registered MappingMetadataIntegrator captures each persistence unit's boot Metadata (keyed by SessionFactory UUID, so it still resolves through a proxied EntityManagerFactory such as Spring's); forEntityManagerFactory looks it back up at audit time. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UkRk16pW4VEM3E6vrDoG5y
0f893ab to
9d348d9
Compare
SchemaEntityValidationAudit previously only confirmed the EntityManagerFactory was built, leaning on Hibernate's fail-fast ddl-auto=validate startup check that aborts on the first mismatch. It now validates every mapped physical table and column against the live schema itself and returns one finding per missing table, missing column, and incompatible column type, reproducing Hibernate's own type-compatibility rule so a mapping Hibernate accepts is never flagged.
A ServiceLoader-registered MappingMetadataIntegrator captures each persistence unit's boot Metadata (keyed by SessionFactory UUID, so it still resolves through a proxied EntityManagerFactory such as Spring's); forEntityManagerFactory looks it back up at audit time.
Claude-Session: https://claude.ai/code/session_01UkRk16pW4VEM3E6vrDoG5y
Summary by CodeRabbit
New Features
Bug Fixes