{"record":{"id":"449e24d9bca0421e","repo":"pinpoint-apm/pinpoint","slug":"unsupported-data-type-fieldname","errorCode":null,"errorMessage":"unsupported data type :<fieldName>","messagePattern":"unsupported data type :<fieldName>","errorType":"exception","errorClass":"ConfigurationException","httpStatus":null,"severity":"error","filePath":"commons-config/src/main/java/com/navercorp/pinpoint/common/config/util/ValueAnnotationProcessor.java","lineNumber":141,"sourceCode":"    private void setAccessible(AccessibleObject accessibleObject) {\n        if (!accessibleObject.isAccessible()) {\n            accessibleObject.setAccessible(true);\n        }\n    }\n\n    private void injectMethod(Method method, Object target, String value) {\n        final Class<?> parameterType = method.getParameterTypes()[0];\n\n        final Object parsedValue = parse(parameterType, value);\n        if (parsedValue != null) {\n            try {\n                setAccessible(method);\n                method.invoke(target, parsedValue);\n            } catch (ReflectiveOperationException e) {\n                throw new ConfigurationException(getFieldName(target, method) + \" access error\", e);\n            }\n        } else {\n            throw new ConfigurationException(\"unsupported data type :\" + getFieldName(target, method));\n        }\n    }\n\n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    private Object parse(Class<?> type, String value) {\n        if (type.isEnum()) {\n            return Enum.valueOf((Class<Enum>) type, value);\n        }\n\n        if (type == String.class) {\n            return value;\n        } else if (type == int.class || type == Integer.class) {\n            return Integer.parseInt(value);\n        } else if (type == long.class || type == Long.class) {\n            return Long.parseLong(value);\n        } else if (type == boolean.class || type == Boolean.class) {\n            return Boolean.parseBoolean(value);\n        } else if (type == double.class || type == Double.class) {","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/pinpoint-apm/pinpoint/blob/744c3d3075e595656abb1ae331ad2c0e4c9eb996/commons-config/src/main/java/com/navercorp/pinpoint/common/config/util/ValueAnnotationProcessor.java#L123-L159","documentation":"ValueAnnotationProcessor injects @Value-annotated properties into setter methods via reflection. After parsing the string value, parse() returns null only if the setter's single parameter type is not one of the supported types (String, primitives/wrappers, enum). The processor then throws ConfigurationException naming the target class.field so the developer knows which config property could not be injected.","triggerScenarios":"Calling ValueAnnotationProcessor.process(instance, resolver) (directly or via a config loader) where a @Value-annotated public/package setX(...) method with exactly one parameter takes an unsupported type such as java.util.List, java.util.Map, java.net.URL, or a custom POJO.","commonSituations":"Adding a new setter to a Pinpoint config class with a complex type (List/Map/array) instead of a String; refactoring a setter parameter from String to a typed object; copying Spring-style @Value usage assuming rich type conversion that this simple processor does not provide.","solutions":["Change the setter's parameter type to String, a primitive/wrapper, or an enum type supported by parse()","Parse the complex value inside the setter body from a String parameter","Remove the @Value annotation from the unsupported setter and initialize it manually in the constructor"],"exampleFix":"// before\n@Value(\"${collector.list}\")\npublic void setListeners(List<String> listeners) { ... }\n// after\n@Value(\"${collector.list}\")\npublic void setListeners(String listenersCsv) { this.listeners = Arrays.asList(listenersCsv.split(\",\")); }","handlingStrategy":"validation","validationCode":"Class<?> p = setter.getParameterTypes()[0];\nboolean ok = p == String.class || p.isEnum()\n    || p == int.class || p == Integer.class || p == long.class || p == Long.class\n    || p == boolean.class || p == Boolean.class || p == double.class || p == Double.class\n    || p == float.class || p == Float.class || p == short.class || p == Short.class\n    || p == byte.class || p == Byte.class || p == char.class || p == Character.class;\nif (!ok) throw new IllegalStateException(\"Unsupported @Value setter type: \" + p.getName());","typeGuard":null,"tryCatchPattern":"try {\n    processor.process(configInstance, resolver);\n} catch (ConfigurationException e) {\n    log.error(\"Config injection failed: {}\", e.getMessage(), e);\n    throw new IllegalArgumentException(\"Unsupported config property type\", e);\n}","preventionTips":["Restrict @Value-annotated setters to String, primitives/wrappers, char, and enum types","Parse complex types (List/Map/POJOs) inside the setter from a String","Write a unit test that runs process() on every config class at build time"],"tags":["java","reflection","configuration","unsupported-type"],"backgroundTag":"unsupported-config-value","analyzedSha":"744c3d3075e595656abb1ae331ad2c0e4c9eb996","analyzedAt":"2026-09-07T18:48:45.289Z","contentChangedAt":"2026-09-07T18:48:45.289Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}