{"record":{"id":"5eb97d561889d2d0","repo":"java-native-access/jna","slug":"unsupported-type-cls","errorCode":null,"errorMessage":"Unsupported type \" + cls","messagePattern":"Unsupported type \" \\+ cls","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/com/sun/jna/Structure.java","lineNumber":2266,"sourceCode":"                }\n            }\n            finally {\n                cacheStructureLock.writeLock().unlock();\n            }\n\n            if (NativeMapped.class.isAssignableFrom(cls)) {\n                NativeMappedConverter c = NativeMappedConverter.getInstance(cls);\n                return get(c.toNative(obj, new ToNativeContext()), c.nativeType());\n            }\n\n            if (cls.isArray()) {\n                FFIType type = new FFIType(obj, cls);\n                // Store it in the map to prevent premature GC of type info\n                storeTypeInfo(cls, Array.getLength(obj), type);\n                return type;\n            }\n\n            throw new IllegalArgumentException(\"Unsupported type \" + cls);\n        }\n\n        private static FFIType getTypeInfo(Class clazz, int elementCount) {\n            cacheStructureLock.readLock().lock();\n            try {\n                Map<Integer, FFIType> typeMap = typeInfoMap.get(clazz);\n                if (typeMap != null) {\n                    return typeMap.get(elementCount);\n                } else {\n                    return null;\n                }\n            }\n            finally {\n                cacheStructureLock.readLock().unlock();\n            }\n        }\n\n        private static void storeTypeInfo(Class clazz, FFIType type) {","sourceCodeStart":2248,"sourceCodeEnd":2284,"githubUrl":"https://github.com/java-native-access/jna/blob/d036ad9781adad4b66693e8fa7098e4ac665e0a3/src/com/sun/jna/Structure.java#L2248-L2284","documentation":"Structure.getTypeInfo(Object, Class) maps Java field values to libffi FFIType descriptors for a known set of types (primitives, boxed types, Pointer, String, WString, arrays, Structure, Callback, etc.). If the class is not one of the supported native-mappable types, it throws IllegalArgumentException with \"Unsupported type <cls>\".","triggerScenarios":"Declaring a Structure field of a type JNA cannot map to native memory (e.g. java.math.BigDecimal, java.util.Date, an arbitrary POJO, or an unsupported generic type) and then reading/writing the structure or calling Native.getNativeSize on it.","commonSituations":"Mapping a struct that contains a field type not supported by JNA (auto-boxed custom wrappers, Optional, collections), refactoring a field from a supported type to an unsupported one, or forgetting a TypeMapper/Structure.FieldOffset mapping for the field.","solutions":["Change the Structure field to a natively mappable type (int, long, double, boolean, byte/short/char, Pointer, String, WString, nested Structure, arrays, or ByReference variants)","If the field has a natural native representation, provide a custom TypeMapper (or @Structure.FieldOrder-safe mapper/ToNativeConverter) registered via Native.setTypeMapper or the Structure constructor","For complex data, flatten into supported primitives or pass as a nested Structure/Pointer with explicit marshalling","Check which field triggers it: the message names the exact class; compare against Structure.FFIType-supported types in the JNA docs"],"exampleFix":"// before\npublic class S extends Structure {\n    public BigDecimal amount; // Unsupported type java.math.BigDecimal\n}\n// after\npublic class S extends Structure {\n    public long amountCents; // map in application code\n}","handlingStrategy":"type-guard","validationCode":"// JNA-supported native-mappable field types (Java types usable directly in Structures)\nSet<Class<?>> NATIVE_TYPES = new HashSet<>(Arrays.asList(\n    boolean.class, byte.class, short.class, char.class, int.class,\n    long.class, float.class, double.class,\n    Boolean.class, Byte.class, Short.class, Character.class, Integer.class,\n    Long.class, Float.class, Double.class,\n    Pointer.class, String.class, WString.class));\nvoid checkFields(Class<?> s) {\n    for (Field f : s.getFields()) {\n        Class<?> t = f.getType();\n        if (!NATIVE_TYPES.contains(t) && !Structure.class.isAssignableFrom(t)\n            && !Callback.class.isAssignableFrom(t) && !t.isArray()\n            && !FromNativeConverter.class.isAssignableFrom(t)) {\n            throw new IllegalArgumentException(\"Field not natively mappable: \" + f);\n        }\n    }\n}","typeGuard":"boolean isNativeMappable(Class<?> t) {\n    return t.isPrimitive()\n        || Number.class.isAssignableFrom(t) || t == Boolean.class || t == Character.class\n        || t == Pointer.class || t == String.class || t == WString.class\n        || Structure.class.isAssignableFrom(t) || Callback.class.isAssignableFrom(t)\n        || t.isArray();\n}","tryCatchPattern":"try {\n    structure.read();\n} catch (IllegalArgumentException e) {\n    if (e.getMessage() != null && e.getMessage().startsWith(\"Unsupported type \")) {\n        throw new IllegalStateException(\"Replace/natively map field of type: \"\n            + e.getMessage().substring(\"Unsupported type \".length()), e);\n    }\n    throw e;\n}","preventionTips":["Only use primitives, boxed primitives, Pointer, String/WString, arrays, nested Structures, or Callbacks as Structure fields","Register a TypeMapper/ToNativeConverter for any custom field type","Run Native.getNativeSize(structureClass) in a unit test to catch unsupported fields early"],"tags":["jna","unsupported-type","structure","type-mapping"],"backgroundTag":"unsupported-dtype","analyzedSha":"d036ad9781adad4b66693e8fa7098e4ac665e0a3","analyzedAt":"2026-09-12T06:50:59.239Z","contentChangedAt":"2026-09-12T06:50:59.239Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}