{"record":{"id":"c9158c4e619cec07","repo":"mybatis/mybatis-3","slug":"ambiguous-collection-type-for-property-property","errorCode":null,"errorMessage":"Ambiguous collection type for property '{property}'. You must specify 'javaType' or 'resultMap'.","messagePattern":"Ambiguous collection type for property '(.+?)'\\. You must specify 'javaType' or 'resultMap'\\.","errorType":"validation","errorClass":"BuilderException","httpStatus":null,"severity":"error","filePath":"src/main/java/org/apache/ibatis/builder/xml/XMLMapperBuilder.java","lineNumber":395,"sourceCode":"\n  private String processNestedResultMappings(XNode context, List<ResultMapping> resultMappings,\n      Class<?> enclosingType) {\n    if (Arrays.asList(\"association\", \"collection\", \"case\").contains(context.getName())\n        && context.getStringAttribute(\"select\") == null) {\n      validateCollection(context, enclosingType);\n      ResultMap resultMap = resultMapElement(context, resultMappings, enclosingType);\n      return resultMap.getId();\n    }\n    return null;\n  }\n\n  protected void validateCollection(XNode context, Class<?> enclosingType) {\n    if (\"collection\".equals(context.getName()) && context.getStringAttribute(\"resultMap\") == null\n        && context.getStringAttribute(\"javaType\") == null) {\n      MetaClass metaResultType = MetaClass.forClass(enclosingType, configuration.getReflectorFactory());\n      String property = context.getStringAttribute(\"property\");\n      if (!metaResultType.hasSetter(property)) {\n        throw new BuilderException(\n            \"Ambiguous collection type for property '\" + property + \"'. You must specify 'javaType' or 'resultMap'.\");\n      }\n    }\n  }\n\n  private void bindMapperForNamespace() {\n    String namespace = builderAssistant.getCurrentNamespace();\n    if (namespace != null) {\n      Class<?> boundType = null;\n      try {\n        boundType = Resources.classForName(namespace);\n      } catch (ClassNotFoundException e) {\n        // ignore, bound type is not required\n      }\n      if (boundType != null && !configuration.hasMapper(boundType)) {\n        // Spring may not know the real resource name so we set a flag\n        // to prevent loading again this resource from the mapper interface\n        // look at MapperAnnotationBuilder#loadXmlResource","sourceCodeStart":377,"sourceCodeEnd":413,"githubUrl":"https://github.com/mybatis/mybatis-3/blob/008069adb1b089579b5dcba87ee591908b263274/src/main/java/org/apache/ibatis/builder/xml/XMLMapperBuilder.java#L377-L413","documentation":"Thrown by XMLMapperBuilder.validateCollection() when a <collection> element in a resultMap has neither resultMap nor javaType, and the enclosing result type has no setter for the given property. MyBatis can usually infer the collection's element type from a setter's generic parameter; without a setter to inspect and without an explicit type, the mapping is ambiguous and rejected at build time.","triggerScenarios":"<collection property=\"items\" ofType=\"Item\"/> inside a <resultMap type=\"Order\"> where Order has no setItems(...) method (wrong property name, field-only class, immutable class, or Lombok @Builder without setters). Absent only when both the resultMap and javaType attributes of <collection> are null.","commonSituations":"Using Lombok @Builder/@Value or Java records as result types (no classic setters); typo in the property attribute; mapping onto a third-party DTO with fluent setters (setX returning 'this') that the reflector does not recognize; nested collections refactored to use ofType only.","solutions":["Add javaType=\"java.util.List\" (or Set/Collection) to the <collection> so the type no longer needs inference","Or add a resultMap=\"itemResultMap\" attribute pointing at an explicit resultMap for the element type","Or give the enclosing type a standard setter setItems(java.util.List<Item> item) / fix the typo in the property attribute"],"exampleFix":"<!-- before -->\n<resultMap id=\"orderRM\" type=\"Order\">\n  <collection property=\"items\" ofType=\"Item\"/>\n</resultMap>\n\n<!-- after -->\n<resultMap id=\"orderRM\" type=\"Order\">\n  <collection property=\"items\" javaType=\"java.util.List\" ofType=\"Item\"/>\n</resultMap>","handlingStrategy":"validation","validationCode":"// static check before running: collection needs javaType/resultMap OR a real setter\nboolean hasSetter = MetaClass.forClass(enclosingType, new DefaultReflectorFactory()).hasSetter(property);\nif (!hasSetter && javaType == null && resultMap == null)\n  throw new IllegalStateException(\"<collection property='\" + property + \"'> is ambiguous\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always set javaType (or resultMap) on <collection> when the enclosing type lacks classic setters","Be explicit with Lombok @Builder/record result types","Smoke-build the configuration in CI"],"tags":["mybatis","resultmap","collection","mapping"],"backgroundTag":null,"analyzedSha":"008069adb1b089579b5dcba87ee591908b263274","analyzedAt":"2026-08-14T13:07:10.264Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}