{"record":{"id":"7795266dcd32003b","repo":"apache/pulsar","slug":"unsupported-field-type-s-for-s","errorCode":null,"errorMessage":"unsupported field-type %s for %s","messagePattern":"unsupported field-type (.+?) for (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-common/src/main/java/org/apache/pulsar/common/util/FieldParser.java","lineNumber":198,"sourceCode":"                return stringToList(strValue, clazz);\n            } else if (field.getType().equals(Set.class)) {\n                // covert to set\n                return stringToSet(strValue, clazz);\n            } else if (field.getType().equals(Map.class)) {\n                Class<?> valueClass =\n                    (Class<?>) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[1];\n                return stringToMap(strValue, clazz, valueClass);\n            } else if (field.getType().equals(Optional.class)) {\n                Type typeClazz = ((ParameterizedType) fieldType).getActualTypeArguments()[0];\n                if (typeClazz instanceof ParameterizedType) {\n                    throw new IllegalArgumentException(format(\"unsupported non-primitive Optional<%s> for %s\",\n                            typeClazz.getClass(), field.getName()));\n                }\n                @SuppressWarnings(\"unchecked\") // typeClazz is verified to be a non-parameterized Class\n                Optional<?> result = Optional.ofNullable(convert(strValue, (Class<?>) typeClazz));\n                return result;\n            } else {\n                throw new IllegalArgumentException(\n                        format(\"unsupported field-type %s for %s\", field.getType(), field.getName()));\n            }\n        } else {\n            return convert(strValue, field.getType());\n        }\n    }\n\n    /**\n     * Sets the empty/null value if field is allowed to be set empty.\n     *\n     * @param strValue\n     * @param field\n     * @param obj\n     * @throws IllegalArgumentException\n     * @throws IllegalAccessException\n     */\n    public static <T> void setEmptyValue(String strValue, Field field, T obj)\n            throws IllegalArgumentException, IllegalAccessException {","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-common/src/main/java/org/apache/pulsar/common/util/FieldParser.java#L180-L216","documentation":"FieldParser.value() only supports parameterized (generic) fields of type List, Set, Map, or Optional. Any other generic field type encountered while converting a non-blank string value throws IllegalArgumentException naming the field type and name.","triggerScenarios":"Calling update()/value() on a class with a generic field whose raw type is not List/Set/Map/Optional, e.g. Properties props field, custom Collection<E> subclass, or OptionalInt-style types, when the properties map has a non-blank value for it.","commonSituations":"Config classes holding java.util.Properties or custom collection fields populated from a properties map; adding a new collection type to a Pulsar config class that FieldParser was never taught about.","solutions":["Change the field to List<T>, Set<T>, Map<K,V>, or a simple type that convert() supports.","Parse the field manually and set it via direct assignment/setter instead of FieldParser.update().","Exclude the field from the properties map so update() never attempts to convert it."],"exampleFix":"// before\nprivate Properties extraProps; // unsupported field-type class java.util.Properties\n// after\nprivate Map<String, String> extraProps; // supported via stringToMap","handlingStrategy":"type-guard","validationCode":"static final Set<Class<?>> SUPPORTED_GENERIC = Set.of(List.class, Set.class, Map.class, Optional.class);\nstatic void checkGenericType(Field f) {\n    if (f.getGenericType() instanceof ParameterizedType && !SUPPORTED_GENERIC.contains(f.getType())) {\n        throw new IllegalArgumentException(\"unsupported field-type \" + f.getType() + \" for \" + f.getName());\n    }\n}","typeGuard":"static boolean isFieldParserSupported(Field f) {\n    if (!(f.getGenericType() instanceof ParameterizedType)) return true; // falls to convert()\n    return List.class.equals(f.getType()) || Set.class.equals(f.getType())\n            || Map.class.equals(f.getType()) || Optional.class.equals(f.getType());\n}","tryCatchPattern":"try {\n    return FieldParser.value(strValue, field);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().startsWith(\"unsupported field-type\")) {\n        return null; // or parse with Jackson manually\n    }\n    throw e;\n}","preventionTips":["Use only List, Set, Map, or Optional as generic field types in config classes","Use Map<String,String> instead of java.util.Properties","Avoid custom Collection subclasses in reflectively-populated POJOs","Unit-test update() over all fields of every config class"],"tags":["reflection","generics","configuration"],"backgroundTag":"unsupported-field-type","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}