{"record":{"id":"1a0d53f96db293d2","repo":"theonedev/onedev","slug":"unknown-collection-element-class-bean-x-propert","errorCode":null,"errorMessage":"Unknown collection element class (bean: X, property: Y)","messagePattern":"Unknown collection element class \\(bean: X, property: Y\\)","errorType":"exception","errorClass":"ExplicitException","httpStatus":null,"severity":"error","filePath":"server-core/src/main/java/io/onedev/server/ai/BuildSpecSchema.java","lineNumber":101,"sourceCode":"                        var grammar = IOUtils.toString(grammarStream, StandardCharsets.UTF_8);\n                        descriptionSections.add(\"NOTE: If set, the value should conform with below ANTLR v4 grammar:\\n\\n\" + grammar);\n                    } catch (IOException e) {\n                        throw new RuntimeException(e);\n                    }\n                }\n            } finally {\n                IOUtils.closeQuietly(grammarStream);\n            }\n        }\n\n        if (descriptionSections.size() != 0)\n            currentNode.put(\"description\", StringUtils.join(descriptionSections, \"\\n\\n\"));\n\n        Class<?> elementClass = null;\n        if (Collection.class.isAssignableFrom(returnType)) {\n            elementClass = ReflectionUtils.getCollectionElementClass(property.getPropertyGetter().getGenericReturnType());\n            if (elementClass == null)\n                throw new ExplicitException(\"Unknown collection element class (bean: \" + property.getBeanClass() + \", property: \" + property.getPropertyName() + \")\");\n            processCollectionProperty(currentNode, elementClass);\n        } else {\n            processType(currentNode, returnType);\n        }\n\n        Object defaultValue;\n        var value = property.getPropertyValue(bean);\n        if (value instanceof Integer) {\n            var intValue = (Integer) value;\n            if (intValue == 0)\n                defaultValue = null;\n            else\n                defaultValue = intValue;\n        } else if (value instanceof Long) {\n            var longValue = (Long) value;\n            if (longValue == 0)\n                defaultValue = null;\n            else","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/ai/BuildSpecSchema.java#L83-L119","documentation":"BuildSpecSchema generates a JSON schema from build spec bean classes. When a property returns a Collection, the code uses reflection to determine the collection's element class; if the generic return type carries no resolvable element type, it throws this ExplicitException because the schema cannot be built.","triggerScenarios":"Processing a bean property whose getter returns a Collection (List/Set) with an unparameterized or non-resolvable generic type, so ReflectionUtils.getCollectionElementClass returns null and processProperty throws.","commonSituations":"Custom build spec property classes defining raw List or Set fields without a type parameter, or using wildcards/generics the reflection helper cannot resolve.","solutions":["Add an explicit generic type parameter to the collection getter, e.g. List<String> instead of raw List.","If the element type is a custom class, ensure the getter's generic return type is concrete (not a type variable).","If writing a third-party spec class, follow OneDev's build spec conventions where all collection properties are strongly typed."],"exampleFix":"// before\npublic List getSteps() { return steps; }\n// after\npublic List<Step> getSteps() { return steps; }","handlingStrategy":"type-guard","validationCode":"for (Method m : beanClass.getMethods()) {\n    Type t = m.getGenericReturnType();\n    if (Collection.class.isAssignableFrom(m.getReturnType())\n            && !(t instanceof ParameterizedType))\n        throw new IllegalStateException(\"Collection property needs generic type: \" + m);\n}","typeGuard":"function isTypedCollection(m) {\n  return Collection.class.isAssignableFrom(m.getReturnType())\n      && m.getGenericReturnType() instanceof ParameterizedType;\n}","tryCatchPattern":"try {\n    schema = BuildSpecSchema.generate(specClass);\n} catch (ExplicitException e) {\n    if (e.getMessage().startsWith(\"Unknown collection element class\")) {\n        // fix the offending raw collection getter named in the message\n    }\n}","preventionTips":["Never use raw collection types in build spec beans.","Always parameterize List/Set/Map property getters.","Run schema generation in tests for custom spec classes."],"tags":["reflection","generics","schema","buildspec"],"backgroundTag":"schema-validation-failed","analyzedSha":"d44925c47c37992c828ea673a5f9620539bc3ff2","analyzedAt":"2026-09-06T07:18:27.995Z","contentChangedAt":"2026-09-06T07:18:27.995Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}