java-native-access/jna · error · com.sun.jna.platform.win32.COM.COMException

advise: Interface must define a value for either iid via the

Error message

advise: Interface must define a value for either iid via the ComInterface annotation

What it means

CallbackProxy.createRIID resolves the IID of a COM event callback interface by reading its @ComInterface annotation; if the annotation is absent it throws this COMException. The proxy needs the interface's GUID (IID) to Advise/Unadvise event sinks and cannot proceed without it.

Source

Thrown at contrib/platform/src/com/sun/jna/platform/win32/COM/util/CallbackProxy.java:92

        this.factory = factory;
        this.comEventCallbackInterface = comEventCallbackInterface;
        this.comEventCallbackListener = comEventCallbackListener;
        this.listenedToRiid = this.createRIID(comEventCallbackInterface);
        this.dsipIdMap = this.createDispIdMap(comEventCallbackInterface);
        this.dispatchListener = new DispatchListener(this);
    }

    ObjectFactory factory;
    Class<?> comEventCallbackInterface;
    IComEventCallbackListener comEventCallbackListener;
    REFIID listenedToRiid;
    public DispatchListener dispatchListener;
    Map<DISPID, Method> dsipIdMap;

    private REFIID createRIID(Class<?> comEventCallbackInterface) {
        ComInterface comInterfaceAnnotation = comEventCallbackInterface.getAnnotation(ComInterface.class);
        if (null == comInterfaceAnnotation) {
            throw new COMException(
                    "advise: Interface must define a value for either iid via the ComInterface annotation");
        }
        String iidStr = comInterfaceAnnotation.iid();
        if (null == iidStr || iidStr.isEmpty()) {
            throw new COMException("ComInterface must define a value for iid");
        }
        return new REFIID(new IID(iidStr).getPointer());
    }

    @SuppressWarnings("deprecation") // ComEventCallback is used here to be backwards compatible
    private Map<DISPID, Method> createDispIdMap(Class<?> comEventCallbackInterface) {
        Map<DISPID, Method> map = new HashMap<>();

        for (Method meth : comEventCallbackInterface.getMethods()) {
            ComEventCallback callbackAnnotation = meth.getAnnotation(ComEventCallback.class);
            ComMethod methodAnnotation = meth.getAnnotation(ComMethod.class);
            if (methodAnnotation != null) {
                int dispId = methodAnnotation.dispId();

View on GitHub (pinned to d036ad9781)

Solutions

  1. Annotate the event callback interface with @ComInterface(iid="{GUID}")
  2. Ensure the correct guid attribute (iid) is present, matching the type library
  3. Rebuild so the annotation is actually compiled onto the interface passed to advise
  4. If the interface already has @ComObject (for createObject), note advise needs @ComInterface instead

Example fix

// before
public interface IDocumentEvents extends IComEventCallbackListener { ... }
// after
@ComInterface(iid = "{A3B2C1D0-1234-5678-9ABC-DEF012345678}")
public interface IDocumentEvents extends IComEventCallbackListener { ... }
Defensive patterns

Strategy: validation

Validate before calling

if (iface.getAnnotation(ComInterface.class) == null)
    throw new IllegalArgumentException(iface.getName() + " needs @ComInterface before advising events");

Try / catch

try { factory.addEventListener(iface, method, listener); } catch (COMException e) { if (e.getMessage().contains("ComInterface annotation")) { /* fix annotation */ } }

Prevention

When it happens

Trigger: Passing a callback interface (annotated only with @ComEventCallback or none at all, not @ComInterface) to ObjectFactory.addEventListener / CallbackProxy construction; renaming or deleting the @ComInterface annotation during refactoring.

Common situations: Hand-writing a COM event interface and forgetting the annotation; moving an interface between packages so an annotation import is lost; migrating from the deprecated ComEventCallback style to the annotation-based util API.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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