android icon indicating copy to clipboard operation
android copied to clipboard

Attempt to invoke virtual method 'java.lang.String java.lang.Package.getName()' - from Retrofit generating implementations from interfaces

Open NathanWalker opened this issue 9 years ago • 13 comments

Curious if this is currently supported. I have tried many different things but none seem to work. The issue seems to stem from the fact that the Retrofit (http://square.github.io/retrofit/) library generates implementations from interfaces and relies on the ability to take say an interface file (for example):

public interface SpotifyService {...

And generate an implementation by doing this restAdapter.create(SpotifyService.class) which crashes immediately with:

com.tns.NativeScriptException: 
Error: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.Package.getName()' on a null object reference
    com.tns.Runtime.getTypeMetadata(Runtime.java:426)
    com.tns.Runtime.getTypeMetadata(Runtime.java:403)
    com.tns.Runtime.callJSMethodNative(Native Method)
    com.tns.Runtime.dispatchCallJSMethodNative(Runtime.java:861)
    com.tns.Runtime.callJSMethodImpl(Runtime.java:726)
    com.tns.Runtime.callJSMethod(Runtime.java:712)
    com.tns.Runtime.callJSMethod(Runtime.java:693)
    com.tns.Runtime.callJSMethod(Runtime.java:683)

The library I'm trying to use does this here: https://github.com/kaaes/spotify-web-api-android/blob/master/spotify-api/src/main/java/kaaes/spotify/webapi/android/SpotifyApi.java#L69

Is there a way to make this work currently or is support for this planned and if so, it would be much appreciated to know approximately when?

UPDATE: I found this https://github.com/NativeScript/android-runtime/pull/501, curious if it's related and if that PR which is now merged will make something like the above possible with 2.2.0?

/cc @bradmartin

NathanWalker avatar Aug 08 '16 02:08 NathanWalker

Hey @NathanWalker, if I understand correctly, you have a Java Interface residing in whatever package in your Java files, and attempt to pass it on to RestAdapter's create method in JavaScript, but fail? Since your interface comes from Java, and is an unknown entity to the JavaScript engine, the Android Runtime will generate metadata with the full path (package name + class name) to your public classes and interfaces, allowing them to be recognized in JavaScript whenever you write something like java.lang.Object - exposing the Java Object API. The same is applicable for whatever other Java class you would use through JavaScript.

If I were to translate the example library that you linked to in NS with JavaScript syntax, I would describe the interface in Java, and build the implementation by specifying the full class name to the interface, like so:

function init(httpExec, cbExec) {
    ...
    return restAdapter.create(kaaes.spotify.webapi.android.SpotifyService.class);
}

As for #501 - it's unrelated to this issue - it will allow you to implement interfaces manually (versus what the aforementioned RestAdapter supposedly does for you), just as you could before, but no longer limiting you to just 1.

Let us know if the above helped you move forward, if not - a small repo with your specific case could assist us in better understanding the issue.

petekanev avatar Aug 08 '16 04:08 petekanev

Hi @Pip3r4o thanks for response. I am referencing as you mention like this: https://github.com/NathanWalker/nativescript-spotify/blob/master/src/android/search.ts#L6

let SpotifyService: any = kaaes.spotify.webapi.android.SpotifyService;

Then using that in my implementation: https://github.com/NathanWalker/nativescript-spotify/blob/master/src/android/search.ts#L70

let serviceApi = restAdapter.create(SpotifyService.class);

But that unfortunately fails :(

Lemme know if you have any other ideas I could try, much appreciated! You can pull that repo, then do this:

npm run setup
npm run demo.android

To run the android demo, then when main screen launches, click on the search icon in top right to show search page, then login to spotify on that page (not on the main page). A search textfield will then appear after logging in; (it's black so you can't actually see it, but if you tap below the Search title in actionbar, the keyboard will show and you can enter in any artst or track name Jackson for example, and you'll see it crash with the logging that have up to that specific line.

NathanWalker avatar Aug 08 '16 06:08 NathanWalker

@NathanWalker, after tinkering for a bit I concluded that we ~~do not expose interfaces' Class to JavaScript on .class calls but only when called with new ...({}). I came up with a workaround, albeit a bit hacky, that should solve this particular case until .class is fixed.~~

var iface = SpotifyService.class; // console.log(iface) will output 'interface kaaes.spotify.webapi.android.SpotifyService'

Edit: after probing some more I noticed that RestAdapter.create() call crashes every single time with the same error, no matter what interface is passed along (with NSHashCodeProvider being an exception). Will continue to investigate and let you know if anything comes up.

petekanev avatar Aug 08 '16 08:08 petekanev

@Pip3r4o does this mean I need to wait for support? Or are you suggesting downgrading Retrofit? Not sure.

NathanWalker avatar Aug 08 '16 14:08 NathanWalker

@NathanWalker please read my updated comment above

petekanev avatar Aug 09 '16 05:08 petekanev

@Pip3r4o thank you so much for your help on this one!! Really tricky. Would love to see this working 👍

NathanWalker avatar Aug 09 '16 06:08 NathanWalker

@Pip3r4o Curious if any other workarounds have been found here? Thank you.

NathanWalker avatar Aug 18 '16 20:08 NathanWalker

@NathanWalker have you considered updating the kaaes web api helpers that you are using to the version that supports retrofit 2.0 ? I tried debugging Retrofit, but I don't think it's right, since that version hasn't been updated in 2+ years, and there is a more recent one, written in a cleaner and more expressive manner (could help us in finding the culprit! :D).

petekanev avatar Sep 14 '16 11:09 petekanev

Adding more information. The original reported error is due to this line. In short, we make an assumption that the type is declared inside a package. This is a good assumption and I think supporting fully-qualified types only is a reasonable limitation of the runtime.

If this is a critical scenario then we can think of some workarounds and deal with the trade offs. I would like to hear more about it. Otherwise providing a better error handling for this error will be helpful.

slavchev avatar Oct 11 '16 10:10 slavchev

Closing this issue until further need.

slavchev avatar Dec 07 '16 09:12 slavchev

I ran into the same problem while trying to use the twitter-android-kit the app always crashed when i tried using any of the following Source i even tried extending their api client and writing my services and using a full package name . The only work around for me was creating my own http calls 😐

triniwiz avatar Jun 05 '17 23:06 triniwiz

@Pip3r4o ☝️☝️

triniwiz avatar Jun 25 '17 04:06 triniwiz

any fix available for this.. Ran into same issue..

sunpasup avatar Jul 18 '18 21:07 sunpasup