Semver4j is a lightweight Java library that helps you handle version strings according to the semantic versioning specification. It provides robust support for multiple range checking formats including:
- π¦ node-semver (NPM style)
- π« CocoaPods
- πΏ Ivy
- Semver4j
- π Overview
- π§Ύ Table of Contents
- βοΈ Installation
- π Usage
- π€ Contributing
- π Thanks
Add the dependency to your project:
<dependency>
<groupId>org.semver4j</groupId>
<artifactId>semver4j</artifactId>
<version>6.0.0</version>
</dependency>
Groovy
implementation 'org.semver4j:semver4j:6.0.0'
Kotlin
implementation("org.semver4j:semver4j:6.0.0")
This version references the original library version v3.1.0
in
the source repository.
π·οΈ What is a version?
8000In Semver4j
, a version follows this format: 1.2.3-beta.4+sha899d8g79f87
1
is themajor
version (required) π’2
is theminor
version (required) π’3
is thepatch
version (required) π’beta.4
is thepre-release
identifier (optional) π§ͺsha899d8g79f87
is thebuild
metadata (optional) π
You can create a Semver
object in several ways:
Semver version = new Semver("1.2.3-beta.4+sha899d8g79f87");
Semver version = Semver.parse("1.2.3-beta.4+sha899d8g79f87"); // returns correct Semver object
Semver version = Semver.parse("invalid"); // returns null, cannot parse this version
The library can help you create valid objects even when the version string isn't valid: Semver
Semver version = Semver.coerce("..1"); // produces the same result as new Semver("1.0.0")
Semver version = Semver.coerce("invalid"); // returns null, cannot coerce this version
Check if you're working with a stable version using isStable()
:
// β
Stable versions (returns true)
boolean stable = new Semver("1.2.3").isStable(); // major is > 0 and has no pre-release version
boolean stable = new Semver("1.2.3+sHa.0nSFGKjkjsdf").isStable(); // major is > 0 and has only build metadata
// β Unstable versions (returns false)
boolean stable = new Semver("0.1.2").isStable(); // major is < 1
boolean stable = new Semver("0.1.2+sHa.0nSFGKjkjsdf").isStable(); // major is < 1
boolean stable = new Semver("1.2.3-BETA.11+sHa.0nSFGKjkjsdf").isStable(); // has pre-release version
Semver version = new Semver("1.2.3");
// Greater than
boolean greaterThan = version.isGreaterThan("1.2.2"); // true β
boolean greaterThan = version.isGreaterThan("1.2.4"); // false β
boolean greaterThan = version.isGreaterThan("1.2.3"); // false β
// Lower than
boolean lowerThan = version.isLowerThan("1.2.2"); // false β
boolean lowerThan = version.isLowerThan("1.2.4"); // true β
boolean lowerThan = version.isLowerThan("1.2.3"); // false β
// Equal to (exact match)
boolean equalTo = version.isEqualTo("1.2.3+sha123456789"); // false β (build metadata differs)
// Equivalent to (ignores build metadata)
boolean equivalentTo = version.isEquivalentTo("1.2.3+sha123456789"); // true β
boolean equivalentTo = version.isEquivalentTo("1.2.3+shaABCDEFGHI"); // true β
Find the most significant difference between versions with diff()
:
Semver version = new Semver("1.2.3-beta.4+sha899d8g79f87");
Semver.VersionDiff diff = version.diff("1.2.3-beta.4+sha899d8g79f87"); // NONE
Semver.VersionDiff diff = version.diff("2.3.4-alpha.5+sha32iddfu987"); // MAJOR
Semver.VersionDiff diff = version.diff("1.3.4-alpha.5+sha32iddfu987"); // MINOR
Semver.VersionDiff diff = version.diff("1.2.4-alpha.5+sha32iddfu987"); // PATCH
Semver.VersionDiff diff = version.diff("1.2.3-alpha.5+sha32iddfu987"); // PRE_RELEASE
Semver.VersionDiff diff = version.diff("1.2.3-beta.4+sha32iddfu987"); // BUILD
Check if a version satisfies a range with the satisfies()
method:
// Using string-based ranges
Semver version = new Semver("1.2.3");
RangeList rangeList = RangeListFactory.create(">=1.0.0 <2.0.0");
boolean satisfies = version.satisfies(rangeList); // true β
Semver4j
supports multiple range formats:
- NPM
- Primitive ranges
<
,<=
,>
,>=
and=
- Hyphen ranges
X.Y.Z - A.B.C
- X-Ranges
1.2.x
,1.X
,1.2.*
and*
- Tilde ranges
~1.2.3
,~1.2
and~1
- Caret ranges
^1.2.3
,^0.2.5
and^0.0.4
- Primitive ranges
- CocoaPods
- Optimistic operator
~> 1.0
- Optimistic operator
- Ivy
- Version Range Matcher
[1.0,2.0]
,[1.0,2.0[
,]1.0,2.0]
,]1.0,2.0[
,[1.0,)
,]1.0,)
,(,2.0]
and(,2.0[
- Version Range Matcher
Build ranges using the fluent interface:
// (=1.0.0 and <2.0.0) or >=3.0.0
RangeExpression rangeExpression = eq("1.0.0")
.and(less("2.0.0"))
.or(greaterOrEqual("3.0.0"));
boolean satisfies = semver.satisfies(rangeExpression);
The Semver
object is immutable, but provides methods to create new versions:
Semver version = new Semver("1.2.3-beta.4+sha899d8g79f87");
// Increment versions
Semver newVersion = version.withIncMajor(); // 2.0.0
Semver newVersion = version.withIncMinor(); // 1.3.0
Semver newVersion = version.withIncPatch(); // 1.2.4
// Clear parts
Semver newVersion = version.withClearedPreRelease(); // 1.2.3+sha899d8g79f87
Semver newVersion = version.withClearedBuild(); // 1.2.3-beta.4
// Next versions (automatically clears pre-release and build)
Semver newVersion = version.nextMajor(); // 2.0.0
Semver newVersion = version.nextMinor(); // 1.3.0
Semver newVersion = version.nextPatch(); // 1.2.4
Semver4j
provides multiple ways to programmatically create Semver
objects without parsing strings:
Semver semver = Semver.builder()
.withMajor(1)
.withMinor(2)
.withPatch(3)
.withPreRelease("alpha")
.withBuild("5bb76cdb")
.build();
// Equivalent to: new Semver("1.2.3-alpha+5bb76cdb")
The of()
method provides a shorthand to initialize a builder with the major
, minor
, and patch
components:
Semver semver = Semver.of(1, 2, 3)
.withPreRelease("beta")
.build();
// Equivalent to: new Semver("1.2.3-beta")
The create()
method is the most concise way to create a basic version with just major
, minor
, and patch
components:
Semver semver = Semver.create(1, 2, 3);
// Equivalent to: new Semver("1.2.3")
Semver4j
allows you to customize how version ranges are processed through its processor architecture. This gives you
the flexibility to support additional range formats or modify the behavior of existing ones.
You can specify which processors to use when creating a RangeList
:
// Create a RangeList using only the Ivy processor
RangeList rangeList = RangeListFactory.create("[1.0.0,2.0.0]", new IvyProcessor());
// The result will be ">=1.0.0 and <=2.0.0"
Use CompositeProcessor
to combine multiple processors:
// Create a processor that handles both Ivy and Tilde ranges
Processor customProcessor = CompositeProcessor.of(
new IvyProcessor(),
new TildeProcessor()
);
// Create a RangeList using the custom processor combination
RangeList rangeList = RangeListFactory.create(
"~1.2.3 || [2.0.0,3.0.0]",
false, // don't include pre-releases
customProcessor
);
Implement the Processor
interface to create a custom range format handler:
public class CustomProcessor implements Processor {
@Override
public @Nullable String process(String range, boolean includePreRelease) {
// Your logic to process custom range format
// Returns null if this processor can't handle the input
if (!range.startsWith("custom:")) {
return null;
}
// Convert custom format to standard format
String version = range.substring(7);
return ">=" + version;
}
}
To use all built-in processors (which is the default behavior):
// Use all available processors
Processor allProcessors = CompositeProcessor.all();
// Create a RangeList with all processors
RangeList rangeList = RangeListFactory.create("^1.0.0 || ~2.0.0");
This processor architecture gives you the flexibility to support custom version range formats for any project-specific needs.
Format versions using custom formatters:
Semver semver = new Semver("1.2.3-alpha.1+sha.1234");
String customVersion = semver.format(sem ->
String.format("%d:%d:%d", sem.getMajor(), sem.getMinor(), sem.getPatch())
); // "1:2:3"
Pull requests and bug reports are welcome! If you have suggestions for new features, please open an issue.
For details on contributing to this repository, see the contributing guide.
Logo created by Tomek Babik @tomekbbk.