{"record":{"id":"8cac047586511d5b","repo":"mybatis/mybatis-3","slug":"there-is-no-setter-for-property-named-in","errorCode":null,"errorMessage":"There is no setter for property named '{}' in '{}'","messagePattern":"There is no setter for property named '(.+?)' in '(.+?)'","errorType":"exception","errorClass":"ReflectionException","httpStatus":null,"severity":"error","filePath":"src/main/java/org/apache/ibatis/reflection/Reflector.java","lineNumber":381,"sourceCode":"  public Class<?> getType() {\n    return clazz;\n  }\n\n  public Constructor<?> getDefaultConstructor() {\n    if (defaultConstructor != null) {\n      return defaultConstructor;\n    }\n    throw new ReflectionException(\"There is no default constructor for \" + clazz);\n  }\n\n  public boolean hasDefaultConstructor() {\n    return defaultConstructor != null;\n  }\n\n  public Invoker getSetInvoker(String propertyName) {\n    Invoker method = setMethods.get(propertyName);\n    if (method == null) {\n      throw new ReflectionException(\"There is no setter for property named '\" + propertyName + \"' in '\" + clazz + \"'\");\n    }\n    return method;\n  }\n\n  public Invoker getGetInvoker(String propertyName) {\n    Invoker method = getMethods.get(propertyName);\n    if (method == null) {\n      throw new ReflectionException(\"There is no getter for property named '\" + propertyName + \"' in '\" + clazz + \"'\");\n    }\n    return method;\n  }\n\n  /**\n   * Gets the type for a property setter.\n   *\n   * @param propertyName\n   *          - the name of the property\n   *","sourceCodeStart":363,"sourceCodeEnd":399,"githubUrl":"https://github.com/mybatis/mybatis-3/blob/008069adb1b089579b5dcba87ee591908b263274/src/main/java/org/apache/ibatis/reflection/Reflector.java#L363-L399","documentation":"Reflector.getSetInvoker(propertyName) throws when the class has no setter registered for that property (setMethods map has no entry). MyBatis calls it while populating result objects or applying parameter settings, so every mapped property needs a writable setter.","triggerScenarios":"A resultMap maps a property (or automapping finds a column matching a field) whose class exposes no setX(...) method — final fields, read-only properties, or a property-name typo in the mapping.","commonSituations":"Immutable DTOs with final fields; property name case/spelling mismatch between column-toProperty mapping and the bean; using a getter-only property like 'id' generated by a sequence.","solutions":["Add a standard setter setProperty(...) to the target class.","Fix the property name in <result property=\"...\"> to match the bean (case-insensitive lookup must still resolve).","For immutable classes, switch to <constructor> mapping so values go through the constructor instead of setters."],"exampleFix":"// before\nclass User { private final String name; User(String name){this.name=name;} }\n<!-- resultMap: <result property=\"name\" column=\"name\"/> -->\n// after\n<resultMap id=\"u\" type=\"User\">\n  <constructor><arg column=\"name\" javaType=\"string\"/></constructor>\n</resultMap>","handlingStrategy":"validation","validationCode":"Reflector ref = new Reflector(User.class);\nString[] writable = ref.getSetablePropertyNames(); // ensure every mapped property appears here","typeGuard":"boolean hasSetter(Class<?> c, String prop) {\n  return Arrays.asList(new Reflector(c).getSetablePropertyNames()).contains(prop.toUpperCase(Locale.ROOT));\n}","tryCatchPattern":null,"preventionTips":["Map only writable properties in resultMaps; route immutable values through <constructor>.","Keep bean property names and column-to-property mappings in one naming convention."],"tags":["mybatis","reflection","setter","resultmap","immutability"],"backgroundTag":null,"analyzedSha":"008069adb1b089579b5dcba87ee591908b263274","analyzedAt":"2026-08-14T13:07:10.264Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}