I am in process of updating my project's jdk from 8 to 11 . So, while running I am facing such kind of warnings
org.aspectj.internal.lang.annotation.ajcDeclareAnnotation scanned from multiple locations: jar:file:///Users/nishtha.garg/.m2/repository/org/aspectj/aspectjrt/1.9.2/aspectjrt-1.9.2.jar!/org/aspectj/internal/lang/annotation/ajcDeclareAnnotation.class, jar:file:///Users/nishtha.garg/.m2/repository/org/aspectj/aspectjweaver/1.9.2/aspectjweaver-1.9.2.jar!/org/aspectj/internal/lang/annotation/ajcDeclareAnnotation.class
javax.mail.search.MessageIDTerm scanned from multiple locations: jar:file:///Users/nishtha.garg/.m2/repository/javax/mail/mail/1.4/mail-1.4.jar!/javax/mail/search/MessageIDTerm.class, jar:file:///Users/nishtha.garg/.m2/repository/javax/mail/javax.mail-api/1.6.2/javax.mail-api-1.6.2.jar!/javax/mail/search/MessageIDTerm.class
org.aspectj.lang.reflect.DeclarePrecedence scanned from multiple locations: jar:file:///private/var/folders/rw/9_fr4s6s01d5vcykl3fqkd7d3j59v0/T/jetty-0.0.0.0-0-attache-api-rest.war-_api-any-13258162480745251787.dir/webapp/WEB-INF/lib/aspectjrt-1.9.2.jar!/org/aspectj/lang/reflect/DeclarePrecedence.class, jar:file:///private/var/folders/rw/9_fr4s6s01d5vcykl3fqkd7d3j59v0/T/jetty-0.0.0.0-0-attache-api-rest.war-_api-any-13258162480745251787.dir/webapp/WEB-INF/lib/aspectjweaver-1.9.2.jar!/org/aspectj/lang/reflect/DeclarePrecedence.class
org.apache.cxf.transport.http.policy.HTTPClientAssertionBuilder$HTTPClientPolicyAssertion scanned from multiple locations: jar:file:///private/var/folders/rw/9_fr4s6s01d5vcykl3fqkd7d3j59v0/T/jetty-0.0.0.0-0-attache-api-rest.war-_api-any-13258162480745251787.dir/webapp/WEB-INF/lib/cxf-rt-transports-http-3.1.12.jar!/org/apache/cxf/transport/http/policy/HTTPClientAssertionBuilder$HTTPClientPolicyAssertion.class, jar:file:///private/var/folders/rw/9_fr4s6s01d5vcykl3fqkd7d3j59v0/T/jetty-0.0.0.0-0-attache-api-rest.war-_api-any-13258162480745251787.dir/webapp/WEB-INF/lib/cxf-rt-transports-http-3.1.4.jar!/org/apache/cxf/transport/http/policy/HTTPClientAssertionBuilder$HTTPClientPolicyAssertion.class
I can understand that this is occurring because 2 jars have same class and I have to exclude some dependencies but I am not getting how to exclude and what should be the criteria.
Let's take one of your conflicts as an example:
org.apache.cxf.transport.http.policy.HTTPClientAssertionBuilder$HTTPClientPolicyAssertion
scanned from multiple locations:
jar:file:///private/var/folders/rw/9_fr4s6s01d5vcykl3fqkd7d3j59v0/T/jetty-0.0.0.0-0-attache-api-rest.war-_api-any-13258162480745251787.dir/webapp/WEB-INF/lib/cxf-rt-transports-http-3.1.12.jar!/org/apache/cxf/transport/http/policy/HTTPClientAssertionBuilder$HTTPClientPolicyAssertion.class,
jar:file:///private/var/folders/rw/9_fr4s6s01d5vcykl3fqkd7d3j59v0/T/jetty-0.0.0.0-0-attache-api-rest.war-_api-any-13258162480745251787.dir/webapp/WEB-INF/lib/cxf-rt-transports-http-3.1.4.jar!/org/apache/cxf/transport/http/policy/HTTPClientAssertionBuilder$HTTPClientPolicyAssertion.class
Digging deeper (bolded) you can see that the class in question is provided by different version of "cxf-rt-transports-http", namely separate jars for versions 3.1.4 and 3.1.12.
You will need to examine each conflict individually and remove the less desirable jar from the classpath.
The best way to do so is by creating an exclusion, such as:
<exclusions>
<exclusion> <!-- declare the exclusion here -->
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
</exclusion>
</exclusions>
You declare this on the dependency that depends on the above.
Which isn't always easy to figure out unless you have software that illustrates the dependency graph.
In Eclipse for example, the Maven POM editor can show you dependencies, conflicts, and generate exclusions for you.
Selection criteria:
In most cases you'll probably want the newest version available, so in this case that's likely going to be 3.1.12.
However, you may not want the latest, latest, but a particular stable version that you have extensively tested, yet which doesn't contain any vulnerabilities. So the answer to that isn't straight forward.
If you need a specific version, it may be best to declare an explicit dependency on that artifact in your own pom and exclude it from all others.
Edit:
Another reason why you might need to choose a particular version over another is that you may be using another library that in turn relies on a specific version of a conflicting dependency, but has issues with a newer one.
In most cases version numbering is <major>.<minor>.<bugfix> and in almost all cases bugfix releases are binary compatible with each other, so in the case of cxf-rt-transports-http above you should be fine selecting 3.1.12.
On the other hand, say you had dependencies A depending on C v1.5.0 and B depending on C v2.1.2. This would be more difficult due to possible incompatibility between those major versions. There may be a feature you need in v2, but A is not compatible as an important method that A relies on was removed.
You would then want to check whether a newer version of A exists that will work with C v2.1.X and replace that instead. If there isn't you might either need to downgrade B, or install them side by side. In an extreme case that may involve repackaging the product.
An alternative is to contribute to or fork project A to create a version with updated dependencies.
Maybe it helps to think about the purpose of the warnings:
They're really saying that your code may run, but it is possible that a dependency version is selected in a non-deterministic fashion and that as a result some operations of your code might not to what you expect.
What you want to do is make it deterministic by providing the JVM only one option to choose from in each case. You do that by making a conscious choice as a developer as to which version to use or depend on.
If you have no other reasons, then I'd go for the latest/highest stable version, as that will probably include the most features and bugfixes.
Test thoroughly, as you would, and on the off-chance that you have problems that are not caused by your own code, isolate and report a possible bug, downgrade if you need to until the bug is fixed, and/or contribute a fix yourself.
Related
I'm new to Drools and I'm trying to start using different tutorials. Lately I've started those two: https://koziolekweb.pl/2008/10/30/jboss-rules-drools-silnik-regul-biznesowych/ and https://www.youtube.com/watch?v=zQhDe_PT60Y but they're using older Drools and I'm using version 7.62.Final. My errors are within those imports:
import org.drools.RuleBase;
import org.drools.RuleBaseFactory;
import org.drools.StatefulSession;
import org.drools.StatelessSession;
import org.drools.compiler.DroolsParserException;
import org.drools.compiler.PackageBuilder;
import org.drools.rule.Package;
and
import org.drools.StatefulSession;
Have they changed in new version of Drools? How may I change them in the code while using for example PackageBuilder builder = new PackageBuilder(); etc? And where can I find this information if it's available?
Thanks
Those tutorials are written against a very old version of Drools (probably Drools 4 or 5, based on the publish date.) Between Drools 5 and 6 there was effectively a complete rewrite, so the backend of the Drools library is completely different.
The imports you mention no longer exist. They no longer exist because their concepts have fundamentally changed. In Drools 5, we had Rule Bases. In Drools 7, we have Kie Bases. Configurations, defaults, how you load and fire rules ... everything is different. If you want to follow those tutorials, down-rev to Drools 5 ... but you can't go to 6.x or newer.
Your best bet is to completely ignore the tutorials -- which are worthless -- and just read the documentation. The Drools documentation is actually very good, and very in depth. Otherwise if you insist on reading tutorials, make sure that you find tutorials targeting 7 (and the newer version of Drools 7 the better, because after 7.44 or so they started implementing non-backwards compatible changes in minor releases.)
Latest from drools is v7.x. I followed the drools examples from the official repository. Check the examples from https://github.com/kiegroup/drools.git
And make sure you switch to latest branch example 'r7.73.0.Final'
Refer the official documentation. I found it a bit overwhelming to understand it initially.
https://docs.drools.org/7.73.0.Final/drools-docs/html_single/index.html
If you build is complaining that it is not finding these imports the real problem is likely that you do not have the correct maven dependencies in your pom.xml downloaded; I am sure that DROOLS still uses the StatelessSession, StatefulSession, etc.
There are two ways to update your pom.xml to use the correct dependency. Do a search on Google
maven org.drools.StatelessSession
and the first item returned is jar.download.com - which let's you download the JAR containing the StatelessSession class for a specific version of the tool. The sixth entry returned by the search is for https://mvnrepository.com - where these JARs are officially stored - showing you the pom.xml dependency for a specific version. Either way, you should make sure you get the correct version of the JAR specified in the pom.xml or downloaded.
DROOLS, JBPM, KIE, etc. use a BOM (bill of materials) project to specify the version of dependencies across a technology (i.e., so if there are 8 hibernate dependencies all 8 reflect the same version.) Your DROOLS documentation probably lists these versions or has a link to the BOM.
One of the blog you are referring is very old and after that there huge amount of changes in the dependencies. You should try updating your pom.xml file and Java Code accordingly. You can download required dependencies from https://mvnrepository.com/
Can you attach you project here ?
I want to understand the difference between [3.8.2] vs 3.8.2 when mentioned for our dependency's version.
From here ,
When declaring a "normal" version such as 3.8.2 for Junit, internally
this is represented as "allow anything, but prefer 3.8.2." This means
that when a conflict is detected, Maven is allowed to use the conflict
algorithms to choose the best version. If you specify [3.8.2], it
means that only 3.8.2 will be used and nothing else. If somewhere else
there is a dependency that specifies [3.8.1], you would get a build
failure telling you of the conflict. We point this out to make you
aware of the option, but use it sparingly and only when really needed.
The preferred way to resolve this is via dependencyManagement.
But I feel something is wrong here.
if I write <version>3.8.2</version> for our dependency and that version artifact is not present in our maven repo, then it is not picking anything else. Build simply fails.
So, why above they are saying - "allow anything, but prefer 3.8.2."
Also, they say - This means that when a conflict is detected,.... I am not able to understand this. What possible can be a conflict that does not arise for 3.8.2 but arises for [3.8.2] ?
The whole thing works as follows:
Step 1: Maven builds a dependency tree for your project, including your direct dependencies, their dependencies, the dependencies of your dependencies and so on.
Step 2: Now Maven makes a list of all nodes. If it encounters a dependency in just one version (say 3.8.2 or [3.8.2]) it will pick just that version.
Step 3: If Maven finds more than one version, the magic begins.
If all versions are versions without brackets (like 3.8.2), it picks the "nearest" version as mentioned in dependency mediation principle.
If you have some (or all are) version ranges (like [1.0.0,2.0.0]) or fixed versions (like [1.0.0]), then first it finds the intersection of all ranges/concrete version (Note that it does not consider versions without brackets here for finding this intersection).
If this intersection is found null, build fails. If it is not null, then it proceeds further by chooses the "nearest" version/concrete version/version range.
If by nearest definition, we get a version range/concrete version, then maven selects the most recent available version in resultant intersection of version range found.
If by nearest definition, we get a version (not concrete version) , then maven checks if that version is present in resultant intersection of version range found. If yes, this version is selected. If not, then maven selects the most recent available version in resultant intersection of version range (and does not fail the build).
The quote "allow anything, but prefer 3.8.2" is at best misleading. Maven does not try to make up for missing dependencies in the repository, it just "mediates" versions if more than one version is found in the dependency tree.
I work on a big legacy project and I've noticed that in the project root pom we explicitly forced certain maven plugin versions.
I've read about the 'maven way' and it seems to me that this is a violation of this way - forcing versions instead of inheriting them from the superpom. Here's an example of what we have in the project pom:
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>...</configuration>
</plugin>
My question is - what are the valid reasons (if any) to force plugin versions like that. I wonder because often times I find code that was written without any clear purpose and I do wonder if this is such a case, and if I should just drop the version from the project root pom.
Afterthought: On this site they say:
When declaring a "normal" version such as 3.8.2 for Junit, internally
this is represented as "allow anything, but prefer 3.8.2." This means
that when a conflict is detected, Maven is allowed to use the conflict
algorithms to choose the best version. If you specify [3.8.2], it
means that only 3.8.2 will be used and nothing else.
So this means, if you force the version to ensure stability, then you should also use [] otherwise maven is free to ignore your forced version.
The best is to define plugins versions only in a corporate pom and of course mainain this corporate pom over the time which means update the plugins versions from time to time.
This means in consequence that in no other project it is needed or better should be prevented to use a different versions of plugins (except there are very good reasons for this bugs in plugins).
Furthermore the excerpt you have given is an example of bad practice cause plugins and/or their configuration should be defined by using pluginManagement instead.
So if a project needs an older version of a maven plugin there should be at least a comment in the pom which describes why it's using not the inherited version. May be with a link to an appropriate JIRA issue...
what are the valid reasons (if any) to force plugin versions like that.
A valid reason is to keep a build repeatable, especially if there are known problems with a later version of the plugin. This ensures that the specific version is used, rather than a later version from an organisational parent pom (or, worse, from the default with no version specified anywhere).
I wonder because often times I find code that was written without any clear purpose and I do wonder if this is such a case
It's very possible, in a large code base, that this is exactly the case. The plugin configuration could have been copied from somewhere else and the version included without a good reason.
and if I should just drop the version from the project root pom.
If there is no reason given, either in a comment or a commit message, and if the same plugin has a version specified in the parent pom and if the build still works perfectly without it, then you should drop that version.
If it doesn't work, you should either fix the build or add a comment explaining exactly why this version is necessary.
As has already been stated, this can be because of corporate reasons - using new versions of plugins can break tests, functionality or even a whole product itself; new versions have to be tested thoroughly, advanced teams even need to discuss them because it can change the product in many ways.
Not forcing versions will create some kind of unstable situation during the next big build - which is always unwanted, developers dont like randomness :).
If your POM only describes a small, private project or maybe even a small community project you may very well let maven do all the version-management but thats pretty much a no-go for professional products which are worth .... say hundreds of thousands or even millions of currency units.
When using multiple APIs in a single project, the JAR files required for each API are added to the project in addition to other needed libraries such as Apache Commons, logging, etc. that are already used by the project. This sometimes results in a large number of jar files.
When a certain API or library is no longer used, it would be nice to remove the JAR files associated with it. However, there is a risk that another API or library requires it. This would NOT always become apparent during the building of the project. Sometimes, JARs that are missing throw errors only at runtime.
I have the following questions:
What is the best way to deal with this issue? In other words, be able to remove JARs without running the risk of runtime errors later?
I have been told that Maven solves this problem. Does it? Would it work if the external APIs used are not Maven-based? Would I be able to remove JARs without worrying about runtime errors? Do I need to rewrite my entire project to be based on Maven?
How do non-JVM platforms deal with the issue of shared libraries and removing them? Is Java lacking in this area or it is a common issue for all platforms?
Yes I agree Maven could help you in this case. Basically in Maven compile & runtime dependencies for each artifact (jar/war/ear/etc) are declared on pom.xml file. If multiple dependencies depends on same artifacts the latest version is used -- for example:
A-1.0.jar -- depends on --> C-2.0.jar
B-1.0.jar -- depends on --> C-2.1.jar
Only C-2.1.jar is is included in your project.
If a required dependency couldn't be found / taken out, Maven build will automatically fail. So to avoid runtime dependency missing, you can declare a dependency in runtime scope to a particular artifact -- and when you no longer need it you just take it out
There is an old trick I used to use on UNIX many years ago, it might still work for you. First use UNIX "touch" to set the date/time on all your files to the current date/time. Then wait for at least one minute. Then run your application. Then run UNIX "ls -lut" to list all your files, but this time the ones that were not used will have the date/time set in the first step whereas those that were used will have a more recent date/time due to the "u" switch reporting the last used date/time.
I just tried testing an application that uses Apache Camel 2.10.3, and immediately, upon the DefaultCamelContext being instantiated, got the following exception:
java.lang.NoSuchMethodError: org.slf4j.Logger.trace(Ljava/lang/String;Ljava/lang/Object;)V
at org.apache.camel.impl.DefaultPackageScanClassResolver.<init>(DefaultPackageScanClassResolver.java:70)
at org.apache.camel.impl.DefaultCamelContext.<init>(DefaultCamelContext.java:222)
I made sure that slf4j-api-1.6.6 (which is what Camel 2.10.3 ships with) was on the runtime classpath. Next, I suspected that I might have other dependencies that also used SLF4J, but that relied on a different version of it. So I opened Eclipse, and ran a type search for org.slf4j.Logger and sure enough, I see that class listed in 2 distinct JARs: slf4j-api-1.6.6.jar (as expected!), and another 3rd party jar, widget-lib-3.0.jar.
So I opened up widget-lib3.0.jar, and see SLF4J packaged up inside of it like so:
widget-lib-3.0/
com/
<Widget Lib's compiled classes>
org/
slf4j/
spi/
...
impl/
...
<A bunch of SLF4J classes, like LoggerFactory.class, etc.>
There's no way to tell what version of SLF4J it's using here, but I'd be willing to bet that it's a version that's earlier than 1.6.x, which is what Camel 2.10.3 wants.
So my best, slightly-educated guess is that at runtime, the JRE classloaders are finding widget-lib-3.0.jar#org/slf4j/Logger first, loading it, and then they go to load the Camel JARs and their dependencies. Then, when DefaultPackageScanClassResolver calls the SLF4J trace(String,Object) method, it's not finding the 1.6.6 version of SLF4J, rather, it's finding whatever version came with widget-lib-3.0.jar, and that method/overload doesn't exist.
Am I on track of way off base? If I'm off base, what does this mean to you, SO? And if I am on track, then my proposed solution would be to re-JAR widget-lib-3.0.jar without the org/slf4j packages in it (no other, more modern versions exist). My theory being that slf4j-api-1.6.6, which is backwards compatible, would be the only SLF4J version that gets loaded, and would then work for both JARs. Any thoughts? Thanks in advance.
Am I on track of way off base?
No. It looks like you are on-track here.
The way to confirm it would be to take the copy of org.sfl4j.Logger in the widget library JAR, and use javah to see if it has the void trace(String, Object) method or not.
Once you have confirmed it, there are a number of solutions:
The cleanest solution would be to get hold of the source code for the widget library, recompile it against the version of sfl4j that you need, and build a new version of the JAR without embedding sfl4j in it. (It is possible that you will need to modify the source of the widget library, but unlikely).
A simpler solution might to make sure that you put the newer (and supposedly backwards compatible) slf4 API JAR ahead of the widget library JAR on the classpath. That way, the old versions of slf4j in the widget JAR will be "shaded" by the newer ones with the extra method that Camel needs.
"There's no way to tell what version of SLF4J it's using here, but I'd
be willing to bet that it's a version that's earlier than 1.6.x, which
is what Camel 2.10.3 wants"...
Why not decompile the class file from the widget-lib-3.0.jar and see if the required method is there or not?
Your approach is the right one. SLF4J 1.x is API-compatible between versions. (Are you using Maven by the way? It's designed to prevent exactly this kind of problem).
What is widget-lib? Is there a version of it that doesn't include its dependencies? If there is, you should use that.