{"id":"1859efdc4553bb6a","repo":"spring-projects/spring-framework","slug":"type-mismatch-between-read-and-write-methods-re","errorCode":null,"errorMessage":"Type mismatch between read and write methods: ${readMethod} - ${writeMethod}","messagePattern":"Type mismatch between read and write methods: (.+?) - (.+?)","errorType":"exception","errorClass":"IntrospectionException","httpStatus":null,"severity":"error","filePath":"spring-beans/src/main/java/org/springframework/beans/PropertyDescriptorUtils.java","lineNumber":177,"sourceCode":"\t\t\t\tthrow new IntrospectionException(\"Read method returns void: \" + readMethod);\n\t\t\t}\n\t\t}\n\n\t\tif (writeMethod != null) {\n\t\t\tClass<?>[] params = writeMethod.getParameterTypes();\n\t\t\tif (params.length != 1) {\n\t\t\t\tthrow new IntrospectionException(\"Bad write method arg count: \" + writeMethod);\n\t\t\t}\n\t\t\tif (propertyType != null) {\n\t\t\t\tif (propertyType.isAssignableFrom(params[0])) {\n\t\t\t\t\t// Write method's property type potentially more specific\n\t\t\t\t\tpropertyType = params[0];\n\t\t\t\t}\n\t\t\t\telse if (params[0].isAssignableFrom(propertyType)) {\n\t\t\t\t\t// Proceed with read method's property type\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthrow new IntrospectionException(\n\t\t\t\t\t\t\t\"Type mismatch between read and write methods: \" + readMethod + \" - \" + writeMethod);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tpropertyType = params[0];\n\t\t\t}\n\t\t}\n\n\t\treturn propertyType;\n\t}\n\n\t/**\n\t * See {@link java.beans.IndexedPropertyDescriptor#findIndexedPropertyType}.\n\t */\n\tpublic static @Nullable Class<?> findIndexedPropertyType(String name, @Nullable Class<?> propertyType,\n\t\t\t@Nullable Method indexedReadMethod, @Nullable Method indexedWriteMethod) throws IntrospectionException {\n\n\t\tClass<?> indexedPropertyType = null;","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/e8729d043887bf0d0baf91e062e909b56eb2b708/spring-beans/src/main/java/org/springframework/beans/PropertyDescriptorUtils.java#L159-L195","documentation":"IntrospectionException from PropertyDescriptorUtils.findPropertyType when the read method's return type and the write method's single parameter type are mutually non-assignable. The JavaBean contract requires the setter argument to be compatible with the getter return; if neither is assignable to the other, the descriptor has an inconsistent type and cannot be built.","triggerScenarios":"A property where getX() returns type A and setX(B) takes type B with A and B unrelated (neither isAssignableFrom the other). Surfaces during introspection of classes whose accessors were edited inconsistently.","commonSituations":"Refactor changed the getter return type but not the setter parameter (or vice versa); copy-paste of an accessor pattern with the wrong type; covariant return on getter not reflected in setter; Lombok @Accessors(fluent=true) plus a hand-written setter with a different type.","solutions":["Align getter return type and setter parameter type to the same property type.","If a more specific setter is intended, ensure the setter param is assignable from the getter return.","Regenerate Lombok-generated accessors and remove conflicting hand-written ones."],"exampleFix":"// before\npublic Number getValue() { ... }\npublic void setValue(String v) { ... }  // String not assignable to/from Number\n\n// after\npublic Number getValue() { ... }\npublic void setValue(Number v) { ... }","handlingStrategy":"type-guard","validationCode":"static void assertReadWriteTypesMatch(Method readMethod, Method writeMethod) {\n    Class<?> rt = readMethod.getReturnType();\n    Class<?> wt = writeMethod.getParameterTypes()[0];\n    if (!rt.isAssignableFrom(wt) && !wt.isAssignableFrom(rt)) {\n        throw new IllegalStateException(\"Getter returns \" + rt + \" but setter takes \" + wt);\n    }\n}","typeGuard":"static boolean accessorsTypeCompatible(Method readMethod, Method writeMethod) {\n    Class<?> rt = readMethod.getReturnType();\n    Class<?> wt = writeMethod.getParameterTypes()[0];\n    return rt.isAssignableFrom(wt) || wt.isAssignableFrom(rt);\n}","tryCatchPattern":"try {\n    return new PropertyDescriptor(name, readMethod, writeMethod);\n} catch (java.beans.IntrospectionException ex) {\n    if (ex.getMessage().startsWith(\"Type mismatch between read and write\")) {\n        log.error(\"Fix accessor pair: getter returns {} setter takes {}\",\n            readMethod.getReturnType(), writeMethod.getParameterTypes()[0]);\n    }\n    throw ex;\n}","preventionTips":["Keep getter return type and setter parameter type identical (or one assignable to the other).","When refactoring a property type, update both accessors in the same commit.","Regenerate Lombok/IDE accessors after type changes."],"tags":["property-descriptor","introspection","type-mismatch","spring-beans"],"analyzedSha":"e8729d043887bf0d0baf91e062e909b56eb2b708","analyzedAt":"2026-08-04T19:07:39.725Z","schemaVersion":2}