How can I prevent code from using wrong version of some dependency? - java

I have a project which depends on a JAR file. The version of this JAR changes often and we are having a hard time trying to ensure we are using the correct one. It is also causing problems when investigating bugs: which version of JAR contains the bug. Some programmers may forget to update corresponding dependencies and include 2 versions of this JAR inside the project, so that an old version may be found by the classloader.
A question is how to account for this issue.
I have a following plan:
1) When an error occurs log the JAR name I am working with to ensure it is a correct version. I plan to use something like
this.getClass().getResource(someResourceINeedFromThatJar).getFile()
2) I can write a test to account for this. But I don't know how I can run a test AFTER the package phase of my Maven build
3) Maybe you can suggest something else for this?

Well, We have same scenario and solved issue by using maven dependencyManagement
It does two things.
Set a default version for dependencies in submodules/child projects
override the version of transitive dependencies
it does override a specified value in a transitive dependency.
The enforcer plugin does not ignore the dependencyManagement. But is unable to recognize the discrepancy since the transitive dependency's version was altered before it went to work.
Here is a nice article : You can go through it:
http://andydennie.com/2012/08/02/maven-enforcer-plugin-vs-dependencymanagement/
And another source: http://maven.apache.org/enforcer/maven-enforcer-plugin/

Related

Setting up an alias name for jar in artifactory

I have a gradle project where the jar is built and pushed to artifactory. I always want every build/new artifact to be referred as the latest which can be used externally. How do I achieve it through gradle? Can I set up something like 'latest' alias for the artifact, so at any point in time my latest tag would be pointing the latest jar which can be added as dependency?
Eg : abc-1.0-latest.jar should always fetch me the latest build irrespective of how many builds I run internally.
Hm - that might be a quite odd thing to do?
So, you'd like to publish an artifact several times with the same versioning, but with different signature? That is; the artifact abc-1.0 can evolve, but the versioning stays the same? Don't know if that is a good practise.
Anyway, why not look in to the versioning of maven/gradle works? Might be that you can add something like this to always fetch the newest artifact of the abc-library:
Maven:
<dependency>
<artifactId>abc</artifactId>
<groupId>com.whatever</groupId>
<version>[1.0,)</version>
<dependency>
Gradle:
dependencies {
compile 'com.whatever:abc:1.+'
}
In this case, the version 1.1, if available, it will be fetched from artifactory.
Keep in mind, though, that your code will not be easy to rebuild, as the artifact will be fetched using a dynamically dependency approach.
Your use case does sound very strange and not according to best practices.
It looks like what you really need is to use maven snapshot versions.
You can avoid specifying the version at all then Gradle will pick the latest one
dependencies {
compile 'com.google.guava:guava:+'
}
or if you want the latest of 7 release
dependencies {
compile 'com.google.guava:guava:7.+'
}
EDIT: sorry I misunderstood the question.
if you want your project always use the latest code is it not better to create a multi-project in this situation and rely on the project 'build' outcome?

Versions Maven Plugin: package not found after versions:use-latest-versions

When I execute in my Maven project the Versions Maven Plugin plugin with the command:
mvn versions:use-latest-versions
The pom.xml is updated with updated dependencies as it is supposed to do.
The problem is that some libraries are updated to version as new as the do not contains some of the packages used in previous versions so the compiler says package not found. Does anybody know how to avoid automatically? I mean, update to the latest version which have the packages and classes I am using in my code.
In my opinion, there is no easy way to determine which version update is "save".
Even if you would check that all classes you compile against still exist, method signatures might have changed. And even if all the method signatures stay the same, the behaviour might have changed, leading to runtime exception etc.
The only reasonable way I know to check a version update is to run a compile and run all test cases. Doing this for all combinations of possible version updates is possible but it will take a lot of time.
The plugin is not going to analyse your code and adjust the dependencies version accordingly.
The objective of the goal use-latest-versions is to upgrade your project to the latest release of your project dependencies, and as a result of you may have compilation and deployment problems.
Once you identified the problems you need to fix all the problems so that your whole project is upgraded to the latest releases of your dependencies.
The problem is that some libraries are updated to version as new as
the do not contains some of the packages used in previous versions so
the compiler says package not found. Does anybody know how to avoid
automatically? I mean, update to the latest version which have the
packages and classes I am using in my code.
Of course, it is not possible.
Updating dependencies is not a game of chance.
If you need to have the last version of a dependency, you should not worry about if this version breaks or doesn't break your code because you need it.
You update a library because you need to update that version. If you don't need to update your dependencies, don't update your dependencies, but if you need to do that, you should make the work to update your code too if necessary.

pointing eclipse to correct jar version in mvn repo

our maven repo currently has two versions of mockito, both versions are being pulled in as dependencies to other jars, and each is used in a different child project. Our integration-tests, which are a separate project, use a different version then the unit tests used by our core application.
The mockito versions have changed the signature of a method, making them not backwards computable. Due to the jars that each mockito version is dependent on it isn't easy for me to reconfigure maven to use only one version of mockito for each project.
When I run maven directly, from eclipse or command line, this is not an issue, the correct mockito version is used for each project based off of the pom file. However, when I try to run our unit tests in eclipse I am getting a NoSuchMethodError, which seems to be due to eclipse using the incorrect mockito version. Is there a way to ensure my junit tests use the version of version of mockito I want, aka the one specified in the pom file?
The first thing you should do is declaring mockito as a direct dependency of the modules that use it and not rely on it being drawn in through a transitive dependency. Maven/Eclipse/m2e should first use the version that is declared locally.
If that fails to resolve the problem, in my experience, it can help reordering the dependencies in the POM and checking the Maven Dependencies container in the project explorer or the Dependency Hierarchy tab in the POM editor afterwards to see if the right version is now used. Typically trying to move the problematic dependency either to the first position in the dependency list or to the last position resolves the problem.
Another (possibly additional) option is to add an exclude to that dependency which draws in the "wrong" version of mockito. Again, check the Dependency Hierarchy tab to see where the dependencies are coming from.
Finally, you should save yourself headaches and set up a project-wide dependency management that covers the unit tests in your application as well as the integration tests.
Good luck ;)
In Eclipse, go to your run configuration for your unit test. There is a "Classpath" tab there. You should be able to modify your classpath there to use the proper version of the jar.

Indirectly referenced from required .class files

I'm getting below error in STS:
The type org.springframework.core.env.EnvironmentCapable cannot be resolved. It is indirectly referenced from required .class files
This sounds like a transitive dependency issue. What this means is that your code relies on a jar or library to do something - evidently, you depend on Spring framework code. Well, all that Spring code also depends on libraries and jars.
Most likely, you need to add the corerctly versioned org.springframework.core jar to your classpath so that the EnvironmentCapable class can be found when your IDE attempts to build your project.
This might also be a jar collision issue as well, although that sounds less likely. When an application experiences jar collision (also known as "dll hell"), the compiler is finding multiple jars and classes with the same fully-qualified name. For example, let's say you added Spring to your classpath, along with the entire Tomcat server library. Well, those two jars may contain the same exact named classes, maybe the same version, maybe different versions. But either way, when the compiler looks for that EnvironmentCapable class, it finds two (in this contrived example) - one in the Spring jar and one in the Tomcat jar. Well, it doesn't know which one to choose, and so it throws a ClassDefNotFoundException, which would/could manifest itself as the error you experienced.
I faced same error while i work with spring security on spring-security-config.i jsut deleted that jar in maven repo and gave maven->update Project in eclipse.
it is resolved.Please try it once.
From command line, run "mvn clean install", you'll see project failed and you'll see artifacts in the logs that cause such a problem.
After that, remove artifacts from .m2/repository, then maven update from eclipse.
To avoid jar collision, make sure you declare your dependency versions under the properties tag in the aggregate pom.xml, and use the property name as a placeholder throughout the project. For example 4.2.5.RELEASE in the parent pom, and then in the child modules just use ${spring.version} instead of 4.2.5.RELEASE. This way you can avoid having two different versions of the same library on the classpath.
Also it is recommended to be consistent with the version of spring dependencies. Use the same version for spring-core, spring-web etc.
If you are using maven, then you can use the maven enforcer plugin to ensure dependency convergence, and avoid further issues with transitive dependencies.

Preferring the latest jar in a sea of dependencies (java)

I have a large Ivy project, and Ive noticed that my code, which run well in eclipse, cause a compile error when run in ant. I've narrowed the problem down to the following line :
FileUtils.write(...).
This line fails - during compilation --- the method is simply not found. Obviously, my code is dependant on apache's commons-io library. And its quite clear that the current commons-io has this method.
http://commons.apache.org/io/apidocs/org/apache/commons/io/FileUtils.html
So what gives ?
I am pretty sure this is related to my ivy.xml -> the eclipse compiler is luckily (or smartly) using the newest possible version of commons-io , whereas my ivy.xml is using an older version which lacks this method.
Most important of all to not here is that ant is clearly using a different version of this jar.
So - my question is :
1) How can I tell ant / ivy to preferentially compile my code with the latest versions of libraries i specify ? I'm assuming that some of the dependencies in my lib/ may depend on older versions of commons-io .....
Also :
2) In this context, any hints about what to worry about regarding the how the classloader deals with duplicates in a multi-jar-dependent project would also be helpful to me ...
Dependency Reporting
I would suggest that you first add the generation of an ivy dependency report into your build, using the report task.
An example of this task is included in the following answer:
What is the Ivy equivalent of Maven's versions:display-dependency-updates?
This will tell you what versions of what jars are being used. Normally, ivy will use the version you specify in the ivy.xml file, however, another module might depend on a more recent version. Ivy's default behaviour is to always favour the most recent version of a Maven module.
Retrieve the latest dependency
If you want ivy to always prefer the latest version of a particular library then declare the dependency as follows:
<dependency org="commons-io" name="commons-io" rev="latest.release"/>
Ivy has a feature called Fixed and Dynamic Revisions.
You can set the version/revision of any artifact to latest-status like
rev="latest.integration" --> for development released
rev="latest.release" --> for released versions
Ivy takes the version with the highest version(you have specified) and omits all libraries with lower versions, so that you only have one lib in the ivy classpath (have a look at the resolution report, run ant -v (verbose mode))., which avoids having duplicate jars with conflicting versions.
This might be worth checking out, maybe you just have an old version defined in one of your ivy files.
As to the second point:
The classloader takes the class, that happens to be first in the classpath(or the jar that is first in the classpath). So mixed versions of the same lib, could behave differently on any system, depending on how the classpath is constructed.

Categories

Resources