{"record":{"id":"7a37462384f290aa","repo":"java-native-access/jna","slug":"callback-type-must-be-an-interface","errorCode":null,"errorMessage":"Callback type must be an interface","messagePattern":"Callback type must be an interface","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/com/sun/jna/CallbackReference.java","lineNumber":160,"sourceCode":"\n    /** Return a Callback associated with the given function pointer.\n     * If the pointer refers to a Java callback trampoline, return the original\n     * Java Callback.  Otherwise, return a proxy to the native function\n     * pointer.\n     * @throws IllegalStateException if the given pointer has already been\n     * mapped to a callback of a different type.\n     */\n    public static Callback getCallback(Class<?> type, Pointer p) {\n        return getCallback(type, p, false);\n    }\n\n    private static Callback getCallback(Class<?> type, Pointer p, boolean direct) {\n        if (p == null) {\n            return null;\n        }\n\n        if (!type.isInterface())\n            throw new IllegalArgumentException(\"Callback type must be an interface\");\n        Map<Callback, CallbackReference> map = direct ? directCallbackMap : callbackMap;\n        synchronized(pointerCallbackMap) {\n            Reference<Callback>[] array = pointerCallbackMap.get(p);\n            Callback cb = getTypeAssignableCallback(type, array);\n            if (cb != null) {\n                return cb;\n            }\n            cb = createCallback(type, p);\n            pointerCallbackMap.put(p, addCallbackToArray(cb,array));\n\n            // No CallbackReference for this callback\n            map.remove(cb);\n            return cb;\n        }\n    }\n\n    private static Callback getTypeAssignableCallback(Class<?> type, Reference<Callback>[] array) {\n        if (array != null) {","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/java-native-access/jna/blob/d036ad9781adad4b66693e8fa7098e4ac665e0a3/src/com/sun/jna/CallbackReference.java#L142-L178","documentation":"IllegalArgumentException thrown by CallbackReference.getCallback(Class, Pointer, boolean) when an existing native Pointer is being re-associated with a callback, but the given Class is not an interface. JNA callbacks must be declared as interfaces (extending com.sun.jna.Callback) because JNA generates a dynamic proxy that implements them; a concrete class cannot be proxied this way.","triggerScenarios":"Calling CallbackReference.getCallback(type, pointer) — e.g. via Native.getCallback or during structure-to-callback conversion — with a Class object that is a concrete class (or abstract class) rather than an interface, typically obtained via getClass() instead of the callback interface.","commonSituations":"Passing obj.getClass() of a class that implements a callback instead of the interface Class; defining a callback as an abstract class implementing Callback and calling native code with it; library utilities re-mapping pointers to callbacks using the wrong Class object.","solutions":["Declare the callback as an interface that extends com.sun.jna.Callback and pass that interface's Class (e.g. MyCallback.class), not the implementing object's class.","If you have an instance, get the interface via a helper that finds the Callback-derived interface (JNA's findCallbackClass logic) instead of using obj.getClass().","Convert abstract-class callbacks to interface-based declarations, with the implementation as a separate class or anonymous class."],"exampleFix":"// before\nclass MyHandler implements MyCallback { public void callback(Object[] args) {} }\nCallback cb = CallbackReference.getCallback(handler.getClass(), ptr); // IllegalArgumentException\n// after\ninterface MyHandler extends Callback { void callback(Object[] args); }\nCallback cb = CallbackReference.getCallback(MyHandler.class, ptr);","handlingStrategy":"type-guard","validationCode":"static void requireCallbackInterface(Class<?> t) {\n    if (t == null || !t.isInterface() || !Callback.class.isAssignableFrom(t))\n        throw new IllegalArgumentException(t + \" must be an interface extending Callback\");\n}","typeGuard":"static boolean isCallbackInterface(Class<?> t) {\n    return t != null && t.isInterface() && Callback.class.isAssignableFrom(t);\n}","tryCatchPattern":"try { cb = CallbackReference.getCallback(type, ptr); } catch (IllegalArgumentException e) { throw new IllegalArgumentException(\"Pass the callback INTERFACE class, not the impl class\", e); }","preventionTips":["Always declare callbacks as interfaces extending com.sun.jna.Callback.","Never pass getClass(); pass the interface Class literal.","Avoid abstract-class callbacks; refactor to interfaces.","Enable IDE linting for JNA callback declarations."],"tags":["jna","callback","interface","type-mismatch"],"backgroundTag":"type-mismatch","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"}