spring-projects/spring-framework · error · IllegalArgumentException

Write method must have exactly 1 or 2 parameters: ${method}

Error message

Write method must have exactly 1 or 2 parameters: ${method}

What it means

IllegalArgumentException thrown by ExtendedBeanInfo when it encounters a method named like a setter (setX) whose parameter count is neither 1 (simple property) nor 2 (indexed property). ExtendedBeanInfo is the lenient BeanInfo implementation Spring uses when the class fails standard java.beans.Introspector rules; a setter with 0 or 3+ params violates even that leniency.

Source

Thrown at spring-beans/src/main/java/org/springframework/beans/ExtendedBeanInfo.java:184

				existingPd.setWriteMethod(method);
			}
		}
		else if (nParams == 2) {
			if (existingPd == null) {
				this.propertyDescriptors.add(
						new SimpleIndexedPropertyDescriptor(propertyName, null, null, null, method));
			}
			else if (existingPd instanceof IndexedPropertyDescriptor indexedPd) {
				indexedPd.setIndexedWriteMethod(method);
			}
			else {
				this.propertyDescriptors.remove(existingPd);
				this.propertyDescriptors.add(new SimpleIndexedPropertyDescriptor(
						propertyName, existingPd.getReadMethod(), existingPd.getWriteMethod(), null, method));
			}
		}
		else {
			throw new IllegalArgumentException("Write method must have exactly 1 or 2 parameters: " + method);
		}
	}

	private @Nullable PropertyDescriptor findExistingPropertyDescriptor(String propertyName, Class<?> propertyType) {
		for (PropertyDescriptor pd : this.propertyDescriptors) {
			final Class<?> candidateType;
			final String candidateName = pd.getName();
			if (pd instanceof IndexedPropertyDescriptor indexedPd) {
				candidateType = indexedPd.getIndexedPropertyType();
				if (candidateName.equals(propertyName) &&
						(candidateType.equals(propertyType) || candidateType.equals(propertyType.componentType()))) {
					return pd;
				}
			}
			else {
				candidateType = pd.getPropertyType();
				if (candidateName.equals(propertyName) &&
						(candidateType.equals(propertyType) || propertyType.equals(candidateType.componentType()))) {

View on GitHub (pinned to e8729d0438)

Solutions

  1. Rename the method so it does not look like a setter (does not start with 'set').
  2. If it must keep the name, give it exactly 1 (simple) or 2 (int-indexed) parameters.
  3. Force standard IntrospectionResults by avoiding the ExtendedBeanInfoFactory SPI registration if the class is incompatible.
  4. Exclude the method from introspection by making it non-public if it is internal.

Example fix

// before
public void setStatus(String code, String reason, long ts) { ... }  // 3-arg 'setter'

// after
public void recordStatus(String code, String reason, long ts) { ... }
Defensive patterns

Strategy: validation

Validate before calling

// Scan candidate setter methods before introspection
for (Method m : MyClass.class.getMethods()) {
    if (m.getName().startsWith("set") && m.getName().length() > 3) {
        int n = m.getParameterCount();
        if (n != 1 && n != 2) {
            throw new IllegalStateException("Suspicious setter arity: " + m);
        }
    }
}

Type guard

static boolean hasOnlyValidSetterArities(Class<?> c) {
    for (Method m : c.getMethods()) {
        if (m.getName().startsWith("set") && m.getName().length() > 3) {
            int n = m.getParameterCount();
            if (n != 1 && n != 2) return false;
        }
    }
    return true;
}

Try / catch

try {
    return new ExtendedBeanInfo(clazz).getPropertyDescriptors();
} catch (IllegalArgumentException ex) {
    if (ex.getMessage().startsWith("Write method must have exactly 1 or 2 parameters")) {
        // log the offending method and fall back to standard Introspector
        return java.beans.Introspector.getBeanInfo(clazz).getPropertyDescriptors();
    }
    throw ex;
}

Prevention

When it happens

Trigger: Spring selecting ExtendedBeanInfo as the introspector (via ExtendedBeanInfoFactory) for a class whose setX method was given an unusual arity, e.g. setFoo() with no args, setFoo(a,b,c), or an overloaded setFoo(int, String, boolean).

Common situations: A method named setX for a reason other than property setting (e.g. configuration helper); overloaded setter that breaks JavaBean conventions; reflective code-generators producing method names beginning with 'set' that aren't actually setters.

Related errors


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