<dependency>
<groupId>com.github.stefanbirkner</groupId>
<artifactId>fishbowl</artifactId>
<version>[1.1.1]</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit-dep</artifactId>
<version>[4.9,)</version>
</dependency>
This construct is altogether different. It specifies a dependency on the artifact known as junit in the group known as junit, but allows for any version greater than or equal to 4.9. The bracket on the left is an inclusive operator and the parenthesis on the right is an exclusive operator. The comma allows for any later revision. By way of example, (4.9,5.0) would mean any version after but not including 4.9 but before and not including 5.0, and (4.9) would mean any version greater than and less than 4.9. That wouldn't work at all.
This seems pretty powerful, but . . .
I have recently come 180° in my thinking about this. I now hate them with a passion - for two very good reasons.
Awesome Reason I
This one is purely idealogical, which is not to say that it is without merit, it's just a caveat that it may be debatable. If you depend, for instance, on apache commons-io 2.3, what reason do you have to expect it to work with 2.4? Or even 2.3.1? What assurances do you have from that developer community that 2.3.1 will not introduce a bug which impacts your library? Certainly by version 2.4 the API might change and break compatibility with your code. This is unpredictable and should not be part of a stable, release build.
Awesome Reason II++
This one is the biggie, and also exceedingly pragmatic. The aforementioned system rules library, which while otherwise awesome, includes a dependency on junit 4.9 and onwards. In a practical sense, though, depending on system-rules exposes my builds to periodic failures that are very difficult to track down or diagnose. Just today I got this error again:
[ERROR] Failed to execute goal on project ssc-cli: Could not resolve dependencies for project org.bitbucket.bradleysmithllc.star-schema-commander:ssc-cli:jar:ssc.1.C: Failed to collect dependencies at com.github.stefanbirkner:system-rules:jar:1.9.0 -> junit:junit-dep:jar:[4.9,): No versions available for junit:junit-dep:jar:[4.9,) within specified range -> [Help 1]
What does this mean? Why is it happening? Well, after being plagued with this for a long time, I finally tracked it down. Some transitive dependency of my project keeps retrieving crapped-up versions of junit, in this case 4.11-beta-1, which satisfies the dependency to be greater than or equal to 4.9, but is not an actual release - it is something that made it to central and then somehow into my repository. My only (reasonable) recourse is to go to my local repository and delete the junit group tree (~/.m2/repository/junit) and rebuild. Guess what happens next?
[ERROR] Failed to execute goal on project ssc-cli: Could not resolve dependencies for project org.bitbucket.bradleysmithllc.star-schema-commander:ssc-cli:jar:ssc.1.C: Failed to collect dependencies at com.github.stefanbirkner:system-rules:jar:1.9.0 -> commons-io:commons-io:jar:[2.0,): No versions available for commons-io:commons-io:jar:[2.0,) within specified range -> [Help 1]
Yep, you guessed it - another broken dependency range - this time apache commons-io. Repeating the same process, I delete my cached commons-io artifacts (~/.m2/repository/commons-io) and now my project builds.
I do not know why exactly this keeps happening - and I am sure that there are many things that could be done to fix it - like track down bad dependencies and fix everyone else's poms, but that isn't an option in most cases nor is it even something I want to do. My project has an explicit dependency on junit 4.11, which satisfies >= 4.9, so I don't know why it would consider any other version. The bottom line is that there is no way to predict when a library will break compatibility with yours, and you should not try to anticipate when that will happen. Builds must be stable and reproducible, and dependency ranges violate both of those goals.