Skip to content

default interface methods. Or not.  #240

Open
@brett-smith

Description

I have a situation where I am sharing some code across a few modules, and my DBusInterface interface and implementation extend a generic interface that is used outside of the dbus components.

Something like this ..

public interface RootItem {
}

public interface Root<ITEM_TYPE extends RootItem> {
     public ITEM_TYPE getItem(long itemId);
}

public interface DBusItem extends RootItem {
}

public interface DBusAPI extends Root<DBusItem>, DBusInterface {
    @Override
    public DBusItem getItem(long itemId);
}

public class DBusAPIImpl implements DBusAPI {
    @Override
    public DBusItem getItem(long itemId) {
         /// do stuff to get item
         return theItem;
    }
}

This will fail to export the interface.

org.freedesktop.dbus.exceptions.DBusException: Exporting non-exportable type: interface com.logonbox.vpn.client.common.api.IVPNConnection
	at org.freedesktop.dbus@5.0.0-SNAPSHOT/org.freedesktop.dbus.Marshalling.recursiveGetDBusType(Marshalling.java:281)
	at org.freedesktop.dbus@5.0.0-SNAPSHOT/org.freedesktop.dbus.Marshalling.getDBusType(Marshalling.java:118)
	at org.freedesktop.dbus@5.0.0-SNAPSHOT/org.freedesktop.dbus.Marshalling.getDBusType(Marshalling.java:103)
	at org.freedesktop.dbus@5.0.0-SNAPSHOT/org.freedesktop.dbus.messages.ExportedObject.generateMethodsXml(ExportedObject.java:227)
	at org.freedesktop.dbus@5.0.0-SNAPSHOT/org.freedesktop.dbus.messages.ExportedObject.generateIntrospectionXml(ExportedObject.java:341)
	at org.freedesktop.dbus@5.0.0-SNAPSHOT/org.freedesktop.dbus.messages.ExportedObject.<init>(ExportedObject.java:37)
	at org.freedesktop.dbus@5.0.0-SNAPSHOT/org.freedesktop.dbus.connections.AbstractConnection.exportObject(AbstractConnection.java:329)

What appears to be happening, is that the getItem() method is being found twice. What is is interesting, is that one occurrence is being identified as a default method even though it's not, while the other is being identified as abstract (like all the other methods in the interface that do not have this generic type).

Doing a System.out of the two methods that are found results in ...

public default com.acme.root.RootItem com.acme.impl.DBusAPI.getItemlong)
public abstract com.acme.impl.DBusItem com.acme.impl.DBusAPI.getItem(long)

I could fix this by adding a @DBusIgnore to Root, but Root is in a module that does not have dbus-java on the CLASSPATH.

So instead, I changed dbus-javas ExportedObject.isExcluded() method.

 public static boolean isExcluded(Method _meth) {
        return !Modifier.isPublic(_meth.getModifiers())
                || _meth.isDefault() /* <--- Added this */
                || _meth.getAnnotation(DBusIgnore.class) != null
                || _meth.getAnnotation(DBusBoundProperty.class) != null
                || _meth.getName().equals("getObjectPath") && _meth.getReturnType().equals(String.class)
                        && _meth.getParameterCount() == 0;
    }

And now it all works again.

This doesn't seem to have any other ill effects to the DBus API. Everything else is still getting exported correctly. It seems that it is only identified as default with this particular arrangement of interfaces, OR if you do actually use a default method in the DBusInterface.

I think this may be a valid fix, because using a default method doesn't make sense anyway. If you are acting as a client, accessing an external DBus service from Java, then default methods don't work anyway (RemoteInvocationHandler tries to run it as if it were a remote method). It might be valid if you are exporting an API from Java, but then you cannot share those interface definitions with client code.

TLDR; I think default methods in DBus interfaces should be excluded by default

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions