Skip to content
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

Annotation interface javax.ws.rs.PathParam has no element 'value' (Android) #967

Closed
kryptohash opened this issue May 30, 2015 · 11 comments
Closed

Comments

@kryptohash
Copy link

I'm getting the below exception on the Android Wallet that I'm developing for my altcoin and I cannot figure out why.

05-30 11:55:32.608    8396-8445/org.kryptohash.wallet W/BaseExchange﹕ [AsyncTask #2] An exception occured while loading the metadata file from the classpath. This may lead to unexpected results.
    com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class com.xeiam.xchange.dto.MetaData]: can not instantiate from JSON object (missing default constructor or creator, or perhaps need to add/enable type information?)
            at [Source: libcore.net.url.JarURLConnectionImpl$JarURLConnectionInputStream@38d6f691; line: 2, column: 4]
            at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1080) ~[na:0.0]
            at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:295) ~[na:0.0]
            at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:142) ~[na:0.0]
            at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3562) ~[na:0.0]
            at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2648) ~[na:0.0]
            at com.xeiam.xchange.BaseExchange.applySpecification(BaseExchange.java:99) ~[na:0.0]
            at com.xeiam.xchange.empoex.EmpoExExchange.applySpecification(EmpoExExchange.java:17) ~[na:0.0]
            at com.xeiam.xchange.ExchangeFactory.createExchange(ExchangeFactory.java:56) ~[na:0.0]
            at de.schildbach.wallet.ExchangeRatesProvider.fetchKHCticker(ExchangeRatesProvider.java:436) ~[na:0.0]
            at de.schildbach.wallet.ExchangeRatesProvider.getKHCRateFromTicker(ExchangeRatesProvider.java:452) ~[na:0.0]
            at de.schildbach.wallet.ExchangeRatesProvider.query(ExchangeRatesProvider.java:193) ~[na:0.0]
            at android.content.ContentProvider.query(ContentProvider.java:966) ~[na:0.0]
            at android.content.ContentProvider$Transport.query(ContentProvider.java:211) ~[na:0.0]
            at android.content.ContentResolver.query(ContentResolver.java:478) ~[na:0.0]
            at android.content.CursorLoader.loadInBackground(CursorLoader.java:64) ~[na:0.0]
            at android.content.CursorLoader.loadInBackground(CursorLoader.java:42) ~[na:0.0]
            at android.content.AsyncTaskLoader.onLoadInBackground(AsyncTaskLoader.java:312) ~[na:0.0]
            at android.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:69) ~[na:0.0]
            at android.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:57) ~[na:0.0]
            at android.os.AsyncTask$2.call(AsyncTask.java:292) ~[na:0.0]
            at java.util.concurrent.FutureTask.run(FutureTask.java:237) ~[na:0.0]
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) ~[na:0.0]
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) ~[na:0.0]
            at java.lang.Thread.run(Thread.java:818) ~[na:0.0]

05-30 11:55:32.608    8396-8445/org.kryptohash.wallet W/ExchangeRatesProvider﹕ [AsyncTask #2] problem fetching KHC-BTC ticker: Annotation interface javax.ws.rs.PathParam has no element 'value'. This is a bug in rescu.

So far, EmpoEx is the only exchange trading my coin so, I'm kinda stuck with this problem.

Here are snips of my code:

public Double getKHCRateFromTicker(ExchangeRate exchangeRate) {
   Ticker KHCticker = null;
   try {
      KHCticker = fetchKHCticker();
   }
   catch (final Exception x) {
      log.warn("problem fetching KHC-BTC ticker: {}", x.getMessage());
      return -1.0;
   }
   return Double.parseDouble(KHCticker.getLast().toString());
}
private Ticker fetchKHCticker() throws Exception {
   Exchange exchange = ExchangeFactory.INSTANCE.createExchange(EmpoExExchange.class.getName());
   PollingMarketDataService marketDataService = exchange.getPollingMarketDataService();
   return marketDataService.getTicker(new CurrencyPair("KHC", "BTC"));
}

Here is the content of the empoex.json file located under \main\resources (Added LTC/BTC to test)

{
   "currency_pairs":[
      "LTC/BTC",
      "KHC/BTC"
   ]  
}

Also, see the screenshot showing Android Studio halted at the breakpoint.
xchange empoex exception

@timmolter
Copy link
Member

The first exception is actually just a warning log and can be ignored fi you want. It does point to some issue though. I would guess that the empoex.json file isn't on the classpath. I will push a change to that log that says it can be ignored.

The second output is an exception and the message says "This is a bug in rescu", which is interesting. I think it could be related to this issue: mmazi/rescu#50

@mmazi Could you share your wisdom here?

@kryptohash
Copy link
Author

Thanks for the answer.

I'm able to workaround the second exception by fetching all the tickers from the exchange. It is not ideal but, it works.

    private EmpoExTicker fetchAll() throws Exception {
        Exchange exchange = ExchangeFactory.INSTANCE.createExchange(EmpoExExchange.class.getName());
        EmpoExMarketDataServiceRaw raw = new EmpoExMarketDataServiceRaw(exchange);
        List<EmpoExTicker> tickers = raw.getEmpoExTickers();
        EmpoExTicker value = Iterables.find(tickers, new Predicate<EmpoExTicker>() {
            public boolean apply(EmpoExTicker ticker) {
                return ticker.getPairname().equals("KHC-BTC");
            }
        });
        return value;
    }

@mmazi
Copy link
Contributor

mmazi commented Jun 1, 2015

@kryptohash , which version(s) of Android does this happen on? Have you tried multiple versions? Did the same thing happen? Which version of XChange are you using? I know you've found a workaround for your issue, but providing this information would help us with debugging.

The only thing I can think of that could be the reason for the rescu error is a strange version of Java (or Android), where the javax.ws.rs.PathParam class is somehow incompatible with the standard one. (I improved the "Annotation interface javax.ws.rs.PathParam has no element 'value'. This is a bug in rescu." message in rescu now since the message was actually a bit misleading in both its claims, and didn't provide all available information.)

@kryptohash , if you can, it would be also great if you could reproduce the error using the latest version of rescu (this won't fix the issue, but should produce a more informative error message); if you're using Maven, just add this to your <dependencies>:

    <dependency>
        <groupId>com.github.mmazi</groupId>
        <artifactId>rescu</artifactId>
        <version>1.8.1-SNAPSHOT</version>
    </dependency>

@kryptohash
Copy link
Author

@mmazi

I'm building the App using the latest and greatest for Android. This is API 22 (or Android 5.1.1 Lollipop).
I've tested both JDK 1.7.0.79 and JDK 1.8.0.45. Here is the issue reproduced with latest rescu and xchange snapshots. Since Android Studio uses Gradle, it couldn't find the latest rescu 1.8.1 and xchange 3.0.1 snapshots. I had to download the source code for both rescu and xchange and place them into the App classpath.

06-01 13:55:12.429    3683-3732/org.kryptohash.wallet W/ExchangeRatesProvider﹕ [AsyncTask #2] problem fetching KHC-BTC ticker: {}
    java.lang.RuntimeException: Can't access element 'value' in  interface javax.ws.rs.PathParam. This is probably a bug in rescu.
            at si.mazi.rescu.AnnotationUtils.getValueOrNull(AnnotationUtils.java:43) ~[na:0.0]
            at si.mazi.rescu.RestInvocation.getParamName(RestInvocation.java:169) ~[na:0.0]
            at si.mazi.rescu.RestInvocation.create(RestInvocation.java:94) ~[na:0.0]
            at si.mazi.rescu.RestInvocationHandler.prepareAndInvoke(RestInvocationHandler.java:108) ~[na:0.0]
            at si.mazi.rescu.RestInvocationHandler.invoke(RestInvocationHandler.java:101) ~[na:0.0]
            at java.lang.reflect.Proxy.invoke(Proxy.java:397) ~[na:0.0]
            at $Proxy3.getEmpoExTicker(Unknown Source) ~[na:na]
            at com.xeiam.xchange.empoex.service.polling.EmpoExMarketDataServiceRaw.getEmpoExTicker(EmpoExMarketDataServiceRaw.java:33) ~[na:0.0]
            at com.xeiam.xchange.empoex.service.polling.EmpoExMarketDataService.getTicker(EmpoExMarketDataService.java:42) ~[na:0.0]
            at de.schildbach.wallet.ExchangeRatesProvider.fetchKHCticker(ExchangeRatesProvider.java:438) ~[na:0.0]
            at de.schildbach.wallet.ExchangeRatesProvider.getKHCRateFromTicker(ExchangeRatesProvider.java:452) ~[na:0.0]
            at de.schildbach.wallet.ExchangeRatesProvider.query(ExchangeRatesProvider.java:193) ~[na:0.0]
            at android.content.ContentProvider.query(ContentProvider.java:966) ~[na:0.0]
            at android.content.ContentProvider$Transport.query(ContentProvider.java:211) ~[na:0.0]
            at android.content.ContentResolver.query(ContentResolver.java:478) ~[na:0.0]
            at android.content.CursorLoader.loadInBackground(CursorLoader.java:64) ~[na:0.0]
            at android.content.CursorLoader.loadInBackground(CursorLoader.java:42) ~[na:0.0]
            at android.content.AsyncTaskLoader.onLoadInBackground(AsyncTaskLoader.java:312) ~[na:0.0]
            at android.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:69) ~[na:0.0]
            at android.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:57) ~[na:0.0]
            at android.os.AsyncTask$2.call(AsyncTask.java:292) ~[na:0.0]
            at java.util.concurrent.FutureTask.run(FutureTask.java:237) ~[na:0.0]
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) ~[na:0.0]
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) ~[na:0.0]
            at java.lang.Thread.run(Thread.java:818) ~[na:0.0]
     Caused by: java.lang.NoSuchMethodException: value []
            at java.lang.Class.getMethod(Class.java:664) ~[na:0.0]
            at java.lang.Class.getMethod(Class.java:643) ~[na:0.0]
            at si.mazi.rescu.AnnotationUtils.getValueOrNull(AnnotationUtils.java:41) ~[na:0.0]
    ... 24 common frames omitted

Here is the build.gradle content

apply plugin: 'com.android.application'

android {
    compileSdkVersion 22
    buildToolsVersion '22.0.1'
    defaultConfig {
        applicationId 'org.kryptohash.wallet'
        minSdkVersion 16
        targetSdkVersion 22
        versionCode 202
        versionName '1.01'
    }
    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            def outputFile = output.outputFile
            if (outputFile != null && outputFile.name.endsWith('.apk')) {
                def fileName = outputFile.name.replace('.apk', "-${versionName}.apk")
                output.outputFile = new File(outputFile.parent, fileName)
            }
        }
    }
    buildTypes {
        release {
            debuggable false
            minifyEnabled true
            //shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        debug {
            debuggable true
            minifyEnabled true
            //shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    productFlavors {
        mainnet {
            applicationId 'org.kryptohash.wallet'
        }
        //devnet {
        //    applicationId 'org.kryptohash.wallet_test'
        //}
    }
    compileOptions {
        encoding "UTF-8"
        sourceCompatibility JavaVersion.VERSION_1_7
        targetCompatibility JavaVersion.VERSION_1_7
    }
    packagingOptions {
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/NOTICE'
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])

    compile 'com.android.support:support-v4:22.1.1'
    compile 'com.android.support:appcompat-v7:22.0.0'
    compile 'com.android.support:support-v13:22.1.1'

    compile 'com.madgag.spongycastle:core:1.51.0.0'
    compile 'com.google.guava:guava:18.0'
    compile 'net.jcip:jcip-annotations:1.0'
    compile 'com.google.code.findbugs:jsr305:2.0.1'
    compile 'com.lambdaworks:scrypt:1.4.0'
    compile 'org.bitcoinj:orchid:1.0'

    compile 'com.google.protobuf:protobuf-java:2.6.1'
    compile 'org.slf4j:slf4j-api:1.7.7'
    compile 'com.github.tony19:logback-android-classic:1.1.1-3'
    compile 'com.github.tony19:logback-android-core:1.1.1-3'
    compile 'com.google.zxing:core:3.1.0'

    //compile 'com.xeiam.xchange:xchange-empoex:3.0.0'
    compile 'com.fasterxml.jackson.core:jackson-databind:2.5.3'
    compile 'org.java-websocket:Java-WebSocket:1.3.0'
    compile 'javax.annotation:javax.annotation-api:1.2'

    //compile 'com.github.mmazi:rescu:1.7.2'
    compile 'javax.ws.rs:jsr311-api:1.1.1'
}

@mmazi mmazi changed the title EmpoEx: An exception occured while loading the metadata file from the classpath. This may lead to unexpected results. EmpoEx: Annotation interface javax.ws.rs.PathParam has no element 'value' (Android) Jun 8, 2015
@mmazi
Copy link
Contributor

mmazi commented Jun 8, 2015

Let me think out loud a bit, since I'm still groping in the dark about this. The core problem is that rescu can't find the value element of the javax.ws.rs.PathParam using reflection:

Can't access element 'value' in  interface javax.ws.rs.PathParam. [...]
   Caused by: java.lang.NoSuchMethodException: value []

The @PathParam annotation is defined in javax.ws.rs:jsr311-api:1.1.1 (the same dependency in rescu pom and in @kryptohash's Gradle build), and it definitely has the value element.

Here's the code that fails:

ann.getClass().getMethod("value")

I can think of a few possible ways this can happen:

  1. There is another javax.ws.rs.PathParam, lacking the value element, in the classpath (that sometimes gets loaded instead of the expected one), possibly originating from another library, or Android system itself;
  2. The PathParam class is somehow modified in runtime so that it looses the value element,
  3. The Class#getMethod method behaves somehow differently in the given environment than expected.

I find all of the above a bit far fetched though. Anyone has any other ideas?

Also, the issue does not seem to be limited to EmpoEx (but should appear at least for all exchanges that use @PathParam, which is probably the majority). Can we get some confirmations that something like this works or fails in similar (Android) environments?

@kryptohash
Copy link
Author

@mmazi

I tried pulling the Doge-BTC ticker from Cryptsy Exchange and I got the same exact exception. So, the problem affects all the exchanges that use PathParam.

20:19:27.947 [AsyncTask #1] ExchangeRatesProvider - Problem fetching KHC-BTC ticker
java.lang.RuntimeException: Can't access element 'value' in  interface javax.ws.rs.PathParam. This is probably a bug in rescu.
    at si.mazi.rescu.AnnotationUtils.getValueOrNull(AnnotationUtils.java:43) ~[na:0.0]
    at si.mazi.rescu.RestInvocation.getParamName(RestInvocation.java:169) ~[na:0.0]
    at si.mazi.rescu.RestInvocation.create(RestInvocation.java:94) ~[na:0.0]
    at si.mazi.rescu.RestInvocationHandler.invoke(RestInvocationHandler.java:110) ~[na:0.0]
    at java.lang.reflect.Proxy.invoke(Proxy.java:397) ~[na:0.0]
    at $Proxy3.getMarketData(Unknown Source) ~[na:na]
    at com.xeiam.xchange.cryptsy.service.polling.CryptsyPublicMarketDataServiceRaw.getCryptsyMarketData(CryptsyPublicMarketDataServiceRaw.java:32) ~[na:0.0]
    at com.xeiam.xchange.cryptsy.service.polling.CryptsyPublicMarketDataService.getTicker(CryptsyPublicMarketDataService.java:33) ~[na:0.0]
    at de.schildbach.wallet.ExchangeRatesProvider.fetchDogeticker(ExchangeRatesProvider.java:451) ~[na:0.0]
    at de.schildbach.wallet.ExchangeRatesProvider.getKHCRateFromTicker(ExchangeRatesProvider.java:475) ~[na:0.0]
    at de.schildbach.wallet.ExchangeRatesProvider.query(ExchangeRatesProvider.java:205) ~[na:0.0]
    at android.content.ContentProvider.query(ContentProvider.java:966) ~[na:0.0]
    at android.content.ContentProvider$Transport.query(ContentProvider.java:211) ~[na:0.0]
    at android.content.ContentResolver.query(ContentResolver.java:478) ~[na:0.0]
    at android.content.CursorLoader.loadInBackground(CursorLoader.java:64) ~[na:0.0]
    at android.content.CursorLoader.loadInBackground(CursorLoader.java:42) ~[na:0.0]
    at android.content.AsyncTaskLoader.onLoadInBackground(AsyncTaskLoader.java:312) ~[na:0.0]
    at android.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:69) ~[na:0.0]
    at android.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:57) ~[na:0.0]
    at android.os.AsyncTask$2.call(AsyncTask.java:292) ~[na:0.0]
    at java.util.concurrent.FutureTask.run(FutureTask.java:237) ~[na:0.0]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) ~[na:0.0]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) ~[na:0.0]
    at java.lang.Thread.run(Thread.java:818) ~[na:0.0]
Caused by: java.lang.NoSuchMethodException: value []
    at java.lang.Class.getMethod(Class.java:664) ~[na:0.0]
    at java.lang.Class.getMethod(Class.java:643) ~[na:0.0]
    at si.mazi.rescu.AnnotationUtils.getValueOrNull(AnnotationUtils.java:41) ~[na:0.0]
    ... 23 common frames omitted

This is the code

    private Ticker fetchDogeticker() throws Exception {
        Exchange exchange = ExchangeFactory.INSTANCE.createExchange(CryptsyExchange.class.getName());
        CryptsyPublicMarketDataService publicMarketDataService = (CryptsyPublicMarketDataService) ((CryptsyExchange) exchange).getPollingPublicMarketDataService();
        return publicMarketDataService.getTicker(new CurrencyPair("DOGE", "BTC"));
    }

@mmazi mmazi changed the title EmpoEx: Annotation interface javax.ws.rs.PathParam has no element 'value' (Android) Annotation interface javax.ws.rs.PathParam has no element 'value' (Android) Jun 11, 2015
@omnibrain
Copy link
Contributor

I just encountered the same problem, but only after enabling ProGuard on my Android project. Therefore I'm pretty sure this problem is ProGuard related.

@kryptohash Maybe try to disable ProGuard and see if the error still occurs. If I find a way to get this working with ProGuard enabled I will let you know. Or if you find a way, please let me know.

@mmazi
Copy link
Contributor

mmazi commented Jul 28, 2015

Quick googling reveals that putting something like this in the proguard.cnf should fix the problem (I know nothing about ProGuard so take this with a grain of salt):

-keep class javax.ws.rs.PathParam { *; }

(Perhpas other *Param classes etc. in javax.ws.rs should be added too.)

Since @kryptohash has confirmed (via code) that he uses ProGuard, and this is a general and well-known ProGuard issue not related to rescu, I'm closing this.

@mmazi mmazi closed this as completed Jul 28, 2015
@mmazi
Copy link
Contributor

mmazi commented Jul 28, 2015

Thanks, @omnibrain !

@mmazi mmazi reopened this Jul 28, 2015
@mmazi mmazi closed this as completed Jul 28, 2015
@omnibrain
Copy link
Contributor

I can confirm that

-keep class javax.ws.rs.PathParam { *; }

solves the problem!

@kryptohash
Copy link
Author

Thanks @omnibrain and @mmazi. Everything works now. You guys rock!

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

No branches or pull requests

4 participants