spring-projects/spring-framework · error · IntrospectionException

Type mismatch between indexed and non-indexed methods

Error message

Type mismatch between indexed and non-indexed methods: {} - {}

What it means

Thrown when a property exposes both a non-indexed accessor (getX()/setX()) and indexed accessors (getX(int)/setX(int, T)), but the non-indexed property type is not an array whose component type equals the indexed element type. Raised at line 239: propertyType must be an array and propertyType.componentType() must equal indexedPropertyType, otherwise IntrospectionException.

Solutions

  1. Align the non-indexed accessor to return an array whose component type matches the indexed element type (e.g. String[] getItems() with String getItem(int)).
  2. Or remove the non-indexed getter/setter so the property is treated as indexed-only.
  3. Or remove the indexed accessors if the collection-style getter is the intended public API.

Example fix

// before
private List<String> items;
public List<String> getItems() { return items; }
public String getItem(int i) { return items.get(i); }

// after
private String[] items;
public String[] getItems() { return items; }
public String getItem(int i) { return items[i]; }
Defensive patterns

Strategy: validation

Validate before calling

// Ensure non-indexed type is array with matching component when indexed accessors exist
Class<?> pt = nonIndexedRead.getReturnType();
Class<?> it = indexedRead.getReturnType();
if (pt != null && (!pt.isArray() || pt.componentType() != it)) {
    throw new IllegalStateException("non-indexed type must be " + it + "[]");
}

Type guard

static boolean indexedMatchesNonIndexed(Class<?> nonIndexedType, Class<?> indexedType) {
    return nonIndexedType == null || (nonIndexedType.isArray() && nonIndexedType.componentType() == indexedType);
}

Prevention

When it happens

Trigger: A bean has List<String> getItems() as the non-indexed getter plus String getItem(int) — List is not an array, so the isArray() check fails. Or String[] getItems() with Integer getItem(int) — component type mismatch.

Common situations: Wrapping an internal List but also providing positional indexed accessors; refactoring from arrays to List collections while leaving the indexed methods in place; code-generated beans mixing collection and array styles.

Related errors


AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09). Data as JSON: /api/errors/ec13175ee8889aa6. Report an issue: GitHub.

Appendix: source

Thrown at spring-beans/src/main/java/org/springframework/beans/PropertyDescriptorUtils.java:239

					// Write method's property type potentially more specific
					indexedPropertyType = params[1];
				}
				else if (params[1].isAssignableFrom(indexedPropertyType)) {
					// Proceed with read method's property type
				}
				else {
					throw new IntrospectionException("Type mismatch between indexed read and write methods: " +
							indexedReadMethod + " - " + indexedWriteMethod);
				}
			}
			else {
				indexedPropertyType = params[1];
			}
		}

		if (propertyType != null && (!propertyType.isArray() ||
				propertyType.componentType() != indexedPropertyType)) {
			throw new IntrospectionException("Type mismatch between indexed and non-indexed methods: " +
					indexedReadMethod + " - " + indexedWriteMethod);
		}

		return indexedPropertyType;
	}

	/**
	 * Compare the given {@code PropertyDescriptors} and return {@code true} if
	 * they are equivalent, i.e. their read method, write method, property type,
	 * property editor and flags are equivalent.
	 * @see java.beans.PropertyDescriptor#equals(Object)
	 */
	public static boolean equals(PropertyDescriptor pd, PropertyDescriptor otherPd) {
		return (ObjectUtils.nullSafeEquals(pd.getReadMethod(), otherPd.getReadMethod()) &&
				ObjectUtils.nullSafeEquals(pd.getWriteMethod(), otherPd.getWriteMethod()) &&
				ObjectUtils.nullSafeEquals(pd.getPropertyType(), otherPd.getPropertyType()) &&
				ObjectUtils.nullSafeEquals(pd.getPropertyEditorClass(), otherPd.getPropertyEditorClass()) &&
				pd.isBound() == otherPd.isBound() && pd.isConstrained() == otherPd.isConstrained());

View on GitHub (pinned to 69bf83ad71)