hypfvieh / dbus-java

Improved version of java DBus library provided by freedesktop.org (https://dbus.freedesktop.org/doc/dbus-java/)
https://hypfvieh.github.io/dbus-java/
MIT License
185 stars 73 forks source link

dynamicProxy issue with interface name overriding #19

Closed haggish closed 6 years ago

haggish commented 6 years ago

Hi!

I have been using dbus-java 2.* and now experimenting with 3.0 SNAPSHOT. I ran to an issue with code that is getting a DBus object, calling DBusConnection.dynamicProxy:

org.freedesktop.dbus.exceptions.DBusExecutionException: Invalid arguments
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.freedesktop.dbus.errors.Error.getException(Error.java:150)
    at org.freedesktop.dbus.errors.Error.throwException(Error.java:180)
    at org.freedesktop.dbus.RemoteInvocationHandler.executeRemoteMethod(RemoteInvocationHandler.java:163)
    at org.freedesktop.dbus.RemoteInvocationHandler.invoke(RemoteInvocationHandler.java:227)
    at com.sun.proxy.$Proxy37.Connect(Unknown Source)
[...]

Cranking up the debug levels I see:

2018-06-06 04:27:29 [DBus Worker Thread-3] DEBUG o.f.d.c.impl.DBusConnection - Trying interface org.freedesktop.DBus.Introspectable
2018-06-06 04:27:29 [DBus Worker Thread-3] DEBUG o.f.d.c.impl.DBusConnection - Trying interface org.freedesktop.DBus.Introspectable
2018-06-06 04:27:29 [DBus Worker Thread-3] DEBUG o.f.d.c.impl.DBusConnection - Trying interface net.connman.Service
2018-06-06 04:27:29 [DBus Worker Thread-3] DEBUG o.f.d.c.impl.DBusConnection - Trying interface net.connman.Service
2018-06-06 04:27:29 [DBus Worker Thread-3] DEBUG o.f.d.c.impl.DBusConnection - 
org.freedesktop.dbus.exceptions.DBusException: Could not find an interface to cast to
    at org.freedesktop.dbus.connections.impl.DBusConnection.dynamicProxy(DBusConnection.java:302)
    at org.freedesktop.dbus.connections.impl.DBusConnection.getExportedObject(DBusConnection.java:334)
    at org.freedesktop.dbus.Marshalling.deSerializeParameter(Marshalling.java:502)
    at org.freedesktop.dbus.Marshalling.deSerializeParameters(Marshalling.java:698)
    at org.freedesktop.dbus.connections.AbstractConnection$2.run(AbstractConnection.java:675)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

Digging into dynamicProxy, I see that it is getting first the object as Introspectable and checking if it can load any interfaces that it declares in the introspection XML, then just using the first one. But it does not take into account if someone has overridden the Java package / DBus interface sync with DBusInterfaceName.

I have these overrides in place in every DBus interface I access, and now in 3.0 also the DBus Introspectable Java package diverges from the DBus interface name. I guess this has previously worked because Introspectable is(?) the interface every DBus object has, and its Java package has been matching the interface name, and you can cast the proxy to another interface. But now Introspectable Java package does not match the DBus interface name any more, and the whole thing fails.

Does this make any sense? Should there be a mechanism that given ClassNotFoundEx for an introspected IF, tries to check if there is a class annotated with IF name override with matching value? Or in the case no classes matching the interfaces can be found (or actually in any case), just use Introspectable since all DBus objects should implement that?

Something along the lines of (DBusConnection.dynamicProxy:301-) ?

            if (ifcs.size() == 0) {
                //throw new DBusException("Could not find an interface to cast to");
                ifcs.add(Introspectable.class);
            }
hypfvieh commented 6 years ago

This is indeed a problem, but using Introspectable.class would not be suitable here.

The DBus spec says: "Objects instances may implement Introspect which returns an XML"... It says 'may' not 'must'.

So the best effort we can do here is to use DBusInterface.class in case no proper interface was found before. This interface must be present on all exported objects.

I changes the code in DBusConnection so it takes care of the default DBus interfaces by looking into the correct package. I hope this will fix it. If not suitable interface could be found, it will try DBusInterface. This may fail with a ClassCastException if it is not compatible (I guess all objects should be compatible, otherwise they wouldn't be published on DBus).

It would be great if you can provide a unit test cover this issue.

hypfvieh commented 6 years ago

Is this issue resolved now?

haggish commented 6 years ago

Yes, it seems to work now without casting problems