{"record":{"id":"9d2b761ae1d55f79","repo":"mybatis/mybatis-3","slug":"illegal-overloaded-getter-method-with-ambiguous-ty","errorCode":null,"errorMessage":"Illegal overloaded getter method with ambiguous type for property ''{0}'' in class ''{1}''. This breaks the JavaBeans specification and can cause unpredictable results.","messagePattern":"Illegal overloaded getter method with ambiguous type for property ''(.+?)'' in class ''(.+?)''\\. This breaks the JavaBeans specification and can cause unpredictable results\\.","errorType":"exception","errorClass":"ReflectionException","httpStatus":null,"severity":"error","filePath":"src/main/java/org/apache/ibatis/reflection/invoker/AmbiguousMethodInvoker.java","lineNumber":33,"sourceCode":" */\npackage org.apache.ibatis.reflection.invoker;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\n\nimport org.apache.ibatis.reflection.ReflectionException;\n\npublic class AmbiguousMethodInvoker extends MethodInvoker {\n  private final String exceptionMessage;\n\n  public AmbiguousMethodInvoker(Method method, String exceptionMessage) {\n    super(method);\n    this.exceptionMessage = exceptionMessage;\n  }\n\n  @Override\n  public Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException {\n    throw new ReflectionException(exceptionMessage);\n  }\n}\n","sourceCodeStart":15,"sourceCodeEnd":36,"githubUrl":"https://github.com/mybatis/mybatis-3/blob/008069adb1b089579b5dcba87ee591908b263274/src/main/java/org/apache/ibatis/reflection/invoker/AmbiguousMethodInvoker.java#L15-L36","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\npublic Status getStatus() { ... }\npublic boolean isStatus() { ... }  // ambiguous with getStatus()\n// after\npublic Status getStatus() { ... }\npublic boolean hasStatus() { ... }","handlingStrategy":"validation","validationCode":"// detect ambiguous getters before MyBatis touches the class\nMap<String, Set<Class<?>>> byProperty = new HashMap<>();\nfor (Method m : Dto.class.getMethods()) {\n  String p = propertyNameOf(m); // getX -> x, isX -> x\n  if (p != null) byProperty.computeIfAbsent(p, k -> new HashSet<>()).add(m.getReturnType());\n}\nboolean ambiguous = byProperty.values().stream().anyMatch(s -> s.size() > 1);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["mybatis","reflection","javabeans","ambiguity","generated-code"],"backgroundTag":null,"analyzedSha":"008069adb1b089579b5dcba87ee591908b263274","analyzedAt":"2026-08-14T13:07:10.264Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}