mybatis/mybatis-3 · error · BuilderException

Cannot use both @One and @Many annotations in the same @Resu

Error message

Cannot use both @One and @Many annotations in the same @Result

What it means

Thrown by MapperAnnotationBuilder.hasNestedResultMap(): while inspecting an @Result for a nested result map, both @Result(one = @One(resultMap=...)) and @Result(many = @Many(resultMap=...)) are populated. A single association property cannot be both a single-object (@One) and a collection (@Many) mapping, so the ambiguity is rejected.

Source

Thrown at src/main/java/org/apache/ibatis/builder/annotation/MapperAnnotationBuilder.java:542

      columnPrefix = result.many().columnPrefix();
    }
    return columnPrefix;
  }

  private String nestedResultMapId(Result result) {
    String resultMapId = result.one().resultMap();
    if (resultMapId.isEmpty()) {
      resultMapId = result.many().resultMap();
    }
    if (!resultMapId.contains(".")) {
      resultMapId = type.getName() + "." + resultMapId;
    }
    return resultMapId;
  }

  private boolean hasNestedResultMap(Result result) {
    if (!result.one().resultMap().isEmpty() && !result.many().resultMap().isEmpty()) {
      throw new BuilderException("Cannot use both @One and @Many annotations in the same @Result");
    }
    return !result.one().resultMap().isEmpty() || !result.many().resultMap().isEmpty();
  }

  private String nestedSelectId(Result result) {
    String nestedSelect = result.one().select();
    if (nestedSelect.isEmpty()) {
      nestedSelect = result.many().select();
    }
    if (!nestedSelect.contains(".")) {
      nestedSelect = type.getName() + "." + nestedSelect;
    }
    return nestedSelect;
  }

  private boolean isLazy(Result result) {
    boolean isLazy = configuration.isLazyLoadingEnabled();
    if (!result.one().select().isEmpty() && FetchType.DEFAULT != result.one().fetchType()) {

View on GitHub (pinned to 008069adb1)

Solutions

  1. Keep exactly one: @One for single-object associations (nested resultMap or select) or @Many for collections
  2. For collection properties use @Many; for to-one relations use @One
  3. Remove the unused annotation attribute entirely

Example fix

// before
@Result(property = "orders", column = "id", one = @One(resultMap = "orderMap"), many = @Many(resultMap = "orderMap"))
// after
@Result(property = "orders", column = "id", many = @Many(resultMap = "orderMap"))
Defensive patterns

Strategy: type-guard

Type guard

static void checkResult(Result r) {
  boolean hasOne = !r.one().resultMap().isEmpty() || !r.one().select().isEmpty();
  boolean hasMany = !r.many().resultMap().isEmpty() || !r.many().select().isEmpty();
  if (hasOne && hasMany) {
    throw new IllegalStateException("@Result(property=" + r.property() + ") declares both @One and @Many");
  }
}

Prevention

When it happens

Trigger: @Result(property = "items", one = @One(resultMap = "itemMap"), many = @Many(resultMap = "itemMap")) — both annotation attributes non-default on the same @Result.

Common situations: Refactoring a one-to-one mapping into a collection (or vice versa) and leaving the old annotation in place; IDE auto-complete generating both stubs; copy-paste of a @Result that already had one side filled.

Related errors


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