Why does Gradle resolve a package with wrong version number? - java

I am building a web application and I am using Dropwizard 1.3.0, which has a dependency on jetty-io 9.4.8. This dependency has conflicts with another package (dropwizard-websocket-jee7-bundle 2.0.0), because it seem to fetch the wrong version number.
I looked into tha package, and found the method that has been renamed in 9.4.x - AbstractWebSocketConnection.java from 9.3.x - AbstractWebSocketConnection.java. The issue is that even though in Gradle the dependency tree shows I fetched 9.4.8 (the new one which I need), I still get the older, 9.3.x java file which causes the conflicts. I tried to Invalidate Caches / Restart and rebuild the whole project, but I seem to get the outdated file all the time.
What are the possible solutions for this?

If your bad class are imported by a transitive dependency, try to exclude explicit the transitive dependency.
For example if your required library is 'my.group:requiredLibrary:2.0.0' and there are another version in 'my.group:someDependency:0.1.5' you can do like this:
dependencies{
compile 'my.group:requiredLibrary:2.0.0'
compile ('my.group:someDependency:0.1.5'){
exclude group: 'my.group' module:'requiredLibrary'
}
}

Try forcing a particular version in your build.gradle
Example here: https://docs.gradle.org/current/dsl/org.gradle.api.artifacts.ResolutionStrategy.html

Related

How to add com.fasterxml.jackson.core.exc.InputCoercionException as a dependency in gradle?

I am getting java.lang.NoClassDefFoundError: com/fasterxml/jackson/databind/PropertyNamingStrategies which is used in another project. I have included jackson jar in current gradle project as well. But while starting the project I am getting the above mentioned error. Seems like we need to add com.fasterxml.jackson.core.exc.InputCoercionException as an dependency but I am not able to understand where to add this as a dependency ? Can someone please help ?
java.lang.NoClassDefFoundError Either means - missing dependency with class com/fasterxml/jackson/databind/PropertyNamingStrategies or class was removed meaning jackson libs versions used in your project dependencies won't work together.
How to start solving problems like those.
1, Via IDE try to find missing class if is present. If is not present then try to find jar with missing class on internet and add as dependency. In case your IDE show class is present then problem may be with import scope. Scope management differ per used technology so provide detail which one you use or paste dependencies from build.kts . Make sure you use implementation in case you import this class in project and not runtimeOnly.
2, You found class then try to print project dependency tree command differ per used technology. For gradle ./gradlew dependencies or for submodule ./gradlew submoduleName:dependencies and look at versions of jackson in your project.
3, Check jackson lib with version listed via dependency tree contains missing class.
How to avoid problem like those with spring boot.
I would recoment to use BOM provided by spring boot project, versions in there should work together.
For gradle with kotlin DSL we import it like this
import org.springframework.boot.gradle.plugin.SpringBootPlugin
plugins {
id("org.springframework.boot") version "2.6.2"
}
dependencies {
val springBootPlatform = platform(SpringBootPlugin.BOM_COORDINATES)
annotationProcessor(springBootPlatform)
implementation(springBootPlatform)
//this version has to be searched for spring boot version
implementation(platform("org.springframework.cloud:spring-cloud-dependencies:2021.0.0"))
//put desired jackson dependencies
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
}

Including javax persistence in a Cordova/Android project

I am trying to incorporate ObjectBox in my hybrid Cordova/Android project. By dint of some trial and error I have managed to figure out two of the steps involved.
The app level build.gradle file has to be modified to include the ObjectBox Gradle plugin classpath "io.objectbox:objectbox-gradle-plugin:2.5.0"
Define a build-extras.gradle file to "apply" the ObjectBox plugin ext.postBuildExtras = {apply plugin: 'io.objectbox'}
The next step according to the ObjectBox docs is to define at least one Entity class
However, the issue here is that I need to import the javax.persistence.* classes into the project. It is not clear to me how I do this. I have run into suggestions along the lines of including
compile group: 'javax.persistence', name: 'javax.persistence-api', version: '2.2'
in the dependencies section of the app level build.gradle file. However, this causes gradle to complain that it does not know the compile() function. I'd be much obliged to anyone who might be able to tell me how this should be done.
For the benefit of anyone running into this thread - you can download the JAR file for javax.persistence here. Place this line in the folder src/android/libsof your custom plugin and then modify plugin.xmlwith the line
<lib-file src='src/android/libs/name-of-javax-persistence.jar'/>

Version conflict when Gradle pull dependencies

In my project, jersey-core is pull from many dependencies. I don't know from which ones. I believed it doesn't matter because I thought that if multiples dependencies pull the same one, than gradle would always take the higher version. I was wrong.
[ERROR] [main] [n/a] org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/] - StandardWrapper.Throwable
java.lang.NoSuchMethodError: com.sun.jersey.core.reflection.ReflectionHelper.getContextClassLoaderPA()Ljava/security/PrivilegedAction;
at com.sun.jersey.spi.scanning.AnnotationScannerListener.<init>(AnnotationScannerListener.java:94) ~[jersey-server-1.19.jar:1.19]
AnnotationScannerListener is 1.19, ReflectionHelper is 1.1, and the method getContextClassLoaderPA() does not exist in ReflectionHelper 1.1
How can I force gradle to always take the higher version?
I use intellij.
By default gradle should add the highest version of a dependency to the classpath.
You can force the version of a dependency to be a specific version like so:
configurations.all {
resolutionStrategy {
// force certain versions of dependencies (including transitive)
// *append new forced modules:
force 'asm:asm-all:3.3.1', 'commons-io:commons-io:1.4'
}
}
This example was lifted directly from https://docs.gradle.org/current/dsl/org.gradle.api.artifacts.ResolutionStrategy.html, which might be worth a read, along with https://docs.gradle.org/current/userguide/dependency_management.html
Another piece of advice, if you want to find out what is pulling in conflicting versions of jars, you can do the following:
gradle dependencyInsight --dependency $dependencyName --configuration $configurationName
where $dependencyName should be substituted for the name of your dependency (such as asm-all), and $configurationName should be replaced with the configuration name you wish to check for (such as compile). This will give you a graph of what versions are being pulled in by which dependencies.

Can I force the order of dependencies in my classpath with Gradle?

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.

Using jackson-dataformat-xml on android

I'm strugling with using jackson-dataformat-xml on android
I have some very basic code that works fine on oracle jre
JacksonXmlModule module = new JacksonXmlModule();
module.setDefaultUseWrapper(false);
XmlMapper xmlMapper = new XmlMapper(module);
First I tried official documentation adapted for gradle (by me, not sure if done correctly):
compile 'com.fasterxml.jackson.core:jackson-core:2.5.4'
compile 'com.fasterxml.jackson.core:jackson-annotations:2.5.4'
compile 'com.fasterxml.jackson.core:jackson-databind:2.5.4'
compile 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.5.4'
compile 'org.codehaus.woodstox:woodstox-core-asl:4.4.1'
compile 'javax.xml.stream:stax-api:1.0-2'
Result: gradle fails build time about bundling corelibraries into an application
...
:app:preDexDebug
trouble processing "javax/xml/stream/EventFilter.class":
Ill-advised or mistaken usage of a core class (java.* or javax.*)
when not building a core library.
...
2nd attempt trying to follow Sean's answer
(Basicly he repackages corelibs with prefix names and rebuilds jackson-dataformat-xml to use the prefixed names)
compile 'com.fasterxml.jackson.core:jackson-core:2.1.2'
compile 'com.fasterxml.jackson.core:jackson-annotations:2.1.2'
compile 'com.fasterxml.jackson.core:jackson-databind:2.1.2'
// Repackaged XML-specific libraries
compile 'edu.usf.cutr.android.xml:jackson-dataformat-xml-android:2.1.2'
compile 'edu.usf.cutr.android.xml:stax2-api-android:3.1.1'
compile 'edu.usf.cutr.android.xml:stax-api-android:1.0-2'
compile 'edu.usf.cutr.android.xml:aalto-xml-android:0.9.8'
And build time failed on duplicates
Duplicate files copied in APK META-INF/services/com.fasterxml.jackson.core.ObjectCodec
so added:
packagingOptions {
...
exclude 'META-INF/services/com.fasterxml.jackson.core.JsonFactory'
exclude 'META-INF/services/com.fasterxml.jackson.core.ObjectCodec'
}
When adding the exclusions it builds and deploys, but fails runtime on below stackdump (AFAIK it cant find the SAX provider, even tho it is added to the classpath to my understanding)
edu.usf.cutr.javax.xml.stream.FactoryConfigurationError: Provider com.bea.xml.stream.MXParserFactory not found
at edu.usf.cutr.javax.xml.stream.FactoryFinder.newInstance(FactoryFinder.java:72)
at edu.usf.cutr.javax.xml.stream.FactoryFinder.find(FactoryFinder.java:176)
at edu.usf.cutr.javax.xml.stream.FactoryFinder.find(FactoryFinder.java:92)
at edu.usf.cutr.javax.xml.stream.XMLInputFactory.newInstance(XMLInputFactory.java:136)
at com.fasterxml.jackson.dataformat.xml.XmlFactory.<init>(XmlFactory.java:97)
at com.fasterxml.jackson.dataformat.xml.XmlFactory.<init>(XmlFactory.java:85)
at com.fasterxml.jackson.dataformat.xml.XmlFactory.<init>(XmlFactory.java:82)
at com.fasterxml.jackson.dataformat.xml.XmlMapper.<init>(XmlMapper.java:46)
What is the proper way to move forward on either #1 or #2?
Number 2 is the correct approach (Android doesn't like it when you include classes in the official Java package namespace - but then again, I wrote the original answer so I'm biased ;) ).
I believe the FactoryConfigurationError: Provider com.bea.xml.stream.MXParserFactory not found error is due to a bug in the Android build tools. In previous versions of ADT for Eclipse and Gradle plugin < 0.7.0 the /META-INF/* files are stripped from the JARs during the build process. It seems like >= v0.7.0 shouldn't have the problem according to Google, but from others' reports it sounds like it still may be problematic, and could potentially remove the META-INF/services/javax.xml.stream.XMLInputFactory file, which is required for the platform to register Aalto.
Try the workaround mentioned in AOSP issue 59658 comment 22:
right click on /src/main (where you have /java and /res folders),
select New > Folder > Java Resources Folder,
click Finish (do not change Folder Location),
right click on new /resources folder,
select New > Directory
enter "META-INF" (without quotes),
right click on /resources/META-INF folder,
select New > Directory
enter "services" (without quotes)
copy any file you need into /resources/META-INF/services
For you, in step 10 above you'd need to copy this file into /resources/META-INF/services. In case the file link is broken in the future, the name of the file is javax.xml.stream.XMLInputFactory and it consists of a single line:
com.fasterxml.aalto.stax.InputFactoryImpl
EDIT
If you get a "Error:duplicate files during packaging of APK... Path in archive: META-INF/services/javax.xml.stream.XMLInputFactory", you can try telling Gradle to keep the first occurrence with:
android {
packagingOptions {
pickFirst 'META-INF/services/javax.xml.stream.XMLInputFactory'
}
}
EDIT 2
This bug may be affecting "pickFirst". Please make sure you're running the latest version of Android Studio, and update your local tools and Android Gradle plugin to make sure you're running the most recent version of the tools. This may be fixed in Android Studio 1.3 RC1.
I have attempted to add XmlPull support to jackson xml. Find the forked project here:
https://github.com/finvu/jackson-dataformat-xml
Currently, only supported for version 2.9.6. (clone the branch jackson-dataformat-xml-2.9.6-XmlPull)
Sorry, I am not able to provide detailed documentation due to time constraints. If you have knowledge of git and maven to pull a specific branch and build the jar, then it should be relatively easy.
To those who will be in need of this in the future:
first integrate Jitpack in Your Android app, following their instructions:
https://jitpack.io/
Then paste teh GitHub url of jackson-dataformat-xml on Jitpack sites' corresponding text box. GitHub url is:
https://github.com/FasterXML/jackson-dataformat-xml.
That's it! Enjoy the result. :)

Categories

Resources