{"record":{"id":"1ce63f44c1ef74a0","repo":"hibernate/hibernate-orm","slug":"anytype-not-supported-as-part-of-cache-key","errorCode":null,"errorMessage":"AnyType not supported as part of cache key!","messagePattern":"AnyType not supported as part of cache key!","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/type/AnyType.java","lineNumber":363,"sourceCode":"\tpublic Serializable disassemble(Object value, SharedSessionContractImplementor session, Object owner) throws HibernateException {\n\t\tif ( value == null ) {\n\t\t\treturn null;\n\t\t}\n\t\telse {\n\t\t\treturn new ObjectTypeCacheEntry(\n\t\t\t\t\tsession.bestGuessEntityName( value ),\n\t\t\t\t\tgetEntityIdentifierIfNotUnsaved(\n\t\t\t\t\t\t\tsession.bestGuessEntityName( value ),\n\t\t\t\t\t\t\tvalue,\n\t\t\t\t\t\t\tsession\n\t\t\t\t\t)\n\t\t\t);\n\t\t}\n\t}\n\n\t@Override\n\tpublic Serializable disassemble(Object value, SessionFactoryImplementor sessionFactory) throws HibernateException {\n\t\tthrow new UnsupportedOperationException( \"AnyType not supported as part of cache key!\" );\n\t}\n\n\t@Override\n\tpublic Object replace(Object original, Object target, SharedSessionContractImplementor session, Object owner, Map<Object, Object> copyCache)\n\t\t\tthrows HibernateException {\n\t\tif ( original == null ) {\n\t\t\treturn null;\n\t\t}\n\t\telse {\n\t\t\tfinal String entityName = session.bestGuessEntityName( original );\n\t\t\tfinal Object id = getEntityIdentifierIfNotUnsaved( entityName, original, session );\n\t\t\treturn session.internalLoad( entityName, id, eager, false );\n\t\t}\n\t}\n\n\t// CompositeType implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n\t@Override","sourceCodeStart":345,"sourceCodeEnd":381,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/type/AnyType.java#L345-L381","documentation":"AnyType (the type Hibernate assigns to @Any/@ManyToAny mappings) overrides Type.disassemble(Object, SessionFactoryImplementor) to throw UnsupportedOperationException, because an any-typed value (discriminator + id pair pointing at different entities) has no stable representation usable as a second-level cache key. The two-argument disassemble is invoked by DefaultCacheKeysFactory when materializing entity-id and natural-id cache keys, so the error surfaces the first time a cached entity whose key includes an @Any value is read or written through the cache.","triggerScenarios":"An @Any or @ManyToAny mapping used as an entity identifier, as part of a composite id, or as a member of a @NaturalId on an entity that is second-level cached (@Cacheable/@Cache); also an @Any embedded in a @Embedded component that participates in a natural id, since ComponentType.disassemble recurses into property types. Calls to Type.disassemble(value, sessionFactory) in custom code on an AnyType hit the same throw.","commonSituations":"Legacy mappings using <any> inside a composite natural key; adding @Cacheable to an entity that already had a polymorphic @Any reference in its natural id; migrating from Hibernate 5 where a different cache-key path silently serialized the value.","solutions":["Remove the @Any attribute from the natural id / composite key and key the cache on a plain value (e.g. the id column alone).","Replace @Any with a concrete @ManyToOne (or several typed associations) if the association must participate in cache keys.","If polymorphism is required, model the reference as a first-class association table (join entity with discriminator + fk) instead of @Any.","Exclude the entity from second-level caching if the @Any must stay in the key position."],"exampleFix":"// before\n@Entity\n@Cacheable\npublic class Document {\n    @Id Long id;\n\n    @Any\n    @AnyDiscriminator(MapKeyDiscriminatorType.STRING)\n    @AnyKeyDefaultDiscriminator(\"USER\")\n    @JoinColumn(name = \"owner_type\")\n    @Column(name = \"owner_id\")\n    private Party owner; // used in @NaturalId below\n\n    @NaturalId\n    OwnerRef naturalKey; // component containing the @Any\n}\n\n// after: key the cache on plain columns only\n@Entity\n@Cacheable\npublic class Document {\n    @Id Long id;\n\n    @Any(...) // kept as an ordinary attribute, NOT part of the natural id\n    private Party owner;\n\n    @NaturalId\n    @Column(name = \"doc_code\")\n    private String docCode;\n}","handlingStrategy":"validation","validationCode":"// Fail fast at startup: cached entities must not have @Any inside id/natural-id components\nMetamodel mm = emf.getMetamodel();\nfor (EntityType<?> et : mm.getEntities()) {\n    if (et.getJavaType().isAnnotationPresent(Cacheable.class)) {\n        for (Attribute<?, ?> attr : et.getAttributes()) {\n            Member m = attr.getJavaMember();\n            if (m instanceof Field f && (f.isAnnotationPresent(Any.class)\n                    || f.isAnnotationPresent(ManyToAny.class))\n                    && (attr.isCollection() || isInNaturalId(et, attr))) {\n                throw new IllegalStateException(\n                    et.getName() + \".\" + attr.getName()\n                    + \" is @Any and cannot participate in a cache key\");\n            }\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep @Any mappings out of identifiers and @NaturalId members; they are value pairs, not cache-key-able scalars.","Add a mapping smoke test that loads/caches one instance of every cached entity to surface cache-key errors at build time.","Document the limitation wherever @Any is introduced in code review."],"tags":["hibernate","any-mapping","second-level-cache","natural-id","cache-key"],"backgroundTag":"cache-key-unsupported-type","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}