java-native-access/jna · error · IllegalArgumentException

Callback must implement a single public method, or one publi

Error message

Callback must implement a single public method, or one public method named 'callback'

What it means

IllegalArgumentException thrown by CallbackReference.getCallbackMethod when it cannot determine which method of the callback interface is the native callback entry point. JNA requires the interface to declare exactly one public method, or (if multiple) one named 'callback' (Callback.METHOD_NAME). Otherwise the mapping from Java method to native trampoline is ambiguous and registration fails.

Source

Thrown at src/com/sun/jna/CallbackReference.java:427

            Method m = i.next();
            if (Callback.FORBIDDEN_NAMES.contains(m.getName())) {
                i.remove();
            }
        }

        Method[] methods = pmethods.toArray(new Method[0]);
        if (methods.length == 1) {
            return checkMethod(methods[0]);
        }
        for (int i=0;i < methods.length;i++) {
            Method m = methods[i];
            if (Callback.METHOD_NAME.equals(m.getName())) {
                return checkMethod(m);
            }
        }
        String msg = "Callback must implement a single public method, "
            + "or one public method named '" + Callback.METHOD_NAME + "'";
        throw new IllegalArgumentException(msg);
    }

    /** Set the behavioral options for this callback. */
    private void setCallbackOptions(int options) {
        cbstruct.setInt(Native.POINTER_SIZE, options);
    }

    /** Obtain a pointer to the native glue code for this callback. */
    public Pointer getTrampoline() {
        if (trampoline == null) {
            trampoline = cbstruct.getPointer(0);
        }
        return trampoline;
    }

    /** Free native resources associated with this callback. */
    public void close() {
        if (cleanable != null) {

View on GitHub (pinned to d036ad9781)

Solutions

  1. Keep callback interfaces to exactly one abstract public method (a functional-interface shape), or
  2. If multiple methods exist, name the native entry point 'callback' (void callback(Object[] args) style) so JNA can disambiguate.
  3. Move helper/default methods out of the interface or make them non-public/static; verify with 'javap' or IDE outline that only one public method (or one named 'callback') remains.

Example fix

// before
interface Cb extends Callback {
  void invoke(int code);
  void log(String s); // second public method -> ambiguous
}
// after
interface Cb extends Callback { void invoke(int code); }
// or
interface Cb2 extends Callback { void callback(Object[] args); }
Defensive patterns

Strategy: validation

Validate before calling

static void checkSinglePublicMethod(Class<?> cbType) {
    long count = java.util.Arrays.stream(cbType.getMethods())
        .filter(m -> !m.isSynthetic() && !m.getDeclaringClass().equals(Object.class))
        .filter(m -> m.getName().equals(Callback.METHOD_NAME))
        .count();
    // require exactly one 'callback' method or a single public method total
}

Type guard

static boolean hasDisambiguatedCallback(Class<?> t) {
    Method[] ms = t.getMethods();
    long named = Arrays.stream(ms).filter(m -> m.getName().equals(Callback.METHOD_NAME)).count();
    return named == 1 || Arrays.stream(ms)
        .filter(m -> m.getDeclaringClass() != Object.class && !m.isSynthetic()).count() == 1;
}

Try / catch

try { registerCallback(cb); } catch (IllegalArgumentException e) { if (e.getMessage().contains("single public method")) { /* reduce to one method or rename to 'callback' */ } throw e; }

Prevention

When it happens

Trigger: Registering a callback interface that: declares zero public methods; declares multiple public methods with none named 'callback'; implements several inherited public methods (e.g. extends two interfaces each adding a public method); relies on a method named something other than 'callback' while other public methods exist (e.g. toString-style helpers, Comparable-style methods inherited).

Common situations: Callback interfaces extending other interfaces (adding public default/abstract methods) so more than one public method exists; adding a second helper method to a working single-method callback; lambdas/functions objects whose interface has multiple public members.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12). Data as JSON: /api/errors/1175d1c1961eec19. Report an issue: GitHub.