spring-projects/spring-framework · error · IntrospectionException

Type mismatch between indexed and non-indexed methods: ${ind

Error message

Type mismatch between indexed and non-indexed methods: ${indexedReadMethod} - ${indexedWriteMethod}

What it means

IntrospectionException from PropertyDescriptorUtils.findIndexedPropertyType when a non-indexed property type is supplied alongside indexed accessors and they disagree. Specifically: the non-indexed propertyType exists, is not an array, OR is an array but its component type differs from the indexed element type. The JavaBean model expects an indexed property to be backed by an array-typed simple property of the same component type.

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 e8729d0438)

Solutions

  1. Make the non-indexed property type an array whose component type equals the indexed element type (e.g. String[] backing String get(int)/set(int,String)).
  2. If you want collection semantics, drop the indexed accessors and use a single collection-typed property.
  3. Ensure consistency between simple and indexed accessors when constructing the descriptor.

Example fix

// before: simple type List<String>, indexed returns String
new IndexedPropertyDescriptor("items",
    /*read*/ getItemsMethod, /*write*/ setItemsMethod,
    /*idxRead*/ getItemIntMethod, /*idxWrite*/ setItemIntMethod);
// getItems() returns List<String> -> mismatch

// after: simple type String[] backing indexed String accessors
private String[] items;
public String[] getItems() { return items; }
public void setItems(String[] items) { this.items = items; }
public String getItems(int i) { return items[i]; }
public void setItems(int i, String v) { items[i] = v; }
Defensive patterns

Strategy: type-guard

Validate before calling

static void assertIndexedMatchesNonIndexed(Class<?> propertyType, Method r, Method w) {
    Class<?> elem = r != null ? r.getReturnType() : (w != null ? w.getParameterTypes()[1] : null);
    if (propertyType != null && elem != null) {
        if (!propertyType.isArray() || propertyType.componentType() != elem) {
            throw new IllegalStateException(
                "Non-indexed type " + propertyType + " must be " + elem + "[]");
        }
    }
}

Type guard

static boolean indexedBackedByArrayOfElement(Class<?> propertyType, Class<?> elementType) {
    return propertyType == null || (propertyType.isArray() && propertyType.componentType() == elementType);
}

Try / catch

try {
    return new IndexedPropertyDescriptor(name, readMethod, writeMethod, idxRead, idxWrite);
} catch (java.beans.IntrospectionException ex) {
    if (ex.getMessage().startsWith("Type mismatch between indexed and non-indexed")) {
        log.error("Simple accessors must use an array of the indexed element type");
        // drop the non-indexed pair and rebuild as indexed-only
        return new IndexedPropertyDescriptor(name, null, null, idxRead, idxWrite);
    }
    throw ex;
}

Prevention

When it happens

Trigger: Calling findIndexedPropertyType with a non-null propertyType that is not an array of the indexed element type - e.g. propertyType=List<String> while indexed accessors return String, or propertyType=String[] while indexed accessors return Integer.

Common situations: An IndexedPropertyDescriptor built where the simple getter/setter pair uses a collection type instead of an array; mixed array/collection accessor pairs on the same property; refactors that changed the backing type from array to List without removing indexed accessors.

Related errors


AI-assisted analysis of spring-projects/spring-framework@e8729d0438 (2026-08-04). Data as JSON: /data/errors/6120254280e70c14.json. Report an issue: GitHub.