I am using Maven 3.3.3 and want to express that I will accept any 2.7.x version of the jackson-core dependency (but am not willing to go to 2.8.x until I've had a chance to assess for backward compatibility, run unit / regression tests, etc.).
This would allow my project to receive bug fixes (under incremental versions), but delay the jump to the next minor version until ready.
I instinctively wrote the following into pom.xml:
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>[2.7.1,2.8)</version>
However, a mvn dependency:list says that the following version is used:
com.fasterxml.jackson.core:jackson-core:jar:2.8.0.rc2:compile
I was taken aback by that, however dug up this answer which leads to the "official" Maven Javadoc which describes the sort order of Maven dependencies.
Those helped me understand why 2.8.0.rc2 is considered "older" than 2.8.0.
So, I reasoned that the following would (albeit hack-ishly) produce the desired results:
[2.7.1,2.8.0.a)
I was wrong. The dependency:list now produces:
com.fasterxml.jackson.core:jackson-core:jar:2.8.0:compile
Same result with (or variations with -a):
[2.7.1,2.8.a)
All together, this seems to imply the following orderings:
2.8.0 < 2.8.0.a
2.8.0.rc2 < 2.8.0
So ... if everything I learned in school about transitive relationships is correct, then:
2.8.0.rc2 < 2.8.0.a
That seems to contradict the SO answer. At the same time, the Javadoc is ambiguous (i.e. is the qualifier ordering listed the actually implemented ordering) and this Apache Wiki / Confluence page is mildly confusing.
Regardless, it doesn't seem to line up with either String sorting or common sense that a "Release Candidate" (assumed meaning for rc would precede an alpha version specified as a).
Would this be handled differently if there an actual 2.8.0-alpha version had been released?
Bottom line: is there a reasonably transferable way to specify a Maven Version Range which excludes everything in the 2.8.0 version space?
Edit: Even more bottom line... is there a clearly documented and publicly available description of the Maven version ordering algorithm outside of their source code? It's hard to tell if the cwiki page is a desired spec or implemented (and certainly doesn't go to the level of detail we're exploring here) and the Javadoc seems to imply (but isn't unambiguous in stating so) the equality between . and - which comments here demonstrate is not the case.
You can simply check the ordering by using the following command:
java -jar apache-maven-3.3.3/lib/maven-artifact-3.3.3.jar 2.8.0.rc2 2.8.0.a
Display parameters as parsed by Maven (in canonical form) and comparison result:
1. 2.8.0.rc2 == 2.8.0.rc-2
2.8.0.rc2 < 2.8.0.a
2. 2.8.0.a == 2.8.0.a
You can also check the other version 2.8.0-alpha via:
java -jar apache-maven-3.3.3/lib/maven-artifact-3.3.3.jar 2.8.0.rc2 2.8.0-alpha
Display parameters as parsed by Maven (in canonical form) and comparison result:
1. 2.8.0.rc2 == 2.8.0.rc-2
2.8.0.rc2 > 2.8.0-alpha
2. 2.8.0-alpha == 2.8-alpha
Maven itself says there is no official documentation until this bug is resolved.
Further, given what is stated in comments on the original question, I am concluding that there is no 100% safe, transferable of stating version numbers in a range for a more permanent solution.
Practically, I suppose making assumptions would render either of these valid for most uses:
[2.7.0,2.8.-alpha.alpha)
[2.7.0,2.7.9999.9999]
But theoretically, there could always be a smaller (in the first case) or larger (in the second) version number of the artifact (note that 2.7.9999.9999.9 > 2.7.9999.9999).
Even with those assumptions, stating the range in either manner leaves a build accepting any 2.7.x version published which might (for example) be 2.7.1-rc2.
I know realize this was an implied premise in my original question. That is, asking to "receive bug fixes (under incremental versions), but delay the jump to the next minor version until ready" assumed that the "incremental versions" are only non-alpha, non-rc, etc. versions.
That premise is invalid. Providing "only unqualified versions (eg. maj.min.inc with no -qualifer)" does not seem to be a use case supported by Maven and is a separate question entirely.
I think I'm now firmly in the "Maven Ranges are Evil" camp... not as much for build reproducibility reasons as much as being able to control the quality / finality of the included artifacts.
Related
It seems that some conformance resources are written to prescribe fixed URLs (with or without version suffix), for example by constraining meta.profile to a fixedCanonical.
{
"id": "Invoice.meta.profile",
"path": "Invoice.meta.profile",
"fixedCanonical": "http://zrbj.eu/StructureDefinition/foo|1.2.3"
}
This means that users always MUST specify the URL exactly as specified, i.e. with or without version, and the builtin flexibility of the FHIR mechanisms goes down the drain.
If I leave off the constraint then it is the user's choice whether to specify a version or not. Given a profile http://zrbj.eu/StructureDefinition/foo with version 1.2.3 the following four canonicals all work as expected in meta.profile of resource instances:
http://zrbj.eu/StructureDefinition/foo
http://zrbj.eu/StructureDefinition/foo|1.2
http://zrbj.eu/StructureDefinition/foo|1.2.2
http://zrbj.eu/StructureDefinition/foo|1.2.3
http://zrbj.eu/StructureDefinition/foo|1.2.4
The fifth example (resource with higher patch level than the profile) may be slightly counter-intuitive but that is how semantic versioning (SemVer) is supposed to function here: if major and minor version correspond then a resource with lower patch level must be accepted by a profile version with higher patch level and vice versa (i.e. compatibility goes both ways).
The following canonicals do not match major.minor of the profile and are rejected, as expected:
http://zrbj.eu/StructureDefinition/foo|1
http://zrbj.eu/StructureDefinition/foo|1.1
http://zrbj.eu/StructureDefinition/foo|1.3
Our usage scenario calls for the second accepted case: resources must 'commit' to one of the structural versions (major.minor) defined as permissible on the day of their creation, and they must document this by specifying the chosen version in the URL suffix. This still leaves the profile author free to fix minor things and increment the patch level, as long as two-way compatibility is preserved. It also offers a way of fixing certain classes of bugs with the least amount of collateral damage.
Is there anything that speaks against leaving off the URL-fixing constraint, given a usage scenario as the one I described?
UPDATE
Lloyd McKenzie has pointed out that extension URLs cannot be versioned. Hence I have rewritten the examples to use meta.profile instead.
Extension.url is defined as having a type of "uri", not "canonical". That means that version-specific references are not permitted. The version of the extension "in play" is driven by the version of the core specification in play and/or the versions of the IGs declared in the CapabilityStatement of the server. If neither of these define the extension, then the version of the extension may be ambiguous. For this reason, its important to not significantly change the semantics of an extension over time - instead, if needed, define a new extension.
There is currently no conformant mechanism of declaring the 'version' of an extension in an instance. If this is an essential requirement for you, submit a change request using the "propose a change" link at the bottom of any page in the spec and the community can discuss alternatives. (Given that Extension is now normative, it is extremely unlikely that changing to allow the 'canonical' syntax will be the agreed solution, as that would be a breaking change.)
Do Maven artifacts or their metadata deployed to a remote repository allow to reliably determine whether an artifact is a stable release?
Snapshots have the suffix SNAPSHOT, however there are also alphas, betas and pre-releases, and the naming is not necessarily consistent, e.g.:
5.0-alpha1
5.1-beta2
3.0.0-M5 (maybe this is actually a stable release?)
4.13-rc-2
5.7.0-RC1
https://mvnrepository.com highlights non-release versions differently, however maybe it is just looking for certain keywords?
(source)
See the POM Reference which has detailed explanations about version numbers beginning at section Dependency Version Requirement Specification:
If version strings are syntactically correct Semantic Versioning 1.0.0 version numbers, then in almost all cases version comparison follows the precedence rules outlined in that specification. [...]
[...]
When version strings do not follow semantic versioning, a more complex set of rules is required. [...] This gives a sequence of version numbers (numeric tokens) and version qualifiers (non-numeric tokens) with "." or "-" prefixes.
So, alpha1, beta2, M5, rc-2, RC1 are:
a) for „A pre-release version [...] denoted by appending an arbitrary string immediately following the patch version and a dash.“ according to point 4. of the Semantic Versioning Specification (SemVer),
b) all qualifiers for (pre-)releases, not snapshots, where M stands for milestone.
Content-wise you only can trust the artifact creator(s) that they took a proper qualifier that represents the actual status of the artifact.
My build complains about a missing dependency:
... requires bundle org.eclipse.ui [3.106.0,4.0.0)' but it could not be found
The used target platform points to a P2 location that includes the following JAR: org.eclipse.ui_3.106.0.v20140812-1751.jar
Still the build fails and raises the following two questions:
I thought 3.106.0.v20140812-1751 would be in the range [3.106.0,4.0.0), is that not true?
How does OSGi handle the fourth part of a version? If 3.106.0 is a valid version, then how is the suffix .v20140812-1751 understood by OSGi?
A link to a good explanation of OSGi versioning would also be highly appreciated.
I thought 3.106.0.v20140812-1751 would be in the range [3.106.0,4.0.0), is that not true?
Yes it is true.
How does OSGi handle the fourth part of a version? If 3.106.0 is a valid version, then how is the suffix .v20140812-1751 understood by OSGi?
The fourth part is just a segment like any other except that it is sorted alphanumerically rather than purely as a number. The specific algorithm is String.compare(), so you should read the standard JavaDocs for that method to get the full details. This segment is called the "qualifier"
In version 3.106.0.v20140812-1751, the qualifier is v20140812-1751. In the version 3.106.0, the qualifier is the empty string. As the JavaDocs for String.compare() will confirm, any non-empty string sorts after the empty string.
I'm trying to figure out if what Maven's policy is on custom qualifiers. I know that there exists specific qualifiers in Version strings that maven checks for, such as:
1.0.0-SNAPSHOT
5.3.0-beta-5
etc, but I was wondering if I could write specific rules or something that could handle custom qualifiers, such as:
1.0.0-mybranch
5.3.0-myotherbranch
or how maven would deal with such version strings. I've tried them out and things seem to be ok, I'm just wondering if Maven has some custom logic that could be used.
Thanks!
These examples will work fine.
Qualifiers have no special meaning other than:
SNAPSHOT, which gets transformed into the correct timestamp / build number
solely numerical values, which are actually a build number instead of a qualifier (and considered newer than the corresponding base version)
All qualifiers are considered to be older than the associated release, i.e. 1.2-beta-1 < 1.2
Comparison of qualifiers is done as a string comparison. This behaviour can differ in Maven 2.x and Maven 3.x (in the former, 1.0-beta-10 < 1.0-beta-5, in the latter it behaves in the reverse as you'd expect).
The 2011 answer is now obsolete in many important details. See the Javadoc on https://maven.apache.org/ref/3.3.9/maven-artifact/apidocs/org/apache/maven/artifact/versioning/ComparableVersion.html and the Wiki link there for the current version processing logic.
c.f. How does maven sort version numbers? for commentary on the Javadoc for ComparableVersion.
Often there's no need to pay any attention to implicit arguments in Scala, but sometimes it's very helpful to understand how the compiler is automatically providing them. Unfortunately, this understanding seems to be hard to obtain!
Is there a general method to discover how an implicit parameter has been provided, in a given piece of code?
Ideally, one day IDE integration would provide this information in some way, but I expect for now I'll have to dig deeper. Is there some way to ask the compiler to explain exactly which implicit definition it chooses at any given point? Can this be deciphered indirectly from other compiler output?
As an example, I'd like to know how to work out on my own where the implicit bf: CanBuildFrom[Repr, B, That] argument to TraversableLike.map comes from, without reading questions like this one on Stack Overflow!
Add the option -Xprint:typer to the scalac command line. This prints the program tree just after the typer compiler phase. This works best with a short, self contained example. You can also pass this to scalac. This is a really huge step towards self-reliance in Scala!
As mentioned by Randall, IntelliJ shows in-scope and the selected Implicit View with CTRL-ALT-SHIFT-I. Wait a month or two and implicit arguments are likely to have similar support.
Ideally, one day IDE integration would provide this information in some way, ...
That day is today in with JetBrains' IDEA. If you run the latest EAP of IDEA version 9 (9.0.3 EA #95.289) with a recent nightly release of the Scala plug-in, this capability is present. Every value expression may be selected and a command issued that displays a pop-up showing all applicable implicit conversions with the one the compiler will select highlighted.
And since there are apparently a few out there who don't yet know it, there is a free and open-source Community Edition of IDEA and it does support the Scala plug-in.