mybatis/mybatis-3 · error · ReflectionException

There is no setter for property named '{}' in '{}'

Error message

There is no setter for property named '{}' in '{}'

What it means

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.

Source

Thrown at src/main/java/org/apache/ibatis/reflection/Reflector.java:381

  public Class<?> getType() {
    return clazz;
  }

  public Constructor<?> getDefaultConstructor() {
    if (defaultConstructor != null) {
      return defaultConstructor;
    }
    throw new ReflectionException("There is no default constructor for " + clazz);
  }

  public boolean hasDefaultConstructor() {
    return defaultConstructor != null;
  }

  public Invoker getSetInvoker(String propertyName) {
    Invoker method = setMethods.get(propertyName);
    if (method == null) {
      throw new ReflectionException("There is no setter for property named '" + propertyName + "' in '" + clazz + "'");
    }
    return method;
  }

  public Invoker getGetInvoker(String propertyName) {
    Invoker method = getMethods.get(propertyName);
    if (method == null) {
      throw new ReflectionException("There is no getter for property named '" + propertyName + "' in '" + clazz + "'");
    }
    return method;
  }

  /**
   * Gets the type for a property setter.
   *
   * @param propertyName
   *          - the name of the property
   *

View on GitHub (pinned to 008069adb1)

Solutions

  1. Add a standard setter setProperty(...) to the target class.
  2. Fix the property name in <result property="..."> to match the bean (case-insensitive lookup must still resolve).
  3. For immutable classes, switch to <constructor> mapping so values go through the constructor instead of setters.

Example fix

// before
class User { private final String name; User(String name){this.name=name;} }
<!-- resultMap: <result property="name" column="name"/> -->
// after
<resultMap id="u" type="User">
  <constructor><arg column="name" javaType="string"/></constructor>
</resultMap>
Defensive patterns

Strategy: validation

Validate before calling

Reflector ref = new Reflector(User.class);
String[] writable = ref.getSetablePropertyNames(); // ensure every mapped property appears here

Type guard

boolean hasSetter(Class<?> c, String prop) {
  return Arrays.asList(new Reflector(c).getSetablePropertyNames()).contains(prop.toUpperCase(Locale.ROOT));
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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