{"record":{"id":"e9d8c93324f235a1","repo":"flowable/flowable-engine","slug":"managedattribute-can-only-be-used-on-java-bean-me","errorCode":null,"errorMessage":"@ManagedAttribute can only be used on Java bean methods, was: ${method} on bean: ${managedClass}","messagePattern":"@ManagedAttribute can only be used on Java bean methods, was: (.+?) on bean: (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable-jmx/src/main/java/org/flowable/management/jmx/MBeanInfoAssembler.java","lineNumber":187,"sourceCode":"                continue;\r\n            }\r\n\r\n            LOGGER.trace(\"Extracting attributes and operations from method: {}\", method);\r\n            ManagedAttribute ma = method.getAnnotation(ManagedAttribute.class);\r\n            if (ma != null) {\r\n                String key;\r\n                String desc = ma.description();\r\n                Method getter = null;\r\n                Method setter = null;\r\n\r\n                if (ReflectUtil.isGetter(method)) {\r\n                    key = ReflectUtil.getGetterShorthandName(method);\r\n                    getter = method;\r\n                } else if (ReflectUtil.isSetter(method)) {\r\n                    key = ReflectUtil.getSetterShorthandName(method);\r\n                    setter = method;\r\n                } else {\r\n                    throw new IllegalArgumentException(\"@ManagedAttribute can only be used on Java bean methods, was: \" + method + \" on bean: \" + managedClass);\r\n                }\r\n\r\n                // they key must be capitalized\r\n                key = capitalize(key);\r\n\r\n                // lookup first\r\n                ManagedAttributeInfo info = attributes.get(key);\r\n                if (info == null) {\r\n                    info = new ManagedAttributeInfo(key, desc);\r\n                }\r\n                if (getter != null) {\r\n                    info.setGetter(getter);\r\n                }\r\n                if (setter != null) {\r\n                    info.setSetter(setter);\r\n                }\r\n\r\n                attributes.put(key, info);\r","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-jmx/src/main/java/org/flowable/management/jmx/MBeanInfoAssembler.java#L169-L205","documentation":"MBeanInfoAssembler processes methods annotated with @ManagedAttribute and requires them to be valid Java bean accessors: a getter (isX/getX) or a setter (setX). When an annotated method is neither, it throws IllegalArgumentException naming the offending method and the managed class.","triggerScenarios":"Annotating a method with @ManagedAttribute when it has a non-bean signature (wrong parameter/return shape, name not matching get/is/set conventions) so ReflectUtil.isGetter/isSetter both return false.","commonSituations":"Typos in accessor names (e.g. fetchValue instead of getValue); getters with parameters; setters with no parameter or non-void return; annotating utility methods by mistake when exposing Flowable services via JMX.","solutions":["Rename the annotated method to follow bean conventions (getX/isX for getters, setX for setters)","Ensure the getter has no parameters and a non-void return; ensure the setter takes exactly one parameter","Remove @ManagedAttribute from methods that are not bean properties and use @ManagedOperation instead if applicable","Check ReflectUtil.isGetter/isSetter expectations if using non-standard accessors"],"exampleFix":"// before\n@ManagedAttribute\ncurrentValue(Long v) { this.v = v; } // not a bean method\n// after\n@ManagedAttribute\npublic void setCurrentValue(Long v) { this.v = v; }","handlingStrategy":"validation","validationCode":"boolean isBeanAccessor(Method m) {\n    String n = m.getName();\n    boolean getter = (n.startsWith(\"get\") && m.getParameterCount() == 0 && m.getReturnType() != void.class)\n        || (n.startsWith(\"is\") && m.getParameterCount() == 0 && (m.getReturnType() == boolean.class || m.getReturnType() == Boolean.class));\n    boolean setter = n.startsWith(\"set\") && m.getParameterCount() == 1 && (m.getReturnType() == void.class || m.getReturnType() == m.getDeclaringClass());\n    return getter || setter;\n}\n// apply before annotating/processing: if (!isBeanAccessor(method)) throw ...","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only annotate get/is/set style methods with @ManagedAttribute","Getters must be no-arg with non-void return; setters one-arg","Use @ManagedOperation for methods that are not properties","Test JMX exposure of each managed bean at startup"],"tags":["jmx","annotations","flowable","reflection","bean-conventions"],"backgroundTag":"invalid-argument-value","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}