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

java.lang.NoSuchMethodError: org.json.JSONTokener.<init>(Ljava/io/Reader;)V #882

Closed
ejoseca opened this issue Dec 21, 2023 · 15 comments · Fixed by #888
Closed

java.lang.NoSuchMethodError: org.json.JSONTokener.<init>(Ljava/io/Reader;)V #882

ejoseca opened this issue Dec 21, 2023 · 15 comments · Fixed by #888
Milestone

Comments

@ejoseca
Copy link

ejoseca commented Dec 21, 2023

Description
JWS cannot be deserialized in Android devices.

Steps to reproduce

  1. Add the required dependencies for an Android project as shown in the README.md
dependencies {
    api('io.jsonwebtoken:jjwt-api:0.12.3')
    runtimeOnly('io.jsonwebtoken:jjwt-impl:0.12.3') 
    runtimeOnly('io.jsonwebtoken:jjwt-orgjson:0.12.3') {
        exclude(group: 'org.json', module: 'json') //provided by Android natively
    }
}
  1. Create a parser
Jwts.parser()
  .verifyWith(publicKey)
  .build()
  .parseSignedClaims(jwsString);
  1. Try to deserialize a signed JWT in an Android device
  2. An error is thrown: java.lang.NoSuchMethodError: org.json.JSONTokener.<init>(Ljava/io/Reader;)V

Cause
Since 0.12.0, the class io.jsonwebtoken.orgjson.io.OrgJsonDeserializer, in its parse() method, is trying to create a JSONTokener passing a Reader as argument to the constructor.
This constructor is not available in the Android implementation of JSONTokener: https://android.googlesource.com/platform/libcore/+/refs/heads/main/json/src/main/java/org/json/JSONTokener.java

@lhazlewood
Copy link
Contributor

This appears to be duplicate of #867. Could you please try the workaround listed there and let us know if that doesn't work?

We'll need to change the implementation on a future release to detect if this method is available on Android and then fallback to older logic if not.

@DanielGalarza
Copy link

DanielGalarza commented Jan 4, 2024

@lhazlewood I ran into the same issue described. I tried the proposed solution (not excluding the org.json dependency), and I still run into the same issue. It looks like it might of worked for someone else in #867, but it didn't solve it for me.

@lhazlewood
Copy link
Contributor

@DanielGalarza thanks for trying the proposed solution. What version of Android are you using?

@phamhongphong what version of Android are you using since it worked for you?

@lhazlewood
Copy link
Contributor

@DanielGalarza just to confirm, your dependencies looked like this?

dependencies {
    api('io.jsonwebtoken:jjwt-api:0.12.3')
    runtimeOnly('io.jsonwebtoken:jjwt-impl:0.12.3') 
    runtimeOnly('io.jsonwebtoken:jjwt-orgjson:0.12.3')
}

@ejoseca
Copy link
Author

ejoseca commented Jan 8, 2024

@lhazlewood Not excluding org.json works, but I don't want to include it in our project because of maintainability.
Overriding the Android's JSON implementation with a transitive dependency could lead to use methods that will not be available when it is removed.

For now, we are going to stay in version 0.11.5.

@lhazlewood
Copy link
Contributor

@ejoseca that's helpful, thanks for the feedback. We'll use this issue to track the work for a fix.

@lhazlewood
Copy link
Contributor

@ejoseca which version of Android are you using? I'd like to ensure a fix is compatible with at least that (and potentially others).

@lhazlewood
Copy link
Contributor

Actually, Android version probably doesn't matter, it appears that even the latest only supports a String constructor:

https://developer.android.com/reference/org/json/JSONTokener#JSONTokener(java.lang.String)

@ejoseca
Copy link
Author

ejoseca commented Jan 9, 2024

We support from Android 5 (SDK 21) onwards, but the JSON implementation is almost the same for all Android versions.

JSONTokener in Android 2.3: https://android.googlesource.com/platform/libcore/+/refs/tags/android-2.3_r1/json/src/main/java/org/json/JSONTokener.java

@DanielGalarza
Copy link

@DanielGalarza just to confirm, your dependencies looked like this?

dependencies {
    api('io.jsonwebtoken:jjwt-api:0.12.3')
    runtimeOnly('io.jsonwebtoken:jjwt-impl:0.12.3') 
    runtimeOnly('io.jsonwebtoken:jjwt-orgjson:0.12.3')
}

@lhazlewood Correct, that's what I tried to use, but still ran into issues. As far as the Android versions we are running, It's Android 8 (API 26) and through Android 14 (API 34)

I will also be staying on v11.5 for now, but I am looking forward to a fix soon, so that I can migrate over to 12+

@lhazlewood lhazlewood added this to the 0.12.4 milestone Jan 9, 2024
lhazlewood added a commit that referenced this issue Jan 10, 2024
…SONTokener(Reader) constructor is not available.

Closes #882
lhazlewood added a commit that referenced this issue Jan 10, 2024
OrgJsonDeserializer: Added fallback implementation for Android when JSONTokener(Reader) constructor is not available.

Closes #882
@lhazlewood
Copy link
Contributor

As updated by the PR merge, I've fixed this issue AFAICT. If anyone in this thread has the ability to build the latest master from source and test, I'd appreciate it! Please report back if you experience any problems.

@lhazlewood
Copy link
Contributor

This will be released in an upcoming 0.12.4 release.

@DanielGalarza
Copy link

DanielGalarza commented Jan 17, 2024

As updated by the PR merge, I've fixed this issue AFAICT. If anyone in this thread has the ability to build the latest master from source and test, I'd appreciate it! Please report back if you experience any problems.

@lhazlewood I'm happy to test this, but I'm not sure how to test you master branch. Is there a specific way I can do that from my Android project? Would this work:

    api("io.jsonwebtoken:jjwt-api:master-SNAPSHOT")
    runtimeOnly("io.jsonwebtoken:jjwt-impl:master-SNAPSHOT")
    runtimeOnly("io.jsonwebtoken:jjwt-orgjson:master-SNAPSHOT") {
        exclude group: "org.json", module: "json" //provided by Android natively
    }

@lhazlewood
Copy link
Contributor

lhazlewood commented Jan 17, 2024

@DanielGalarza you'd have to git clone and then build JJWT yourself on your own machine, and then use the snapshots .jars created by the JJWT build in your Android project.

@lhazlewood
Copy link
Contributor

@DanielGalarza I believe it would look something like this after building JJWT locally via mvn clean install:

    api("io.jsonwebtoken:jjwt-api:0.12.4-SNAPSHOT")
    runtimeOnly("io.jsonwebtoken:jjwt-impl:0.12.4-SNAPSHOT")
    runtimeOnly("io.jsonwebtoken:jjwt-orgjson:0.12.4-SNAPSHOT") {
        exclude group: "org.json", module: "json" //provided by Android natively
    }

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

Successfully merging a pull request may close this issue.

3 participants