HIBERNATE-153 Explicitly forbid the @JdbcTypeCode annotation#156
HIBERNATE-153 Explicitly forbid the @JdbcTypeCode annotation#156strogiyotec wants to merge 1 commit intomongodb:mainfrom
Conversation
| OuterEmbeddable outer; | ||
| } | ||
|
|
||
| private static void assertNotSupported(Class<?> entityClass) { |
There was a problem hiding this comment.
there is a similar method in CalendarIntegrationTests that is used all over the code base, I believe it's a tech debt and should be moved to a separate utility class ?
For now I introduced a new one with hardcoded expected error message
There was a problem hiding this comment.
Pull request overview
Adds a runtime metadata scan to explicitly reject Hibernate’s @JdbcTypeCode usage when bootstrapping mappings for the MongoDB Hibernate extension, aligning with HIBERNATE-153.
Changes:
- Add reflection-based scanning in
MongoAdditionalMappingContributorto throwFeatureNotSupportedExceptionwhen@JdbcTypeCodeis detected on entity/embeddable classes or superclasses. - Add integration tests covering direct entity usage, embeddable usage (including nested embeddables), and superclass inheritance.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
src/main/java/com/mongodb/hibernate/internal/boot/MongoAdditionalMappingContributor.java |
Introduces runtime scanning logic to forbid @JdbcTypeCode during metadata contribution. |
src/integrationTest/java/com/mongodb/hibernate/type/JdbcTypeCodeIntegrationTests.java |
Adds integration tests asserting bootstrapping fails when @JdbcTypeCode is present in several mapping scenarios. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| forbidJdbcTypeCodeAnnotationOnClass(persistentClass, persistentClass.getMappedClass()); | ||
| forbidJdbcTypeCodeAnnotationOnProperties(persistentClass, persistentClass.getProperties()); | ||
| } | ||
|
|
There was a problem hiding this comment.
forbidJdbcTypeCodeAnnotation() scans the entity class and mapped properties, but it does not traverse the identifier mapping. If the entity uses an @EmbeddedId (or other composite identifier backed by a Component), @JdbcTypeCode inside the embeddable identifier type won’t be detected because only the entity field itself is scanned (not the embeddable class). Consider also inspecting persistentClass.getIdentifierProperty()/getIdentifier() when it is a Component and recursing into that component’s class/properties, similar to how checkPropertyTypes() handles identifiers.
| forbidJdbcTypeCodeAnnotationOnClass(persistentClass, persistentClass.getMappedClass()); | |
| forbidJdbcTypeCodeAnnotationOnProperties(persistentClass, persistentClass.getProperties()); | |
| } | |
| forbidJdbcTypeCodeAnnotationOnClass(persistentClass, persistentClass.getMappedClass()); | |
| forbidJdbcTypeCodeAnnotationOnIdentifier(persistentClass); | |
| forbidJdbcTypeCodeAnnotationOnProperties(persistentClass, persistentClass.getProperties()); | |
| } | |
| private static void forbidJdbcTypeCodeAnnotationOnIdentifier(PersistentClass persistentClass) { | |
| var identifierProperty = persistentClass.getIdentifierProperty(); | |
| if (identifierProperty != null && identifierProperty.getValue() instanceof Component component) { | |
| forbidJdbcTypeCodeAnnotationOnClass(persistentClass, component.getComponentClass()); | |
| forbidJdbcTypeCodeAnnotationOnProperties(persistentClass, component.getProperties()); | |
| } | |
| if (persistentClass.getIdentifier() instanceof Component component) { | |
| forbidJdbcTypeCodeAnnotationOnClass(persistentClass, component.getComponentClass()); | |
| forbidJdbcTypeCodeAnnotationOnProperties(persistentClass, component.getProperties()); | |
| } | |
| } |
| private static void forbidJdbcTypeCodeAnnotationOnProperties( | ||
| PersistentClass persistentClass, java.util.List<Property> properties) { | ||
| properties.forEach(property -> { | ||
| if (property.getValue() instanceof Component component) { | ||
| forbidJdbcTypeCodeAnnotationOnClass(persistentClass, component.getComponentClass()); | ||
| forbidJdbcTypeCodeAnnotationOnProperties(persistentClass, component.getProperties()); | ||
| } | ||
| }); |
There was a problem hiding this comment.
forbidJdbcTypeCodeAnnotationOnProperties() only recurses when property.getValue() is a Component. For plural attributes mapped via an AggregateColumn (e.g., arrays/collections of @Struct/@embeddable types), the embeddable Component hangs off the AggregateColumn (see checkPropertyType() handling at MongoAdditionalMappingContributor.java:193-195), so @JdbcTypeCode on those embeddable classes would currently be missed. Consider detecting AggregateColumn-backed values and recursing into aggregateColumn.getComponent() as well.
| @Test | ||
| void entityWithJdbcTypeCodeOnBasicField() { | ||
| assertNotSupported(ItemWithJdbcTypeCodeOnField.class); | ||
| } | ||
|
|
||
| @Test | ||
| void entityWithJdbcTypeCodeInEmbeddable() { | ||
| assertNotSupported(ItemWithEmbeddableContainingJdbcTypeCode.class); | ||
| } | ||
|
|
||
| /** | ||
| * Test that @JdbcTypeCode is not supported even when it's nested within multiple levels of embeddables, as the | ||
| * feature is not supported at all. | ||
| */ | ||
| @Test | ||
| void entityWithJdbcTypeCodeInNestedEmbeddable() { | ||
| assertNotSupported(ItemWithNestedEmbeddableContainingJdbcTypeCode.class); | ||
| } | ||
|
|
||
| @Test | ||
| void entityWithJdbcTypeCodeInSuperclass() { | ||
| assertNotSupported(ItemInheritingJdbcTypeCode.class); | ||
| } |
There was a problem hiding this comment.
Current integration tests cover basic field / embedded / nested embedded / superclass cases, but they don’t cover @JdbcTypeCode inside an embeddable identifier (e.g., @EmbeddedId) or inside embeddables mapped via AggregateColumn (e.g., arrays/collections of @Struct embeddables). Adding tests for these cases would prevent regressions once the runtime scan is extended to traverse identifier components and AggregateColumn components.
HIBERNATE-153 on runtime scan entities on the usage of JdbcTypeCode
This PR covers following cases
EntityEntity