My program relies on the following code to get available system memory:
import oshi.SystemInfo;
import oshi.hardware.HardwareAbstractionLayer;
SystemInfo si = new SystemInfo();
HardwareAbstractionLayer hal = si.getHardware();
// Next line throws exception: NoClassDefFoundError -> com/sun/jna/platform/win32/Psapi
long availableBytes = hal.getMemory().getAvailable();
double availableMegabytes = ((double) availableBytes) / 1048576;
double availableGigabytes = ((double) availableMegabytes)/1024;
Update: After deleting every occurrence of oshi-core from every project in Workspace (to remove possibility of transient conflict dependency - only 4.2.1 is left). Now the error I get is -> java.lang.NoClassDefFoundError: com/sun/jna/platform/win32/VersionHelpers
In pom.xml I've added oshi-core dependency - I've tried almost every version starting from version 3.4.0 to latest version 4.2.1 and they all result in the same error.
I realize oshi-core relies on jna and jna-platform. In Dependency Hierarchy I see both have resolved (compiled) to version 5.5.0.
What is causing this error and how can it be solved?
Thanks!
P.S
I've seen some other threads with similar error but could not find any thread with this exact problem (missing com/sun/jna/platform/win32/Psapi)
While you've pointed out in your comments that you think the latest version of JNA is being resolved, the errors indicate that your project does not have the most recent version of jna-platform (or possibly it has multiple versions linked on the classpath). This is nearly always the case for NoClassDefFoundError and while you're troubleshooting in the right direction, evidence indicates there's an old jna-platform version in your project somewhere.
The com.sun.jna.platform.win32.VersionHelpers class is in jna-platform version 5.3.0 and newer. The GetPerformanceInfo() method required for the method call giving you the error is in the com.sun.jna.platform.win32.Psapi class is in jna-platform version 4.3.0 and newer. If your classloader can't find these classes, then you don't have the correct jars linked to your project -- or you have incorrect jars linked alongside the correct ones.
Maven resolves dependencies by level... first it does all the dependencies you list in your POM (in order), then the transitive dependencies of those projects (in order) and so on. Ensuring the most recent version of JNA is used can be enforced by either (or both) of:
Specify oshi-core dependency earlier in your list of dependencies
in your POM, specifically, before any project that depends on an
earlier version of JNA.
Explicitly specify the jna and
jna-platform versions (5.5.0) in your top-level POM.
Also, in Eclipse, be sure to go through the menus to Update Maven Project to ensure your dependencies are in sync after changes in the POM.
It's possible that your local repository is not downloading the updated jar, in which case you can purge it (or just delete any JNA artifacts, or everything, from C:\Users\<username>\.m2\repository and let it rebuild.)
Also check the classpath in Eclipse. If you have manually added dependencies (e.g., to JNA) before setting up your POM to get them from Maven, you could be using those.
If the above hints do not resolve your problem, please post the contents of the dependencies section your pom.xml file so we can provide additional advice.
Seems oshi-core relies on internal undocumented features of the Sun / Oracle JVM, and you're running on a different and/or newer JVM that doesn't have that undocumented feature anymore. That's the risk of using undocumented features.
Get a newer/other version of oshi-core that supports the version of the JVM you're using, or switch to use a JVM that oshi-core supports.
Related
How to safely manage with such a problem:
In maven we have 2 libs (A with version 20, B with version 30) that depends on C (1.0 and 1.1 respectively). We get jar hell in target libs
*--A20--C1.0
\--B30--C1.1
Then I add dependencyManagment section and force C version to 1.1. It works as expected.
*--A20--C1.1 (not C1.0)
\--B30--C1.1
After several months, we decide to upgrade A to version 50. Now it depends on C version 2.0. But project still uses 1.1 due to dependencyManagement. It's a problem now
*--A50--C1.1 (not C2.0 as needed)
\--B30--C1.1
The question is: is it possible to override transitive dependency and this override will work only if version of transitive dependency match the version we set? Otherwise this override will be ignored and we'll see an error (with help of maven-enforcer plugin, for instance) I wonder if we have some plugin to check this case?
No.
I understand your use case, but I do not see anything in Maven to produce the result you want.
Summary
Our build pipeline has been broken after some machines have updated from JDK 11.0.10- to JDK 11.0.11+. This happens due to changed jdeps behavior. After some research it became evident, this is likely due to changes introduced with JDK-8214213:
https://mail.openjdk.java.net/pipermail/jdk-updates-dev/2021-April/005860.html
Assuming we were retrieving dependencies for sentry-1.7.25.jar, then our usage of jdeps via CLI is as follows:
jdeps --list-deps -filter:module --multi-release=11 "..\somePath\sentry-1.7.25.jar
The resulting dependency lists look like this:
11.0.10 and below
java.base
java.logging
java.naming
11.0.11 and above
Error: Missing dependencies: classes not found from the module path and classpath.
To suppress this error, use --ignore-missing-deps to continue.
sentry-1.7.25.jar
io.sentry.event.helper.BasicRemoteAddressResolver -> javax.servlet.http.HttpServletRequest not found
io.sentry.event.helper.ForwardedAddressResolver -> javax.servlet.http.HttpServletRequest not found
io.sentry.event.helper.HttpEventBuilderHelper -> javax.servlet.http.HttpServletRequest not found
io.sentry.event.helper.RemoteAddressResolver -> javax.servlet.http.HttpServletRequest not found
io.sentry.event.interfaces.HttpInterface -> javax.servlet.http.Cookie not found
io.sentry.event.interfaces.HttpInterface -> javax.servlet.http.HttpServletRequest not found
io.sentry.servlet.SentryServletContainerInitializer -> javax.servlet.ServletContainerInitializer not found
io.sentry.servlet.SentryServletContainerInitializer -> javax.servlet.ServletContext not found
io.sentry.servlet.SentryServletContainerInitializer -> javax.servlet.ServletException not found
io.sentry.servlet.SentryServletRequestListener -> javax.servlet.ServletRequest not found
io.sentry.servlet.SentryServletRequestListener -> javax.servlet.ServletRequestEvent not found
io.sentry.servlet.SentryServletRequestListener -> javax.servlet.ServletRequestListener not found
io.sentry.servlet.SentryServletRequestListener -> javax.servlet.http.HttpServletRequest not found
In order to fix this on OpenJDK 11.0.11+ it's necessary to set --ignore-missing-deps when calling jdeps. If done, then the output again looks correct again:
java.base
java.logging
java.naming
Question
So I am able to produce the same output with jdeps using JDK 11.0.11+ as I was able to do with JDK 11.0.10-. That being said, this output is used to create a custom runtime and in the description of JDK-8214213 is explicitely stated:
Note that a
custom image is created with the list of modules output by jdeps when
using the --ignore-missing-deps option for a non-modular
application. Such an application, running on the custom image, might
fail at runtime when missing dependence errors are suppressed.
From my understanding this means that if there is a transitive dependency involved, where the dependency of a dependency requires a runtime module that is not required by any of the top level dependencies, then this can lead to a custom runtime uncapable of running the application, since the transitive dependency cannot be resolved. In other words, if my application requires dependency A, which requires dependency B and module C, but dependency B also requires module D, then my application is at risk of encountering runtime errors, since my custom runtime is not being provided with module D.
My question now is this, since I am unable to derive it from documentation:
With JDK 11.0.11+ I can only get the same dependency list output, if --ignore-missing-deps is used. Does that mean that...
...jdeps was able to resolve transitive dependencies prior to 11.0.11, but cannot do so anylonger above said version, e.g. because dependency analysis is done differently internally in jdeps?
...jdeps acted as if it was using --ignore-missing-deps prior to 11.0.11 by default, hence if the default changed, jdeps is now throwing an error on 11.0.11+?
...something else is going on?
The resulting dependency list might be the same, simply because there are a lot of libraries, so most modules are used either way. However I am trying to determine, whether
jdeps --list-deps -filter:module --multi-release=11 "..\somePath\sentry-1.7.25.jar (11.0.10)
and
jdeps --list-deps --ignore-missing-deps -filter:module --multi-release=11 "..\somePath\sentry-1.7.25.jar (11.0.11)
behave exactly the same, or whether using --ignore-missing-deps introduces a new risk when adding new libraries to our project, as they may at some point require a module that is not part of the current jdeps-list.
Bear in mind, to me this is rather a deep-dive into OpenJDK specifics, so if there is faulty terminoogy or problems with my understanding of these scenarios, then feel free to point out and correct them.
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 am getting this error message when I try to compile my new modularized Java 11 application:
Error occurred during initialization of boot layer
java.lang.module.FindException: Unable to derive module descriptor for C:\Users\inter\.m2\repository\xalan\xalan\2.7.2\xalan-2.7.2.jar
Caused by: java.lang.module.InvalidModuleDescriptorException: Provider class org.apache.bsf.BSFManager not in module
This appears to be an issue from a dependency of a dependency. I can't even find which module is pulling it in so I can update it.
I am using openjdk 11.0.2, IntelliJ 2018.3.4, Maven
Any advice how I can troubleshoot or fix this? I have found very little documentation on this issue.
Xalan
I had a look at their bug tracker following their index page and wasn't able to find this reported and not sure how actively is the library being maintained either.
General Explanation
Just to explain what has caused the issue in your code, I would share a screenshot and then try to add details around it.
So within the JAR that for version 2.7.2, there are service declarations (META-INF/services) which include org.apache.xalan.extensions.bsf.BSFManager as one of them. The service file here has to indicate the Provider thereby for itself and the class is supposed to be present on the modulepath to be resolved for reliable configuration of modules.
In this case for the module xalan(automatic module), the service listed doesn't have the provider class packaged within the dependency itself. (See the package org.apache, it doesn't further have package bsf and the class BSFManager thereby. Hence the exception as you get.
Short term hack
One of the tweaks to get that resolved would be to get update the library jar (patch it) and get rid of the service file if you're not using it. Or to add the provider copied from the corresponding artifact.
If you don't directly depend on this artifact or its parent dependencies, you can let those remain on the --classpath and get resolved as an unnamed module for your application.
Long term solve
An ideal way would be to report this to the maintainers and getting it resolved. It depends though on how actively are they maintaining it e.g. the last release for xalan was almost 5 years back, might just want to look for an actively participated alternative in my opinion.
I tried to install update for TestNG in eclipse:
"Help -> Check for updates -> deselect all and select TestNG check box. Then
install latest version i installed the version which starts with 7.2.0.
It fixed the issue for me.
Java 8 here.
Say there is an old version of the widget libray, with Maven coordinates widgetmakers:widget:1.0.4, that has a class defined in it like so:
public class Widget {
private String meow;
// constructor, getters, setters, etc.
}
Years pass. The maintainers of this widget library decide that a Widget should never meow, rather, that it should in fact bark. And so a new release is made, with Maven coordinates widgetmakers:widget:2.0.0 and with Widget looking like:
public class Widget {
private Bark bark;
// constructor, getters, setters, etc.
}
So now I go to build my app, myapp. And, wanting to use the latest stable versions of all my dependencies, I declare my dependencies like so (inside of build.gradle):
dependencies {
compile (
,'org.slf4j:slf4j-api:1.7.20'
,'org.slf4j:slf4j-simple:1.7.20'
,'bupo:fizzbuzz:3.7.14'
,'commons-cli:commons-cli:1.2'
,'widgetmakers:widget:2.0.0'
)
}
Now let's say that this (fictional) fizzbuzz library has always depended on a 1.x version of the widget library, where Widget would meow.
So now, I'm specifying 2 versions of widget on my compile classpath:
widgetmakers:widget:1.0.4 which is pulled in by the fizzbuzz library, as a dependency of it; and
widgetmakers:widget:2.0.0 which I am referencing directly
So obviously, depending on which version of Widget gets classloaded first, we will either have a Widget#meow or a Widget#bark.
Does Gradle provide any facilities for helping me out here? Is there any way to pull in multiple versions of the same class, and configure fizzbuzz classes to use the old version of Widget, and my classes to use the new version? If not, the only solutions I can think of are:
I might be able to accomplish some kind of shading- and/or fatjar-based soltuion, where perhaps I pull in all my dependencies as packages under myapp/bin and then give them different version-prefixes. Admittedly I don't see a clear solution here, but am sure something is feasible (yet totally hacky/nasty). Or...
Carefully inspect my entire dependency graph and just make sure that all of my transitive dependencies don't conflict with each other. In this case for me, this means either submitting a pull-request to the fizzbuzz maintainers to upgrade it to the latest widget version, or, sadly, downgrading myapp to use the older widget version.
But Gradle (so far) has been magic for me. So I ask: is there any Gradle magic that can avail me here?
Don't know the specifics of Gradle, as I'm a Maven person, but this is more generic anyway. You basically have two options (and both are hacky):
ClassLoader magic. Somehow, you need to convince your build system to load two versions of the library (good luck with that), then at runtime, load the classes that use the old version with a ClassLoader that has the old version. I have done this, but it's a pain. (Tools like OSGI may take away some of this pain)
Package shading. Repackage the library A that uses the old version of library B, so that B is actually inside A, but with a B-specific package prefix. This is common practice, e.g. Spring ships its own version of asm. On the Maven side, the maven-shade-plugin does this, there probably is a Gradle equivalent. Or you can use ProGuard, the 800 pound gorilla of Jar manipulation.
Gradle will only set up the classpath with your dependencies, it doesn't provide its own runtime to encapsulate dependencies and its transitive dependencies. The version active at runtime will be the one according to the classloading rules, which I believe is the first jar in the classpath order to contain the class. OSGI provides runtime that can deal with situations like this and so will the upcoming module system.
EDIT: Bjorn is right in that it will try to resolve conflicts in different versions; it'll compile the classpath based on its strategies, so the order you put your dependencies in the file doesn't matter. However you still only get one class per classname, it won't resolve OP's issue
If you have different versions of a library with otherwise equal coordinates, Gradles conflict resolution mechanism comes into play.
The default resolution strategy is to use the newest requested version of the library. You will not get multiple versions of the same library in your dependendcy graph.
If you really need different versions of the same library at runtime you would have to either do some ClassLoader magic which definitely is possible or do some shading for one of the libraries or both.
Regarding conflict resolution, Gradle has built-in the newest strategy that is default and a fail strategy that fails if different versions are in the dependency graph and you have to explicitly resolve version conflicts in your build files.
Worse case is when the same class appears in multiple jars. This is more insidious - look at the metrics jars from Codahale and Dropwizard with incompatible versions of the same class in the two jars.
The gradle classpath-hell plugin can detect this horror.