mybatis/mybatis-3 · error · TypeException

ArrayType Handler requires SQL array or java array parameter

Error message

ArrayType Handler requires SQL array or java array parameter and does not support type " + parameter.getClass()

What it means

ArrayTypeHandler.setNonNullParameter only accepts java.sql.Array instances or genuine Java arrays (Object whose Class.isArray() is true). Any other object (List, String, POJO) reaches the else-branch and triggers this TypeException because MyBatis has no way to convert an arbitrary object into an SQL array via Connection.createArrayOf.

Source

Thrown at src/main/java/org/apache/ibatis/type/ArrayTypeHandler.java:86

    STANDARD_MAPPING.put(Short.class, JdbcType.SMALLINT.name());
    STANDARD_MAPPING.put(String.class, JdbcType.VARCHAR.name());
    STANDARD_MAPPING.put(Time.class, JdbcType.TIME.name());
    STANDARD_MAPPING.put(Timestamp.class, JdbcType.TIMESTAMP.name());
    STANDARD_MAPPING.put(URL.class, JdbcType.DATALINK.name());
  }

  public ArrayTypeHandler() {
  }

  @Override
  public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType)
      throws SQLException {
    if (parameter instanceof Array) {
      // it's the user's responsibility to properly free() the Array instance
      ps.setArray(i, (Array) parameter);
    } else {
      if (!parameter.getClass().isArray()) {
        throw new TypeException(
            "ArrayType Handler requires SQL array or java array parameter and does not support type "
                + parameter.getClass());
      }
      Class<?> componentType = parameter.getClass().getComponentType();
      String arrayTypeName = resolveTypeName(componentType);
      Array array = ps.getConnection().createArrayOf(arrayTypeName, (Object[]) parameter);
      ps.setArray(i, array);
      array.free();
    }
  }

  protected String resolveTypeName(Class<?> type) {
    return STANDARD_MAPPING.getOrDefault(type, JdbcType.JAVA_OBJECT.name());
  }

  @Override
  public Object getNullableResult(ResultSet rs, String columnName) throws SQLException {
    return extractArray(rs.getArray(columnName));

View on GitHub (pinned to 008069adb1)

Solutions

  1. Pass a plain Java array (e.g. Integer[] or String[]) instead of a collection: convert with ids.toArray(new Integer[0])
  2. Or pass a java.sql.Array built via connection.createArrayOf(...) and free() it afterwards
  3. If you must accept List, write a custom TypeHandler extending BaseTypeHandler<List<T>> that delegates to createArrayOf

Example fix

// before
List<Integer> ids = ...;
sqlSession.selectOne("stmt", ids); // ArrayTypeHandler gets a List

// after
Integer[] ids = list.toArray(new Integer[0]);
sqlSession.selectOne("stmt", ids);
Defensive patterns

Strategy: validation

Validate before calling

Object param = /* value bound for the array column */;
if (!(param instanceof java.sql.Array) && (param == null || !param.getClass().isArray())) {
  throw new IllegalArgumentException("Array parameter required, got: " + (param == null ? "null" : param.getClass()));
}

Type guard

static boolean isSqlArrayParam(Object v) {
  return v instanceof java.sql.Array || (v != null && v.getClass().isArray());
}

Try / catch

try { ... } catch (TypeException e) { // log param class, convert collections to arrays and retry once }

Prevention

When it happens

Trigger: A mapper parameter bound to ArrayTypeHandler (explicitly via #{ids,typeHandler=org.apache.ibatis.type.ArrayTypeHandler} or through javaType resolution) receives a java.util.List, Set, String, or custom object instead of Integer[]/String[]/java.sql.Array.

Common situations: Using PostgreSQL/HSQDB array columns and passing a List<Integer> from service code; registering ArrayTypeHandler as the default handler for a too-broad java type; wrapping the array in a DTO so the handler receives the wrapper object.

Related errors


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