{"record":{"id":"9328d84fb84d490b","repo":"spring-projects/spring-framework","slug":"write-method-must-have-exactly-1-or-2-parameters","errorCode":null,"errorMessage":"Write method must have exactly 1 or 2 parameters: {method}","messagePattern":"Write method must have exactly 1 or 2 parameters: (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"spring-beans/src/main/java/org/springframework/beans/ExtendedBeanInfo.java","lineNumber":184,"sourceCode":"\t\t\t\texistingPd.setWriteMethod(method);\n\t\t\t}\n\t\t}\n\t\telse if (nParams == 2) {\n\t\t\tif (existingPd == null) {\n\t\t\t\tthis.propertyDescriptors.add(\n\t\t\t\t\t\tnew SimpleIndexedPropertyDescriptor(propertyName, null, null, null, method));\n\t\t\t}\n\t\t\telse if (existingPd instanceof IndexedPropertyDescriptor indexedPd) {\n\t\t\t\tindexedPd.setIndexedWriteMethod(method);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthis.propertyDescriptors.remove(existingPd);\n\t\t\t\tthis.propertyDescriptors.add(new SimpleIndexedPropertyDescriptor(\n\t\t\t\t\t\tpropertyName, existingPd.getReadMethod(), existingPd.getWriteMethod(), null, method));\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tthrow new IllegalArgumentException(\"Write method must have exactly 1 or 2 parameters: \" + method);\n\t\t}\n\t}\n\n\tprivate @Nullable PropertyDescriptor findExistingPropertyDescriptor(String propertyName, Class<?> propertyType) {\n\t\tfor (PropertyDescriptor pd : this.propertyDescriptors) {\n\t\t\tfinal Class<?> candidateType;\n\t\t\tfinal String candidateName = pd.getName();\n\t\t\tif (pd instanceof IndexedPropertyDescriptor indexedPd) {\n\t\t\t\tcandidateType = indexedPd.getIndexedPropertyType();\n\t\t\t\tif (candidateName.equals(propertyName) &&\n\t\t\t\t\t\t(candidateType.equals(propertyType) || candidateType.equals(propertyType.componentType()))) {\n\t\t\t\t\treturn pd;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tcandidateType = pd.getPropertyType();\n\t\t\t\tif (candidateName.equals(propertyName) &&\n\t\t\t\t\t\t(candidateType.equals(propertyType) || propertyType.equals(candidateType.componentType()))) {","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/69bf83ad716d0cfc4b0520a19b4d8b24c79d1538/spring-beans/src/main/java/org/springframework/beans/ExtendedBeanInfo.java#L166-L202","documentation":"Thrown as IllegalArgumentException by ExtendedBeanInfo when a non-void-returning method treated as a 'write method' (setter) has a parameter count that is neither 1 (simple setter) nor 2 (indexed setter). ExtendedBeanInfo inspects setter-like methods during construction and rejects ones that do not match JavaBeans conventions.","triggerScenarios":"ExtendedBeanInfo is built over a BeanInfo; for each method it treats as a setter, if the parameter count is not 1 or 2 it throws. Typically triggered when a class has a method named setXxx with zero or 3+ parameters being picked up by the extended introspector.","commonSituations":"A class with an unconventional method like setFoo() with no args, setFoo(a, b, c), or a fluent builder setFoo(a, b) intended to be a setter but misinterpreted. Also seen with libraries that generate odd setter-shaped methods.","solutions":["Rename or remove the offending setXxx method so it has exactly 1 (simple) or 2 (indexed, first int) parameters.","Use a different method name prefix (e.g. withFoo) for fluent builders to avoid being treated as a setter.","If the class is from a third party, avoid passing it through Spring's ExtendedBeanInfo; isolate it."],"exampleFix":"// before\npublic void setItems(int i, String value, boolean flag) { ... }\n\n// after - conform to indexed-setter convention or rename\npublic void setItem(int i, String value) { ... }\n// or use a non-setter name\npublic Builder withItem(int i, String value) { ... }","handlingStrategy":"validation","validationCode":"// before exposing a class to ExtendedBeanInfo\nfor (Method m : cls.getMethods()) {\n    if (m.getName().startsWith(\"set\") && m.getName().length() > 3) {\n        int n = m.getParameterCount();\n        if (n != 1 && n != 2) {\n            throw new IllegalStateException(\"non-conformant setter: \" + m);\n        }\n    }\n}","typeGuard":"static boolean settersConform(Class<?> c) {\n    for (Method m : c.getMethods()) {\n        if (m.getName().startsWith(\"set\") && m.getName().length() > 3) {\n            int n = m.getParameterCount();\n            if (n != 1 && n != 2) return false;\n        }\n    }\n    return true;\n}","tryCatchPattern":null,"preventionTips":["Name fluent builder methods 'withXxx', not 'setXxx', to avoid setter detection.","Keep simple setters to 1 param and indexed setters to 2 (first int).","Add a unit test asserting no setXxx method has invalid arity for shared beans."],"tags":["extended-bean-info","introspection","javabeans","spring-beans"],"backgroundTag":null,"analyzedSha":"69bf83ad716d0cfc4b0520a19b4d8b24c79d1538","analyzedAt":"2026-08-09T15:32:58.770Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}