diff --git a/multiapps-common/pom.xml b/multiapps-common/pom.xml
index fb01a8e5..a5260ab7 100644
--- a/multiapps-common/pom.xml
+++ b/multiapps-common/pom.xml
@@ -29,7 +29,7 @@
commons-lang3
- com.fasterxml.jackson.core
+ tools.jackson.core
jackson-databind
diff --git a/multiapps-mta/pom.xml b/multiapps-mta/pom.xml
index 47512e9b..ae725f9f 100644
--- a/multiapps-mta/pom.xml
+++ b/multiapps-mta/pom.xml
@@ -21,7 +21,7 @@
commons-collections4
- com.vdurmont
+ org.semver4j
semver4j
diff --git a/multiapps-mta/src/main/java/module-info.java b/multiapps-mta/src/main/java/module-info.java
index 1a092d01..e337fdb6 100644
--- a/multiapps-mta/src/main/java/module-info.java
+++ b/multiapps-mta/src/main/java/module-info.java
@@ -29,7 +29,7 @@
requires org.apache.commons.collections4;
requires org.apache.commons.io;
requires org.apache.commons.lang3;
- requires semver4j;
+ requires org.semver4j;
requires org.apache.commons.compress;
requires static java.compiler;
diff --git a/multiapps-mta/src/main/java/org/cloudfoundry/multiapps/mta/model/Version.java b/multiapps-mta/src/main/java/org/cloudfoundry/multiapps/mta/model/Version.java
index f8f2efc3..67eaf16b 100644
--- a/multiapps-mta/src/main/java/org/cloudfoundry/multiapps/mta/model/Version.java
+++ b/multiapps-mta/src/main/java/org/cloudfoundry/multiapps/mta/model/Version.java
@@ -4,16 +4,12 @@
import org.cloudfoundry.multiapps.common.ParsingException;
import org.cloudfoundry.multiapps.mta.Messages;
-import org.cloudfoundry.multiapps.mta.parsers.PartialVersionConverter;
-import com.vdurmont.semver4j.Semver;
-import com.vdurmont.semver4j.Semver.SemverType;
-import com.vdurmont.semver4j.SemverException;
+import org.semver4j.Semver;
+import org.semver4j.SemverException;
public class Version implements Comparable {
- private static final PartialVersionConverter PARTIAL_VERSION_CONVERTER = new PartialVersionConverter();
-
private final Semver version;
private Version(Semver version) {
@@ -32,21 +28,12 @@ public int getPatch() {
return version.getPatch();
}
- public String getBuild() {
- return version.getBuild();
- }
-
- public String[] getSuffixTokens() {
- return version.getSuffixTokens();
- }
-
public static Version parseVersion(String versionString) {
- try {
- String fullVersionString = PARTIAL_VERSION_CONVERTER.convertToFullVersionString(versionString);
- return new Version(new Semver(fullVersionString, SemverType.NPM));
- } catch (SemverException e) {
- throw new ParsingException(e, Messages.UNABLE_TO_PARSE_VERSION, versionString);
+ var version = Semver.coerce(versionString);
+ if (version == null) {
+ throw new ParsingException(MessageFormat.format(Messages.UNABLE_TO_PARSE_VERSION, versionString));
}
+ return new Version(version);
}
@Override
@@ -56,7 +43,7 @@ public int hashCode() {
@Override
public String toString() {
- return version.getValue();
+ return version.toString();
}
@Override
@@ -81,7 +68,8 @@ public boolean equals(Object obj) {
public boolean satisfies(String requirement) {
try {
- return version.satisfies(requirement);
+ // The second parameter is preventing the default behavior of Semver to treat the suffix as a pre-release tag.
+ return version.satisfies(requirement, true);
} catch (SemverException e) {
throw new IllegalArgumentException(MessageFormat.format(Messages.UNABLE_TO_PARSE_VERSION_REQUIREMENT, requirement));
}
diff --git a/multiapps-mta/src/main/java/org/cloudfoundry/multiapps/mta/parsers/PartialVersionConverter.java b/multiapps-mta/src/main/java/org/cloudfoundry/multiapps/mta/parsers/PartialVersionConverter.java
deleted file mode 100644
index 22059356..00000000
--- a/multiapps-mta/src/main/java/org/cloudfoundry/multiapps/mta/parsers/PartialVersionConverter.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package org.cloudfoundry.multiapps.mta.parsers;
-
-import com.vdurmont.semver4j.Semver;
-import com.vdurmont.semver4j.Semver.SemverType;
-
-public class PartialVersionConverter {
-
- private static final String VERSION_STRING_TEMPLATE = "%s.%s.%s%s%s";
- private static final String VERSION_SUFFIX_STRING_TEMPLATE = "-%s";
- private static final String VERSION_BUILD_STRING_TEMPLATE = "+%s";
- private static final String DEFAULT_VERSION_SUFFIX = "";
-
- public String convertToFullVersionString(String partialVersionString) {
- Semver partialVersion = new Semver(partialVersionString, SemverType.LOOSE);
- Integer majorVersion = partialVersion.getMajor();
- Integer minorVersion = partialVersion.getMinor();
- Integer patchVersion = partialVersion.getPatch();
-
- if (minorVersion == null) {
- minorVersion = 0;
- }
- if (patchVersion == null) {
- patchVersion = 0;
- }
- return buildVersionString(majorVersion, minorVersion, patchVersion, partialVersion.getSuffixTokens(), partialVersion.getBuild());
- }
-
- private String buildVersionString(int major, int minor, int patch, String[] suffixTokens, String buildVersion) {
- String formattedSuffixTokens = formatSuffixTokens(suffixTokens);
- String formattedBuildVersion = formatBuildVersion(buildVersion);
- return String.format(VERSION_STRING_TEMPLATE, major, minor, patch, formattedSuffixTokens, formattedBuildVersion);
- }
-
- private String formatSuffixTokens(String[] suffixTokens) {
- if (suffixTokens.length == 0) {
- return DEFAULT_VERSION_SUFFIX;
- }
- return String.format(VERSION_SUFFIX_STRING_TEMPLATE, String.join(".", suffixTokens));
- }
-
- private String formatBuildVersion(String buildVersion) {
- if (buildVersion == null) {
- return DEFAULT_VERSION_SUFFIX;
- }
- return String.format(VERSION_BUILD_STRING_TEMPLATE, buildVersion);
- }
-
-}
diff --git a/multiapps-mta/src/test/java/org/cloudfoundry/multiapps/mta/model/VersionTest.java b/multiapps-mta/src/test/java/org/cloudfoundry/multiapps/mta/model/VersionTest.java
new file mode 100644
index 00000000..c3a0d3d5
--- /dev/null
+++ b/multiapps-mta/src/test/java/org/cloudfoundry/multiapps/mta/model/VersionTest.java
@@ -0,0 +1,205 @@
+package org.cloudfoundry.multiapps.mta.model;
+
+import java.util.stream.Stream;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class VersionTest {
+
+ private static final String UNABLE_TO_PARSE_VERSION = "Unable to parse version";
+
+ // ---------------------------------------------------------------------------------------------
+ // PARSING AND NORMALIZATION TESTS
+ // ---------------------------------------------------------------------------------------------
+ @Nested
+ @DisplayName("parseVersion() and normalization behavior")
+ class ParseVersionTests {
+
+ @Test
+ @DisplayName("should parse complex versions with build metadata and timestamps")
+ void testParseComplexVersions() {
+ Version v1 = Version.parseVersion("0.0.1-20251105063220+e303076b5d51da7f0f3a10cd69de018ac0a3853d");
+ Version v2 = Version.parseVersion("1.2.0-20251105043948+cb754700fb069b3367c869938ac6beb396c800e4");
+ Version v3 = Version.parseVersion("1.0.0-SNAPSHOT-20240116224612+200df4832787863cc2f94d998c6cbcd711518933");
+
+ assertNotNull(v1);
+ assertNotNull(v2);
+ assertNotNull(v3);
+
+ assertVersionParts(v1, 0, 0, 1);
+ assertVersionParts(v2, 1, 2, 0);
+ assertVersionParts(v3, 1, 0, 0);
+ }
+
+ private void assertVersionParts(Version version, int major, int minor, int patch) {
+ assertEquals(major, version.getMajor());
+ assertEquals(minor, version.getMinor());
+ assertEquals(patch, version.getPatch());
+ }
+
+ @ParameterizedTest(name = "Partial version \"{0}\" should normalize to \"{1}\"")
+ @MethodSource
+ void testNormalizePartialVersions(String input, String expected) {
+ Version version = Version.parseVersion(input);
+ assertEquals(expected, version.toString());
+ }
+
+ static Stream testNormalizePartialVersions() {
+ return Stream.of(
+ Arguments.of("1.0.0", "1.0.0"),
+ Arguments.of("2.1", "2.1.0"),
+ Arguments.of("2", "2.0.0"),
+ Arguments.of("1.9.0-SNAPSHOT", "1.9.0-SNAPSHOT"),
+ Arguments.of("1.9-SNAPSHOT", "1.9.0"),
+ Arguments.of("1-SNAPSHOT", "1.0.0"),
+ Arguments.of("1.2.0-beta+exp.sha.5114f85", "1.2.0-beta+exp.sha.5114f85"),
+ Arguments.of("1.2-beta+exp.sha.5114f85", "1.2.0"),
+ Arguments.of("1-beta+exp.sha.5114f85", "1.0.0"),
+ Arguments.of("v1.2.3", "1.2.3")
+ );
+ }
+
+ @ParameterizedTest(name = "Invalid version \"{0}\" should throw SemverException or ParsingException")
+ @MethodSource
+ void testInvalidVersions(String invalid, String expectedMessage) {
+ Exception ex = assertThrows(Exception.class, () -> Version.parseVersion(invalid));
+ assertTrue(ex.getMessage()
+ .contains(expectedMessage));
+ }
+
+ static Stream testInvalidVersions() {
+ return Stream.of(
+ Arguments.of("a.b.c", UNABLE_TO_PARSE_VERSION),
+ Arguments.of("", UNABLE_TO_PARSE_VERSION),
+ Arguments.of("null", UNABLE_TO_PARSE_VERSION),
+ Arguments.of("not-a-version", UNABLE_TO_PARSE_VERSION)
+ );
+ }
+ }
+
+ // ---------------------------------------------------------------------------------------------
+ // COMPARISON AND EQUALITY TESTS
+ // ---------------------------------------------------------------------------------------------
+ @Nested
+ @DisplayName("compareTo() and equality behavior")
+ class CompareTests {
+
+ @Test
+ void testVersionComparison() {
+ Version v1 = Version.parseVersion("1.2.3");
+ Version v2 = Version.parseVersion("1.3.0");
+ Version v3 = Version.parseVersion("1.2.3");
+
+ assertTrue(v1.compareTo(v2) < 0);
+ assertTrue(v2.compareTo(v1) > 0);
+ assertEquals(0, v1.compareTo(v3));
+ }
+
+ @Test
+ void testEqualsAndHashCode() {
+ Version v1 = Version.parseVersion("2.0.0");
+ Version v2 = Version.parseVersion("2.0.0");
+ Version v3 = Version.parseVersion("2.0.1");
+
+ assertEquals(v1, v2);
+ assertNotEquals(v1, v3);
+ assertEquals(v1.hashCode(), v2.hashCode());
+ assertNotEquals(v1.hashCode(), v3.hashCode());
+ }
+ }
+
+ // ---------------------------------------------------------------------------------------------
+ // TO STRING & EDGE CASE TESTS
+ // ---------------------------------------------------------------------------------------------
+ @Nested
+ class ToStringAndEdgeCases {
+
+ @Test
+ void testToStringRepresentation() {
+ String raw = "3.4.5-alpha+build";
+ Version version = Version.parseVersion(raw);
+ assertEquals(raw, version.toString());
+ }
+
+ @Test
+ void testLargeVersionNumbers() {
+ Version version = Version.parseVersion("9999.9999.9999");
+ assertEquals(9999, version.getMajor());
+ }
+
+ @Test
+ void testPreReleaseVersion() {
+ Version version = Version.parseVersion("1.0.0-alpha");
+ assertTrue(version.toString()
+ .contains("alpha"));
+ }
+ }
+
+ // ---------------------------------------------------------------------------------------------
+ // SATISFIES() RANGE CHECK TESTS
+ // ---------------------------------------------------------------------------------------------
+ @Nested
+ class SatisfiesBehavior {
+
+ @Test
+ void testSimpleComparisons() {
+ Version v = Version.parseVersion("3.1.4");
+
+ assertTrue(v.satisfies(">3.0.0"));
+ assertTrue(v.satisfies(">=3.1.4"));
+ assertFalse(v.satisfies("<3.0.0"));
+ assertFalse(v.satisfies("<=3.1.3"));
+ }
+
+ @Test
+ void testCompositeRanges() {
+ Version v = Version.parseVersion("3.1.4");
+ assertTrue(v.satisfies(">=3.1.4 <4.0.0"));
+ assertTrue(v.satisfies(">=3.0.0 <=3.1.4"));
+ assertFalse(v.satisfies(">=3.2.0 <4.0.0"));
+ }
+
+ @Test
+ void testCaretAndTilde() {
+ Version v = Version.parseVersion("1.3.5");
+ assertTrue(v.satisfies("^1.3.0"));
+ assertTrue(v.satisfies("~1.3.0"));
+ assertFalse(v.satisfies("^2.0.0"));
+ }
+
+ @Test
+ void testMalformedRequirementsReturnFalse() {
+ Version v = Version.parseVersion("3.1.4");
+ assertFalse(v.satisfies("not-a-requirement"));
+ assertFalse(v.satisfies("pesho3.1.4"));
+ assertFalse(v.satisfies("3.1.4.2.3.4.5"));
+ }
+
+ @Test
+ void testNullRequirement() {
+ Version v = Version.parseVersion("3.1.4");
+ assertThrows(NullPointerException.class, () -> v.satisfies(null));
+ }
+
+ @Test
+ void testSatisfiesWithComplexVersions() {
+ Version v = Version.parseVersion("1.2.3-20251105063220+e303076b5d51da7f0f3a10cd69de018ac0a3853d");
+ assertTrue(v.satisfies(">=1.2.0"));
+ assertFalse(v.satisfies(">1.2.3"));
+ assertTrue(v.satisfies(">=1.2.0 <2.0.0"));
+ assertFalse(v.satisfies(">1.2.3 <2.0.0"));
+ }
+ }
+}
\ No newline at end of file
diff --git a/multiapps-mta/src/test/java/org/cloudfoundry/multiapps/mta/parsers/PartialVersionConverterTest.java b/multiapps-mta/src/test/java/org/cloudfoundry/multiapps/mta/parsers/PartialVersionConverterTest.java
deleted file mode 100644
index 5a539d72..00000000
--- a/multiapps-mta/src/test/java/org/cloudfoundry/multiapps/mta/parsers/PartialVersionConverterTest.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package org.cloudfoundry.multiapps.mta.parsers;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-
-import java.util.stream.Stream;
-
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.Arguments;
-import org.junit.jupiter.params.provider.MethodSource;
-
-import com.vdurmont.semver4j.SemverException;
-
-class PartialVersionConverterTest {
-
- private final PartialVersionConverter partialVersionConverter = new PartialVersionConverter();
-
- @ParameterizedTest
- @MethodSource
- void testConvertWithInvalidVersions(String versionString, String expectedExceptionMessage) {
- SemverException exception = assertThrows(SemverException.class,
- () -> partialVersionConverter.convertToFullVersionString(versionString));
-
- assertEquals(expectedExceptionMessage, exception.getMessage());
- }
-
- static Stream testConvertWithInvalidVersions() {
- return Stream.of(
-// @formatter:off
- Arguments.of("1.0.0-beta+", "The build cannot be empty."),
- Arguments.of("3.a", "Invalid version (no minor version): 3.a"),
- Arguments.of("a.b.c", "Invalid version (no major version): a.b.c"),
- Arguments.of( "", "Invalid version (no major version): "),
- Arguments.of("[ 2.0, 2.1 ]", "Invalid version (no major version): [ 2.0, 2.1 ]")
-// @formatter:on
- );
- }
-
- @ParameterizedTest
- @MethodSource
- void testConvertWithValidVersions(String versionString, String expectedResult) {
- String fullVersionString = partialVersionConverter.convertToFullVersionString(versionString);
-
- assertEquals(expectedResult, fullVersionString);
- }
-
- static Stream testConvertWithValidVersions() {
- return Stream.of(
-// @formatter:off
- // Full version:
- Arguments.of("1.0.0", "1.0.0"),
- // Partial version with minor version:
- Arguments.of("2.1", "2.1.0"),
- // Partial version with patch version:
- Arguments.of("2", "2.0.0"),
- // Full version with suffix tokens:
- Arguments.of("1.9.0-SHAPSHOT", "1.9.0-SHAPSHOT"),
- // Partial version with suffix tokens:
- Arguments.of("1.9-SHAPSHOT", "1.9.0-SHAPSHOT"),
- // Partial version with suffix tokens:
- Arguments.of("1-SHAPSHOT", "1.0.0-SHAPSHOT"),
- // Full version with suffix tokens and build information:
- Arguments.of("1.2.0-beta+exp.sha.5114f85", "1.2.0-beta+exp.sha.5114f85"),
- // Partial version with suffix tokens and build information:
- Arguments.of("1.2-beta+exp.sha.5114f85", "1.2.0-beta+exp.sha.5114f85"),
- // Partial version with suffix tokens and build information:
- Arguments.of("1-beta+exp.sha.5114f85", "1.0.0-beta+exp.sha.5114f85")
-// @formatter:on
- );
- }
-
-}
diff --git a/pom.xml b/pom.xml
index d333ff11..8c54f570 100644
--- a/pom.xml
+++ b/pom.xml
@@ -18,20 +18,18 @@
cloudfoundry
../multiapps-coverage/target/site/jacoco-aggregate/jacoco.xml
- 5.13.4
- 1.13.2
- 5.18.0
- 3.18.0
+ 6.0.1
+ 5.21.0
+ 3.20.0
4.5.0
- 2.20.0
- 2.4
-
-
- 3.1.0
- 2.10.1
- 2.19.2
- 4.0.5
- 4.0.2
+ 2.21.0
+ 2.5
+ 6.0.0
+ 2.12.0
+ 3.0.3
+ 2.20.1
+ 4.0.6
+ 4.0.4
1.28.0
@@ -121,7 +119,7 @@
org.apache.maven.plugins
maven-javadoc-plugin
- 3.11.2
+ 3.12.0
@@ -217,7 +215,7 @@
org.junit.platform
junit-platform-launcher
- ${junit-platform.version}
+ ${junit.version}
test
@@ -246,16 +244,17 @@
jaxb-runtime
${jaxb-runtime.version}
-
+
- com.fasterxml.jackson.core
+ tools.jackson.core
jackson-databind
${jackson.version}
+
com.fasterxml.jackson.datatype
jackson-datatype-jsr310
- ${jackson.version}
+ ${jackson.datatype.jsr310.version}
@@ -281,9 +280,9 @@
snakeyaml
${snakeyaml.version}
-
+
- com.vdurmont
+ org.semver4j
semver4j
${semver4j.version}