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
- Keep exactly one: @One for single-object associations (nested resultMap or select) or @Many for collections
- For collection properties use @Many; for to-one relations use @One
- 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
- Match multiplicity: single object → @One, collection → @Many, never both
- Delete the unused half when changing an association's kind
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
- If there is no type discriminator, then the NamedResultMap a
- Could not find a parent resultMap with id '{extend}'
- Could not find result map '{resultMapName}' referenced from
- Error in result map '{resultMapId}'. Failed to find a constr
- Error in result map '{resultMapId}'. We do not support parti
AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14).
Data as JSON: /api/errors/8b0c5bbee1a515b4.
Report an issue: GitHub.