{"record":{"id":"e50865464e3bd5bd","repo":"hibernate/hibernate-orm","slug":"class-componentclassname-is-an-embeddable-t","errorCode":null,"errorMessage":"Class '<componentClassName>' is an '@Embeddable' type and may not be annotated '@BatchSize'","messagePattern":"Class '<componentClassName>' is an '@Embeddable' type and may not be annotated '@BatchSize'","errorType":"exception","errorClass":"AnnotationException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/binder/internal/BatchSizeBinder.java","lineNumber":33,"sourceCode":"import org.hibernate.mapping.Property;\nimport org.hibernate.mapping.Value;\n\n/**\n * Binder for the {@link BatchSize} annotation.\n *\n * @since 6.5\n *\n * @author Gavin King\n */\npublic class BatchSizeBinder implements TypeBinder<BatchSize>, AttributeBinder<BatchSize> {\n\t@Override\n\tpublic void bind(BatchSize batchSize, MetadataBuildingContext context, PersistentClass persistentClass) {\n\t\tpersistentClass.setBatchSize( batchSize.size() );\n\t}\n\n\t@Override\n\tpublic void bind(BatchSize batchSize, MetadataBuildingContext context, Component embeddableClass) {\n\t\tthrow new AnnotationException(\"Class '\" + embeddableClass.getComponentClassName()\n\t\t\t\t+ \"' is an '@Embeddable' type and may not be annotated '@BatchSize'\");\n\t}\n\n\t@Override\n\tpublic void bind(BatchSize batchSize, MetadataBuildingContext context, PersistentClass persistentClass, Property property) {\n\t\tfinal Value value = property.getValue();\n\t\tif ( value instanceof Collection collection ) {\n\t\t\tcollection.setBatchSize( batchSize.size() );\n\t\t}\n\t\telse {\n\t\t\tthrow new AnnotationException(\"Property '\" + property.getName() + \"' may not be annotated '@BatchSize'\");\n\t\t}\n\t}\n}\n","sourceCodeStart":15,"sourceCodeEnd":48,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/binder/internal/BatchSizeBinder.java#L15-L48","documentation":"Thrown by BatchSizeBinder when a class mapped as an @Embeddable is annotated @BatchSize. Hibernate 6.5+ validates annotation placement via dedicated binders, and batch fetching only applies to entity classes and collection roles. An embeddable is always loaded together with its owning entity, so a batch size on it is meaningless and fails metadata binding at SessionFactory build time with an AnnotationException.","triggerScenarios":"Registering an @Embeddable class that carries @BatchSize (via MetadataSources.addAnnotatedClass, addPackage, or annotation scanning) and building the SessionFactory. The type-binder overload bind(BatchSize, context, Component) runs and unconditionally throws.","commonSituations":"Copying @BatchSize onto a shared embeddable (e.g. Address) while refactoring an entity; a leftover annotation after converting an @Entity into an @Embeddable; upgrading to Hibernate 6.5+ where the previously ignored annotation now aborts bootstrap.","solutions":["Remove @BatchSize from the @Embeddable class.","To batch-fetch the owning entities, put @BatchSize(size = N) on the owning @Entity class instead.","If the embeddable declares a lazy collection, put @BatchSize on that collection-typed property (allowed for Collection values)."],"exampleFix":"// before\n@Embeddable\n@BatchSize(size = 10)\npublic class Address { ... }\n\n// after\n@Embeddable\npublic class Address { ... }\n\n@Entity\n@BatchSize(size = 10) // batch-fetch the owning entities\npublic class User {\n    @Embedded\n    private Address address;\n}","handlingStrategy":"validation","validationCode":"for (Class<?> cls : persistentClasses) {\n    if (cls.isAnnotationPresent(jakarta.persistence.Embeddable.class)\n            && cls.isAnnotationPresent(org.hibernate.annotations.BatchSize.class)) {\n        throw new IllegalStateException(\"@BatchSize not allowed on @Embeddable \" + cls.getName());\n    }\n}","typeGuard":null,"tryCatchPattern":"Wrap SessionFactory bootstrap (metadata.buildSessionFactory()) in try/catch (org.hibernate.AnnotationException e): the message names the offending class; log it and abort startup. Never catch-and-continue — the metadata is unusable.","preventionTips":["Keep @BatchSize on @Entity classes and collection-typed properties only.","Add a startup mapping lint that scans persistent classes for misplaced Hibernate annotations.","Treat any AnnotationException during bootstrap as a build failure in CI."],"tags":["hibernate","jpa","annotations","batch-size","embeddable","orm-mapping"],"backgroundTag":"jpa-annotation-misplacement","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}