Hi I'm working on an Android app and I need to use a library called Semantics3. The issue I'm having is that the Semantics3 library depends on a few different libraries one of which is org.json but Android Studio automatically includes its own unique version of org.json which causes various issues. I've tried a few things to work around this and I'll describe them below.
First, I just imported the Semantics3 library. All the code compiles but when code from the library runs to make a service call the app crashes. This is due to a "NoSuchMethod" error because Semantics3 makes use of a constructor from a class in org.json which the AS version doesn't include.
To get around this I made my own jar file of the Semantics3 code and add in the dependencies it needs on my own in Gradle. The app still crashes, though not because it can't find the constructor. In this case the error is due to an exception from org.json, specifically "org.json.JSONException: Value com.android.okhttp.internal.huc.HttpURLConnectionImpl of type java.lang.String cannot be converted to JSONObject". I couldn't figure out why this error was popping up so I decided to try out the Semantics3 library outside of Android and just made a simple Maven project. In the Maven project I can make service calls just fine with no issue, but if I add the jar file and dependencies on my own, I get the same error as in AS.
So I figure there's something missing in the source code on Github that I used to make the jar or something but that's beyond me to figure out, so I'm back at trying to just import the library. My final and current attempt involves trying to explicitly import the version of org.json that Semantics3 needs along with the Semantics3 library in Gradle. But when I bring in the Sematnics3 library I try to exclude the transitive dependency Semantics3 introduces to org.json. I've included the Gradle file for this attempt below.
// https://mvnrepository.com/artifact/com.semantics3/Sem3Java
implementation('com.semantics3:Sem3Java:1.2.4'){
exclude group:'org.json:json'
}
implementation 'org.json:json'
constraints {
implementation(group: 'org.json', name: 'json', version: '20190722') {
because 'Semantics3 requires version 20190722 of org.json, not the default AS version'
}
}
The issue is when I try to run the code with the above setup in Gradle I get an error saying there are duplicate class definitions contained in the Semantics3 library and org.json library. And yes there are certainly conflicts but I thought the exclude bit to the Semantics3 implementation would be enough to prevent that from happening. Did I make a mistake somewhere or am I misunderstanding or misusing the exclude? If it makes a difference it appears the Semantics3 library does hardcode the org.json library into its Jar file. I appreciate any help with this. Thank you.
Related
I am upgrading my play-services-ads library from version 12 to version 18.1:
dependencies {
api 'com.google.android.gms:play-services-ads:18.1.0'
}
The problem is that the compilation fails with this error:
.gradle/caches/transforms-1/files-1.1/play-services-ads-identifier-17.0.0.aar/75b3c9fbdc51199269673bd2fa8b6cfe/jars/classes.jar(com/google/android/gms/ads/identifier/AdvertisingIdClient.class): warning: Cannot find annotation method 'value()' in type 'GuardedBy': class file for javax.annotation.concurrent.GuardedBy not found
I took away all the usages for AdvertisingIdClient and left only the import, but the problem persists:
import com.google.android.gms.ads.identifier.AdvertisingIdClient;
Is there anything I am doing wrong?
com.google.android.gms:play-services-ads:18.1.0 depends upon com.google.android.gms:play-services-ads-identifier:17.0.0, among other libraries.
Your error indicates that com.google.android.gms:play-services-ads-identifier:17.0.0 references javax.annotation.concurrent.GuardedBy. However, that class is not in the Android SDK. The POM file for com.google.android.gms:play-services-ads-identifier:17.0.0 should be referencing a library that has an implementation of that class, but it does not seem to.
One library that has an implementation of that class is com.google.code.findbugs:jsr305. Adding a dependency on com.google.code.findbugs:jsr305 for a recent version (e.g., 3.0.2) gave you that class, satisfying the compiler.
So, there appears to be a bug in the Play Services SDK packaging, which my workaround resolves. You might want to add a comment in your module's build.gradle file to consider removing the com.google.code.findbugs:jsr305 if a future update to com.google.android.gms:play-services-ads fixes this bug.
I have a problem with proto file in my project
I had import in my proto file:
import "google/api/annotations.proto";
I am getting following error when building the project.
Import "google/api/annotations.proto" was not found or had errors.
How can I use this import in my project? Should I add something to my build.gradle?
On non-Android, you could add this dependency to your build.gradle:
compile 'com.google.api.grpc:proto-google-common-protos:1.12.0'
However, Android uses Protobuf "Lite" instead of full Protobuf and there's not a pre-generated library with Lite for this proto. There is an open issue about this.
However, a workaround discussed for the well-known protos can be used here as well. Namely, use a protobuf dependency instead of a compile dependency. This will generate the code as part of your build.
protobuf 'com.google.api.grpc:proto-google-common-protos:1.12.0'
Unfortunately, this solution only really works for applications. If two libraries use this "solution" they must never be included into the same application as they will have duplicated (and potentially have different versions of) the generated classes.
I'm trying to set up the PubNub jar as a library in my Android Studio project. The project is something I am porting over from another computer, so I'm mostly copying things in.
It appears between then and now that I now have to configure the AnnotationProcessor of this jar, but I'm really not sure what that requires, nor have I been able to find an example that fits my issue.
When I try to compile my project, I am left with this message:
Error:FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:javaPreCompileDebug'.
Annotation processors must be explicitly declared now.
The following dependencies on the compile classpath are found to contain annotation processor.
Please add them to the annotationProcessor configuration- pubnub-gson-4.19.0-all.jar (pubnub-gson-4.19.0-all.jar).
Alternatively, set android.defaultConfig.javaCompileOptions.annotationProcessorOptions.includeCompileClasspath = true to continue with previous behavior.
Note that this option is deprecated and will be removed in the future.
See https://developer.android.com/r/tools/annotation-processor-error- message.html for more details.
I'm really not sure at all what this is telling me to do, and the examples I can find of annotationprocessor on the internet (none for PubNub) all are pointing to packages and classes, which I don't see what I am suppose to do with.
Can someone lead me down the correct path?
I apologize for the formatting of the error, but the site wouldn't let me submit it in blockquotes because it was "improperly formatted code."
Try to add this line in your dependencies{} block:
annotationProcessor files('libs/pubnub-gson-4.19.0-all.jar')
(along with the implementation files('libs/pubnub-gson-4.19.0-all.jar'))
It works in my case.
I have created a Android library which is packaged as an .aar file.
My library uses v1.8.0 of Squares Retrofit library internally.
An end user of my library is also using Retrofit, but they are using 2.0.1.
A problem arises when they try and run their app, a java.lang.NoClassDefFoundError is thrown when it reaches a line in my library that calls a Retrofit function that is no longer present in v2.
dependencies {
compile 'com.mylibrary.sdk:mylibrary:1.0.1#aar'
compile 'com.squareup.retrofit:retrofit:1.8.0'
...
compile 'com.squareup.retrofit:retrofit:2.0.1'
}
I am wondering if there is a standard way of dealing with this this?
The easy options that spring to mind are:
We upgrade our Retrofit version to 2
The end user downgrades their Retrofit version to 1
Both these options feel to be short-term. Also if for example, we upgrade to Retrofit 2 and a new end-user comes along that is using Retrofit 1, we are back to facing the same problem but in reverse.
Having done some research already, creating a full fat .aar build or using shading, may be solutions. If anyone can shed any light on how these can be used in this case it would be much appreciated.
The problem is probably somewhere else. It's not about the fact that there are some methods missing, because the new (2.X.X) version of Retrofit can work side-by-side with the old one (pre 2.0.0). So if both versions were imported properly into the project, you should be able to use both Retrofit and Retrofit2 without any problems. It's possible because the new version of the library has a different package (retrofit2.Retrofit instead of retrofit.Retrofit).
Are you sure that your library includes Retrofit 1.8.X? Maybe it just uses methods from the library but the 1.8.X version is not shipped in your aar? That would actually explain a lot.
What you can is either:
Ask the person that is using your library to include both versions of the Retrofit, apart from your library.
compile 'com.squareup.retrofit:retrofit:1.9.0'
compile 'com.squareup.retrofit2:retrofit:2.0.1'
or
Make sure the proper version of the Retrofit (1.X.X) is included in your library's aar.
A project runs on Google App Engine. The project has dependency that uses a class that can't be invoked on App Engine due to security constraints (it's not on the whitelist). My (very hacky) solution was to just copy a modified version of that class into my project (matching the original Class's name and package) that doesn't need the restricted class. This works on both dev and live, I assume because my source appears in the classpath before my external dependencies.
To make it a bit cleaner, I decided to put my modified version of that class into it's own project that can be packaged up in a jar and published for anyone else to use should they face this problem.
Here's my build.gradle:
// my jar that has 'fixed' version of Class.
compile files('path/to/my-hack-0.0.1.jar')
// dependency that includes class that won't run on appengine
compile 'org.elasticsearch:elasticsearch:1.4.4'
On my local dev server, this works fine, the code finds my hacked version of the class first at runtime. On live, for some unknown reason, the version in the elasticsearch dependency is loaded first.
I know having two versions of the same class in the classpath isn't ideal but I was hoping I could reliably force my version to be at the start of the classpath. Any ideas? Alternatively, is there a better way to solve this problem?
Not really sure if this is what people visiting this question were looking for, but this was what my problem and a solution that I reached at.
Jar A: contains class XYZ
Jar B: also contains class XYZ
My Project needs Jar B on the classpath before Jar A to be able to get compiled.
Problem is Gradle sorts the dependencies based on alphabetical order post resolving them which meant Jar B will be coming after Jar A in the generated classpath leading to error while compiling.
Solution:
Declare a custom configuration and patch the compileClasspath. This is how the relevant portion of build.gradle might look like.
configurations {
priority
sourceSets.main.compileClasspath = configurations.priority + sourceSets.main.compileClasspath
}
dependencies {
priority 'org.blah:JarB:2.3'
compile 'org.blah:JarA:2.4'
...
}
It's the app engine classloader I should have been investigating, not gradle...
App Engine allows you to customise the class loader JAR ordering with a little bit of xml in your appengine-web.xml. In my case:
<class-loader-config>
<priority-specifier filename="my-hack-0.0.1.jar"/>
</class-loader-config>
This places my-hack-0.0.1.jar as the first JAR file to be searched for classes, barring those in the directory war/WEB-INF/classes/.
...Thanks to a nudge in the right direction from #Danilo Tommasina :)
UPDATE 2020:
I just hit the same problem again and came across my own question... This time, live appengine was loading a different version of org.json than was being loaded in dev. Very frustrating and no amount of fiddling the build script would fix it. For future searchers, if you're getting this:
java.lang.NoSuchMethodError: org.json.JSONObject.keySet()Ljava/util/Set;
It's because it's loading an old org.json dependency from god-knows-where. I fixed it by adding this to my appengine-web.xml:
<class-loader-config>
<priority-specifier filename="json-20180130.jar"/>
</class-loader-config>
You'll also need a matching dependency in build.gradle if you don't already have one:
compile 'org.json:json:20180130'
According to gradle dependencies documentation, the order of dependencies defines the order in the classpath. So, we can simply put the libraries in the correct order in "dependencies".
But beware! here are two rules with higher priorities:
For a dynamic version, a 'higher' static version is preferred over a 'lower' version.
Modules declared by a module descriptor file (Ivy or POM file) are preferred over modules that have an artifact file only.