{"record":{"id":"dd5e6a0d82f2709c","repo":"flowable/flowable-engine","slug":"not-allowed-to-access-method-settername-on-clas","errorCode":null,"errorMessage":"Not allowed to access method ${setterName} on class ${clazz.getCanonicalName()}","messagePattern":"Not allowed to access method (.+?) on class (.+?)","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/util/ReflectUtil.java","lineNumber":246,"sourceCode":"     * Returns the setter-method for the given field name or null if no setter exists.\n     */\n    public static Method getSetter(String fieldName, Class<?> clazz, Class<?> fieldType) {\n        String setterName = \"set\" + Character.toTitleCase(fieldName.charAt(0)) + fieldName.substring(1);\n        try {\n            // Using getMethods(), getMethod(...) expects exact parameter type\n            // matching and ignores inheritance-tree.\n            Method[] methods = clazz.getMethods();\n            for (Method method : methods) {\n                if (method.getName().equals(setterName)) {\n                    Class<?>[] paramTypes = method.getParameterTypes();\n                    if (paramTypes != null && paramTypes.length == 1 && paramTypes[0].isAssignableFrom(fieldType)) {\n                        return method;\n                    }\n                }\n            }\n            return null;\n        } catch (SecurityException e) {\n            throw new FlowableException(\"Not allowed to access method \" + setterName + \" on class \" + clazz.getCanonicalName(), e);\n        }\n    }\n    \n    public static void invokeSetter(Method setterMethod, Object target, String name, Object value) {\n        try {\n            setterMethod.invoke(target, value);\n        } catch (IllegalArgumentException e) {\n            throw new FlowableException(\"Error while invoking '\" + name + \"' on class \" + target.getClass().getName(), e);\n        } catch (IllegalAccessException e) {\n            throw new FlowableException(\"Illegal access when calling '\" + name + \"' on class \" + target.getClass().getName(), e);\n        } catch (InvocationTargetException e) {\n            throw new FlowableException(\"Exception while invoking '\" + name + \"' on class \" + target.getClass().getName(), e);\n        }\n    }\n\n    private static Method findMethod(Class<? extends Object> clazz, String methodName, Object[] args) {\n        for (Method method : clazz.getDeclaredMethods()) {\n            // TODO add parameter matching","sourceCodeStart":228,"sourceCodeEnd":264,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/util/ReflectUtil.java#L228-L264","documentation":"ReflectUtil.getSetter scans a class's methods for a setter matching the given name and value type. If the JVM SecurityManager throws SecurityException during method inspection, it throws this FlowableException naming the setter and class.","triggerScenarios":"Calling getSetter (directly or via invokeSetterOrField / Flowable field injection with setter preference) when a SecurityManager or module access rules deny reflective enumeration/access of the class's declared methods.","commonSituations":"Strict SecurityManager policies in application servers; reflecting into module-encapsulated or sealed classes on modern JDKs; sandboxed/agent environments restricting setAccessible-equivalent access.","solutions":["Grant ReflectPermission (suppressAccessChecks) in your security policy.","Avoid targeting JDK/module-encapsulated classes; use --add-opens for module boundaries you control.","Add a proper public setter to the target class so standard access works without privileged reflection.","Use field injection instead of setter injection if setters are inaccessible.","Run without a restrictive SecurityManager where the platform permits."],"exampleFix":"// before\n// class has only package-private setter\nvoid setRecipient(String r) { ... }\n// after\npublic void setRecipient(String r) { this.recipient = r; }","handlingStrategy":"validation","validationCode":"boolean hasSetter = java.util.Arrays.stream(clazz.getMethods())\n    .anyMatch(m -> m.getName().equalsIgnoreCase(\"set\" + setterName) && m.getParameterCount() == 1);\nif (!hasSetter) throw new IllegalStateException(\"No public setter \" + setterName + \" on \" + clazz.getName());","typeGuard":null,"tryCatchPattern":"try {\n    Method m = ReflectUtil.getSetter(setterName, clazz, valueType);\n} catch (FlowableException e) {\n    LOGGER.error(\"Setter {} blocked on {}: {}\", setterName, clazz.getName(), e.getCause());\n    throw new SecurityConfigurationException(\"Grant ReflectPermission or add a public setter\", e);\n}","preventionTips":["Always provide public setters for injected properties","Audit SecurityManager policies before upgrading JDK or app server","Avoid sealed/module-encapsulated classes as injection targets","Prefer constructor/field injection when setters are restricted"],"tags":["reflection","security","setter","java"],"backgroundTag":"permission-denied","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-18T11:17:12.947Z"}