Static code analysis to detect all circular references in Spring framework in one go - spring

New Spring versions disallow cyclic beans by default. We are trying to do the right thing by refactoring code to avoid cyclic dependency.
But is there any way to detect all possible cyclic dependency rather than having to fix one, compile and rerun to get the next dependency error?

Related

Direct dependency vs Transitive dependency in build system

I was studying Maven's build system and it adds a lot of transitive dependencies because of its transitive dependency system (maven itself does not add dependencies but transitive dependency system does). I see issues with it like major version conflicts and unknown dependencies coming in.
I was thinking why is the system designed this way and why not take direct dependencies. My library does not need to depend on something which my dependency is using but not my library (I mean I understand why it needs to be included in the build list, my dependencies need to build using those, but why does it needs to cause major version conflict?). Am I missing something fundamental here? One thing that I can think of is that my library's build dependency list can grow to be very big because of all the direct dependencies I will need to take, but that does seem to be as big of a problem as problems with transitive dependency system.
I am new to build systems, so please don't be too harsh. I also tried to google this question but didn't find useful answers but please feel free to comment anything that I might have missed.
Thanks
If you need library A to run, and library A needs library B to run, and this needs C to run, it is very tedious to figure this out and add all the relevant dependencies to your project.
Before Maven and Gradle, many people worked that way and found out, that it is much easier to let a build tool figure out the transitive dependencies.
My library does not need to depend on something which my dependency is using but not my library [...]
This is your major misconception. There are two possibilities:
The direct dependency of your library exposes types from the transitive dependency in its public API. To use this public API you need to access these types, so you need the transitive dependencies during compile time.
The direct dependency of your library only uses its own dependency internally, but not in its public API. In this case, your library does not need to depend on the transitive dependency during compile time. But as soon as your library code runs (even in a test), it may use some functionality of its direct dependency that internally uses functionality of the transitive dependency, causing your library code to fail.
[...] I mean I understand why it needs to be included in the build list, my dependencies need to build using those [...]
There is no actual build list (or order) for external dependencies, because they are used when they are already built (the downloaded .jar files contain compiled .class files). But as I mentioned above, you will need the transitive dependencies either during compile time or during runtime (e.g. tests), so your build system (Maven or Gradle) will fetch them for you.
[...] but why does it needs to cause major version conflict?
#khmarbaise already explained in his comment, why and how version conflict between transitive dependencies may occur:
You are using two libs X and Y. Both of them using another lib (A) So X is using A in version 1.0.0 but Y is using A in version 2.0.0. In the end you can't have both on the classpath there must be done a decision for one version. So depending on how X,Y are implemented either X can fail while using A in V1.0.0 or Y can fail in using A in V1.0.0 or with V2.0.0 the same... This can happen if X or Y are being updated. This is also true for different version combinations like A in 1.0.0 and 1.1.0 (if compatibility is not 100%)

Force Maven to use latest dependency among the ones present in dependency tree

I understand Maven's behavior whenever it finds more than one version of the same dependency is to choose the one closer to the dependency root. If more than one are same as close, then it will choose the first one it finds.
Is there a way to change this behavior and make it simply pick the highest version?
The versions plugin can do some of the work for you, by rewriting your POM, but I highly recommend avoiding using it. Explicitly managing dependencies as gogstad and Michael stated is the recommended path.
Add a dependency management section and pick the version you actually want to use. You should always be setting versions so you're getting repeatable builds.
No, it's not possible to change the maven dependency mechanism to anything other than nearest definition.
If you experience that maven chooses the wrong dependency, the only way to fix it is to explicitly depend on that dependency in your application (maven will of course not allow two different versions of the same dependency in the clasdpath at the same time). The dependency you define will be used in any transitive dependencies for the same artifact.

Obtain multiple maven dependency trees

I have a Maven project that depends on numerous other projects, which often have several conflicting dependencies.
Maven will automatically resolve dependency conflicts using its nearest-wins strategy, in which case it will list the chosen version on the result mvn dependency:tree:
[INFO] | - (commons-collections:commons-collections:jar:2.1:compile - omitted for conflict with 2.0)
In this example, should commons-collections:2.1 be chosen, I would have an alternate dependency tree, potentially containing multiple other dependencies.
What I need to know is how this alternate tree would look like should the other version be chosen.
The way I'm currently doing is identifying the top level dependency that has conflicts with other dependencies, and running dependency tree just for it, i.e. by effectively creating multiple new poms with a single dependency just for the purpose of obtain their trees. This works, and I can write a script for that, but it's a manual process. I'm looking for Maven goal or other approach, which would act on my pom making things straightforward.
I've looked at other goals of the Maven dependency plugin such as analyse, but they do not appear to be helpful in this case.
There is no plugin that does exactly that, but there is a plugin that can help deal with the nearest-win maven dependency resolution strategy, and protect against it's occasionally unintended consequences.
It's the maven enforcer plugin, that with it's dependencyConvergence rule basically turns off the maven nearest-win strategy. With that rule applied to a build, if there is a dependency on version 1 of a transitive library, but also a dependency on version 2 of the same library, the build will fail.
This is a fail early mechanism that will allow to detect when the maven nearest dependency mechanism kicks in and silently makes a choice for a library version that we would prefer to do ourselves based on some code/library analysis.
What you can do with this plugin is to fix the current build by choosing the versions you want one by one, and then turn on the dependencyConvergence for future builds. This will ensure that you won't have to do the same analysis and fix in a near future, whe someone else changes the poms and the problem occurs again.

Maven exclude philosophy

What maven Excluded dependencies was invented for?
Should I care to exclude any dependencies other then for fixing libraries conflicts?
What would good maven project architecture look like:
tend to exclude as much as possible
or as minimum as needed?
I don't know the reasons for the design but I've seen it used in the following cases:
I had a library which had junit as a compile time dependency so JUnit code leaked into my production code.
I had a library which uses log4j. Since I'm using slf4j, I used dependency exclusion to get rid of the hardwired logging framework and used a slf4j-log4j bridge instead so I could ultimately log to logback.
In another case, I was using only some features of a framework and didn't need all the dependencies. Since they weren't optional in the first place, I used exclusions to keep my classpath lean and clean.
General rules:
Use it to get rid of things that break your build
Get rid of things that you're replacing with something else
Get rid of things that you know you don't need (optional)
If none of the rules apply, leave the dependency alone; chances are that the immediate dependency might change over time and suddenly, it will need some dependency that seemed superfluous before and you code will unexpectedly break.
In addition to Aaron's answer:
An exclusion is usually needed when the provider of the dependency did something wrong (i.e. did not make a dependency optional where he should have, included an actual logging backend - as opposed to api - or used the wrong scope).
The one exception is logging frameworks. See Aaron's answer for that.
So no, do only exclude dependencies if you have a specific reason to exclude them.

Spring jar dependencies

Trying to build Spring-based application one needs to figure out all necessary dependencies the application will have.
For example, I was using HibernateTemplate, and each time I run the application the ClassNotFound exception comes out. So I “google” for jars that contains this particular class, after search mvnrepository to find appropriate artifact. Always confuse about which version to use.
And it’s happened again and again, and only after few hours and few dozens of dependencies added the application become runnable.
But even after that, I tried to use my app. on different computer with slightly different parameters, and slf4j class not found error appeared, even after testing extensively on the developer machine, still some dependencies missing.
Now it works fine, but I want to distribute my application, and not sure if on another system there will no dependency missing.
So, what is the best practice to determine all necessary dependencies not only at design time but in runtime too? Is there any tool for that?
How one can manage versions confusion, when there are dozens of dependencies each with its own version?
They both resolve dependencies, so you keep a dependency file and it does all the heavy lifting of making sure everything is included in your builds. Use the full spring dependency list. I had problems with SLF4J too.
http://mvnrepository.com/artifact/org.springframework/spring-full/1.2.8

Resources