mybatis/mybatis-3 · error · ReflectionException

Cannot get the value '{}' because the property '{}' is not M

Error message

Cannot get the value '{}' because the property '{}' is not Map, List or Array.

What it means

BaseWrapper.getCollectionValue handles Map, List, and arrays (object arrays plus all primitive arrays) as indexable collections. If the resolved property value is non-null but is none of those types, MyBatis cannot apply the '[index]' operator to it, so a ReflectionException is thrown. The index expression only works on Map (key lookup) and integer-indexed types.

Source

Thrown at src/main/java/org/apache/ibatis/reflection/wrapper/BaseWrapper.java:75

      return ((Object[]) collection)[i];
    } else if (collection instanceof char[]) {
      return ((char[]) collection)[i];
    } else if (collection instanceof boolean[]) {
      return ((boolean[]) collection)[i];
    } else if (collection instanceof byte[]) {
      return ((byte[]) collection)[i];
    } else if (collection instanceof double[]) {
      return ((double[]) collection)[i];
    } else if (collection instanceof float[]) {
      return ((float[]) collection)[i];
    } else if (collection instanceof int[]) {
      return ((int[]) collection)[i];
    } else if (collection instanceof long[]) {
      return ((long[]) collection)[i];
    } else if (collection instanceof short[]) {
      return ((short[]) collection)[i];
    } else {
      throw new ReflectionException("Cannot get the value '" + prop.getIndexedName() + "' because the property '"
          + prop.getName() + "' is not Map, List or Array.");
    }
  }

  protected void setCollectionValue(PropertyTokenizer prop, Object collection, Object value) {
    if (collection == null) {
      throw new ReflectionException("Cannot set the value '" + prop.getIndexedName() + "' because the property '"
          + prop.getName() + "' is null.");
    }
    if (collection instanceof Map) {
      ((Map) collection).put(prop.getIndex(), value);
    } else {
      int i = Integer.parseInt(prop.getIndex());
      if (collection instanceof List) {
        ((List) collection).set(i, value);
      } else if (collection instanceof Object[]) {
        ((Object[]) collection)[i] = value;
      } else if (collection instanceof char[]) {

View on GitHub (pinned to 008069adb1)

Solutions

  1. Change the property to a List, Map, or array if you need index access
  2. For Sets, iterate with <foreach> instead of indexing, or convert: new ArrayList<>(set)
  3. Use dotted property names ('bean.field') for beans instead of bracket syntax
  4. For Map-like lookup on non-standard types, expose the value through a getter (getByIndex(i))

Example fix

// before
private Set<Item> items; // #{items[0]} throws

// after
private List<Item> items; // #{items[0]} works
Defensive patterns

Strategy: type-guard

Validate before calling

Object coll = metaObject.getValue(prop);
if (!(coll instanceof Map || coll instanceof List || coll.getClass().isArray())) {
  // convert to List or use a different expression
}

Type guard

boolean indexable(Object o) {
  return o == null || o instanceof Map || o instanceof List || o.getClass().isArray();
}

Try / catch

try { metaObject.getValue("tags[0]"); }
catch (ReflectionException e) {
  if (e.getMessage().contains("not Map, List or Array")) { /* switch to foreach or convert type */ }
  else throw e;
}

Prevention

When it happens

Trigger: #{item[0]} where 'item' is a plain bean or String; MetaObject.getValue("someSet[0]") where the property is a java.util.Set (Set is Iterable but not List, so it fails); indexing into a custom collection type that implements neither List nor Map.

Common situations: Switching a field from List to Set (e.g. HashSet for dedup) while mapper expressions still index it; using '[key]' syntax against a bean instead of dotted property access; parameter objects carrying custom collection implementations.

Related errors


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