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-java
s 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