mybatis/mybatis-3 · error · ReflectionException
Illegal overloaded getter method with ambiguous type for pro
Error message
Illegal overloaded getter method with ambiguous type for property ''{0}'' in class ''{1}''. This breaks the JavaBeans specification and can cause unpredictable results. What it means
AmbiguousMethodInvoker replaces a normal MethodInvoker when Reflector finds two getters resolving to the same property with incompatible types (e.g. getX() and isX() returning different types, or overloaded getX() with unrelated return types). Any later read of that property throws this ReflectionException instead of silently picking one — an explicit fail-fast because the JavaBeans spec forbids such pairs.
Source
Thrown at src/main/java/org/apache/ibatis/reflection/invoker/AmbiguousMethodInvoker.java:33
*/
package org.apache.ibatis.reflection.invoker;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.apache.ibatis.reflection.ReflectionException;
public class AmbiguousMethodInvoker extends MethodInvoker {
private final String exceptionMessage;
public AmbiguousMethodInvoker(Method method, String exceptionMessage) {
super(method);
this.exceptionMessage = exceptionMessage;
}
@Override
public Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException {
throw new ReflectionException(exceptionMessage);
}
}
View on GitHub (pinned to 008069adb1)
Solutions
- Rename or delete one of the conflicting accessors so a single getter serves the property.
- If isX() and getX() must coexist, make their types consistent or annotate the property mapping to a different, unambiguous property.
- Wrap the offending class in a clean DTO for MyBatis mapping instead of mapping the generated class directly.
Example fix
// before
public Status getStatus() { ... }
public boolean isStatus() { ... } // ambiguous with getStatus()
// after
public Status getStatus() { ... }
public boolean hasStatus() { ... } Defensive patterns
Strategy: validation
Validate before calling
// detect ambiguous getters before MyBatis touches the class
Map<String, Set<Class<?>>> byProperty = new HashMap<>();
for (Method m : Dto.class.getMethods()) {
String p = propertyNameOf(m); // getX -> x, isX -> x
if (p != null) byProperty.computeIfAbsent(p, k -> new HashSet<>()).add(m.getReturnType());
}
boolean ambiguous = byProperty.values().stream().anyMatch(s -> s.size() > 1); Prevention
- When refactoring a boolean property to another type, delete the old is-getter in the same change.
- Map generated classes (Thrift/Protobuf) through hand-written DTOs, or run the ambiguity check above in CI for all mapped types.
When it happens
Trigger: A class used as parameter or result type declaring both T getX() and boolean isX() (or two getX() overloads with unrelated returns); MyBatis registers the collision and throws the moment the property is accessed.
Common situations: Generated code (Thrift/Protobuf/ANTLR visitors) with is/set overloads; refactoring a boolean to an enum/object while keeping the old is-getter; third-party DTOs pulled in as resultType.
Related errors
- Error creating instance. Cause: {cause}
- Error in result map '{resultMapId}'. Failed to find a constr
- Failed to create a new Configuration instance.
- Cannot get Configuration as factory method [" + this.configu
- Cannot get Configuration as factory class [" + this.configur
AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14).
Data as JSON: /api/errors/9d2b761ae1d55f79.
Report an issue: GitHub.