Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
NathanWalker opened this issue Aug 8, 2016 · 13 comments
Labels

Comments

@NathanWalker
Copy link
Contributor

NathanWalker commented Aug 8, 2016

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 #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

@petekanev
Copy link
Contributor

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.

@NathanWalker
Copy link
Contributor Author

NathanWalker commented Aug 8, 2016

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.

@petekanev petekanev self-assigned this Aug 8, 2016
@petekanev petekanev added the bug label Aug 8, 2016
@petekanev
Copy link
Contributor

petekanev commented Aug 8, 2016

@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.

@NathanWalker
Copy link
Contributor Author

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

@petekanev
Copy link
Contributor

@NathanWalker please read my updated comment above

@NathanWalker
Copy link
Contributor Author

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

@NathanWalker
Copy link
Contributor Author

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

@petekanev
Copy link
Contributor

@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).

@slavchev
Copy link

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
Copy link

slavchev commented Dec 7, 2016

Closing this issue until further need.

@slavchev slavchev closed this as completed Dec 7, 2016
@triniwiz
Copy link
Member

triniwiz commented Jun 5, 2017

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
Copy link
Member

@Pip3r4o ☝️☝️

@petekanev petekanev reopened this Jun 25, 2017
@petekanev petekanev removed their assignment Apr 2, 2018
@sunpasup
Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants