{"record":{"id":"bd2896ad3a8f32d9","repo":"hibernate/hibernate-orm","slug":"generic-collections-don-t-have-indexes","errorCode":null,"errorMessage":"generic collections don't have indexes","messagePattern":"generic collections don't have indexes","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/type/CollectionType.java","lineNumber":70,"sourceCode":"\tprivate final String foreignKeyPropertyName;\n\n\t// the need for the persister if very hot in many use cases: cache it in a field\n\t// TODO initialize it at constructor time\n\tprivate volatile CollectionPersister persister;\n\n\tpublic CollectionType(String role, String foreignKeyPropertyName) {\n\t\tthis.role = role;\n\t\tthis.foreignKeyPropertyName = foreignKeyPropertyName;\n\t}\n\n\tpublic abstract CollectionClassification getCollectionClassification();\n\n\tpublic String getRole() {\n\t\treturn role;\n\t}\n\n\tpublic Object indexOf(Object collection, Object element) {\n\t\tthrow new UnsupportedOperationException( \"generic collections don't have indexes\" );\n\t}\n\n\tpublic boolean contains(Object collection, Object childObject, SharedSessionContractImplementor session) {\n\t\t// we do not have to worry about queued additions to uninitialized\n\t\t// collections, since they can only occur for inverse collections!\n\t\tfinal var elems = getElementsIterator( collection );\n\t\twhile ( elems.hasNext() ) {\n\t\t\tfinal Object maybeProxy = elems.next();\n\t\t\t// worrying about proxies is perhaps a little bit of overkill here...\n\t\t\tfinal var initializer = extractLazyInitializer( maybeProxy );\n\t\t\tfinal Object element =\n\t\t\t\t\tinitializer != null && !initializer.isUninitialized()\n\t\t\t\t\t\t\t? initializer.getImplementation()\n\t\t\t\t\t\t\t: maybeProxy;\n\t\t\tif ( element == childObject ) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/type/CollectionType.java#L52-L88","documentation":"CollectionType.indexOf (CollectionType.java:69) is the base implementation for collection types that have no positional index; it throws UnsupportedOperationException ('generic collections don't have indexes') because only indexed collections - List mapped with @OrderColumn/@ListIndexBase and Map with a key - can answer 'at which position does this element sit'. Any operation asking for element indexes against a Set/Bag-mapped role fails here.","triggerScenarios":"HQL that requests the index of elements on a collection mapped as Set or Bag (e.g. 'select index(d.lines) from Order d' or legacy 'indices(...)' where lines is a Set/@ElementCollection without @OrderColumn); programmatic calls to CollectionType.indexOf(collection, element) on a set/bag role; internal paths that build indexed snapshots for a role whose persister is not indexed.","commonSituations":"Changing a @OneToMany List to Set (for uniqueness) while old queries still use index()/list()-style expressions; porting legacy Hibernate 3/4 HQL that used indices()/elements(); assuming @ElementCollection of an ordered DB collection is index-addressable without @OrderColumn.","solutions":["If order matters, map the collection as a List with @OrderColumn (or a Map with @MapKeyColumn) so indexes exist.","If order does not matter, rewrite the query to use element membership/elements instead of index functions.","Check the persister: for Set-typed roles there is no index by definition - restructure the query or the model.","Replace legacy 'indices(...)'/'index(...)' HQL with @OrderColumn-based list handling or explicit position columns."],"exampleFix":"// before (lines is Set<Line>)\nList<Integer> idx = session.createQuery(\n    \"select index(l) from Order o join o.lines l\", Integer.class)\n    .getResultList(); // UnsupportedOperationException\n\n// after: map as ordered List\n@OneToMany(mappedBy = \"order\")\n@OrderColumn(name = \"position\")\nprivate List<Line> lines = new ArrayList<>();\n// then 'select index(l) ...' is valid","handlingStrategy":"validation","validationCode":"// Before querying, verify the collection actually has an index\nCollectionPersister p = ((SessionFactoryImplementor) sessionFactory)\n        .getMappingMetamodel().getCollectionDescriptor(Order.class.getName() + \".lines\");\nif (!p.hasIndex()) {\n    throw new IllegalStateException(\n        \"Order.lines is a Set/Bag; index()/indices() queries are not valid\");\n}","typeGuard":"static boolean isIndexedCollection(Collection<?> c) {\n    return c instanceof List<?> || c instanceof Map<?, ?>;\n}","tryCatchPattern":null,"preventionTips":["Map ordered data as List + @OrderColumn or Map + @MapKeyColumn when queries need element positions.","Remove index()/indices() expressions from HQL the moment a collection becomes a Set."],"tags":["hibernate","collection-mapping","hql","set","order-column"],"backgroundTag":"non-indexed-collection-access","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}