mybatis/mybatis-3 · error · BuilderException

Ambiguous collection type for property '{property}'. You mus

Error message

Ambiguous collection type for property '{property}'. You must specify 'javaType' or 'resultMap'.

What it means

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.

Source

Thrown at src/main/java/org/apache/ibatis/builder/xml/XMLMapperBuilder.java:395

  private String processNestedResultMappings(XNode context, List<ResultMapping> resultMappings,
      Class<?> enclosingType) {
    if (Arrays.asList("association", "collection", "case").contains(context.getName())
        && context.getStringAttribute("select") == null) {
      validateCollection(context, enclosingType);
      ResultMap resultMap = resultMapElement(context, resultMappings, enclosingType);
      return resultMap.getId();
    }
    return null;
  }

  protected void validateCollection(XNode context, Class<?> enclosingType) {
    if ("collection".equals(context.getName()) && context.getStringAttribute("resultMap") == null
        && context.getStringAttribute("javaType") == null) {
      MetaClass metaResultType = MetaClass.forClass(enclosingType, configuration.getReflectorFactory());
      String property = context.getStringAttribute("property");
      if (!metaResultType.hasSetter(property)) {
        throw new BuilderException(
            "Ambiguous collection type for property '" + property + "'. You must specify 'javaType' or 'resultMap'.");
      }
    }
  }

  private void bindMapperForNamespace() {
    String namespace = builderAssistant.getCurrentNamespace();
    if (namespace != null) {
      Class<?> boundType = null;
      try {
        boundType = Resources.classForName(namespace);
      } catch (ClassNotFoundException e) {
        // ignore, bound type is not required
      }
      if (boundType != null && !configuration.hasMapper(boundType)) {
        // Spring may not know the real resource name so we set a flag
        // to prevent loading again this resource from the mapper interface
        // look at MapperAnnotationBuilder#loadXmlResource

View on GitHub (pinned to 008069adb1)

Solutions

  1. Add javaType="java.util.List" (or Set/Collection) to the <collection> so the type no longer needs inference
  2. Or add a resultMap="itemResultMap" attribute pointing at an explicit resultMap for the element type
  3. Or give the enclosing type a standard setter setItems(java.util.List<Item> item) / fix the typo in the property attribute

Example fix

<!-- before -->
<resultMap id="orderRM" type="Order">
  <collection property="items" ofType="Item"/>
</resultMap>

<!-- after -->
<resultMap id="orderRM" type="Order">
  <collection property="items" javaType="java.util.List" ofType="Item"/>
</resultMap>
Defensive patterns

Strategy: validation

Validate before calling

// static check before running: collection needs javaType/resultMap OR a real setter
boolean hasSetter = MetaClass.forClass(enclosingType, new DefaultReflectorFactory()).hasSetter(property);
if (!hasSetter && javaType == null && resultMap == null)
  throw new IllegalStateException("<collection property='" + property + "'> is ambiguous");

Prevention

When it happens

Trigger: <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.

Common situations: 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.

Related errors


AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14). Data as JSON: /api/errors/c9158c4e619cec07. Report an issue: GitHub.