{"record":{"id":"af7baa22b0c55346","repo":"java-native-access/jna","slug":"structures-require-bidirectional-type-conversion-for-type","errorCode":null,"errorMessage":"Structures require bidirectional type conversion for \" + type","messagePattern":"Structures require bidirectional type conversion for \" \\+ type","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/com/sun/jna/Structure.java","lineNumber":1419,"sourceCode":"                nativeType = tc.nativeType();\n                structField.writeConverter = tc;\n                structField.readConverter = tc;\n                structField.context = new StructureReadContext(this, field);\n            }\n            else if (typeMapper != null) {\n                ToNativeConverter writeConverter = typeMapper.getToNativeConverter(type);\n                FromNativeConverter readConverter = typeMapper.getFromNativeConverter(type);\n                if (writeConverter != null && readConverter != null) {\n                    value = writeConverter.toNative(value,\n                                                    new StructureWriteContext(this, structField.field));\n                    nativeType = value != null ? value.getClass() : Pointer.class;\n                    structField.writeConverter = writeConverter;\n                    structField.readConverter = readConverter;\n                    structField.context = new StructureReadContext(this, field);\n                }\n                else if (writeConverter != null || readConverter != null) {\n                    String msg = \"Structures require bidirectional type conversion for \" + type;\n                    throw new IllegalArgumentException(msg);\n                }\n            }\n\n            if (value == null) {\n                value = initializeField(structField.field, type);\n            }\n\n            try {\n                structField.size = getNativeSize(nativeType, value);\n                fieldAlignment = getNativeAlignment(nativeType, value, firstField);\n            }\n            catch(IllegalArgumentException e) {\n                // Might simply not yet have a type mapper set yet\n                if (!force && typeMapper == null) {\n                    return null;\n                }\n                String msg = \"Invalid Structure field in \" + getClass() + \", field name '\" + structField.name + \"' (\" + structField.type + \"): \" + e.getMessage();\n                throw new IllegalArgumentException(msg, e);","sourceCodeStart":1401,"sourceCodeEnd":1437,"githubUrl":"https://github.com/java-native-access/jna/blob/d036ad9781adad4b66693e8fa7098e4ac665e0a3/src/com/sun/jna/Structure.java#L1401-L1437","documentation":"When a TypeMapper supplies only a one-way converter (toNative or fromNative) but not both, JNA cannot round-trip the field value between Java and native memory. Structures need bidirectional conversion, so IllegalArgumentException is thrown naming the type.","triggerScenarios":"Setting a TypeMapper whose FromNativeConverter or ToNativeConverter covers a type but not the reverse direction, then calculating layout/writing a Structure field of that type.","commonSituations":"Custom mappers written for serialization only (toNative) and reused for structures; combining multiple mappers where one side's registry misses a type; third-party TypeMapper implementations that only implement one converter interface.","solutions":["Implement a TypeMapper whose getToNativeConverter and getFromNativeConverter both return converters for the field type","If the field is genuinely read-only in native terms, use a Pointer or raw type and read manually instead of a one-way mapper","Verify the mapper's registry includes the exact Java type (and its subclasses) on both sides"],"exampleFix":"// before\nmapper.getToNativeConverter(...); // only toNative registered\n// after\nclass MyMapper implements TypeMapper {\n    public ToNativeConverter getToNativeConverter(Class<?> c) { ... }\n    public FromNativeConverter getFromNativeConverter(Class<?> c) { ... } // both directions\n}","handlingStrategy":"validation","validationCode":"TypeMapper m = ...;\nfor (Class<?> t : mappedFieldTypes) {\n    if (m.getToNativeConverter(t) == null || m.getFromNativeConverter(t) == null) {\n        throw new IllegalStateException(\"Converter not bidirectional for \" + t);\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    s.size();\n} catch (IllegalArgumentException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"bidirectional\")) {\n        throw new IllegalStateException(\"Register both to/from converters for \" + e.getMessage(), e);\n    }\n    throw e;\n}","preventionTips":["Always implement both converter directions in a TypeMapper","Test mappers by round-tripping each mapped type","Reuse existing mappers known to be bidirectional","Document single-direction mappers as unsuitable for Structures"],"tags":["jna","structure","type-mapper","conversion"],"backgroundTag":"incompatible-source-type","analyzedSha":"d036ad9781adad4b66693e8fa7098e4ac665e0a3","analyzedAt":"2026-09-12T06:50:59.239Z","contentChangedAt":"2026-09-12T06:50:59.239Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}