getQualifiers() {
* @param key qualifier key
* @return qualifier value or {@code null} if one is not set
*/
- public String getQualifier(String key) {
- if (qualifiers == null) {
- return null;
- }
- return qualifiers.get(key);
+ public @Nullable String getQualifier(String key) {
+ return qualifiers == null ? null : qualifiers.get(requireNonNull(key));
}
/**
@@ -298,6 +308,12 @@ public String getQualifier(String key) {
* @throws MalformedPackageURLException thrown if the type or name has not been specified or if a field fails validation
*/
public PackageURL build() throws MalformedPackageURLException {
+ if (type == null) {
+ throw new MalformedPackageURLException("type is required");
+ }
+ if (name == null) {
+ throw new MalformedPackageURLException("name is required");
+ }
return new PackageURL(type, namespace, name, version, qualifiers, subpath);
}
}
diff --git a/src/main/java/com/github/packageurl/package-info.java b/src/main/java/com/github/packageurl/package-info.java
index 6a7436c..55397be 100644
--- a/src/main/java/com/github/packageurl/package-info.java
+++ b/src/main/java/com/github/packageurl/package-info.java
@@ -1,6 +1,29 @@
+/*
+ * MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
/**
* Java implementation of the Package-URL Specification.
* https://github.com/package-url/purl-spec
*/
+@NullMarked
package com.github.packageurl;
+import org.jspecify.annotations.NullMarked;
\ No newline at end of file
diff --git a/src/main/java/com/github/packageurl/validator/PackageURLConstraintValidator.java b/src/main/java/com/github/packageurl/validator/PackageURLConstraintValidator.java
index 481ef1c..43d1511 100644
--- a/src/main/java/com/github/packageurl/validator/PackageURLConstraintValidator.java
+++ b/src/main/java/com/github/packageurl/validator/PackageURLConstraintValidator.java
@@ -24,6 +24,7 @@
import com.github.packageurl.MalformedPackageURLException;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
+import org.jspecify.annotations.Nullable;
/**
* A JSR-303 compliant validator that validates String fields conform to the Package URL specification.
@@ -32,7 +33,7 @@
public class PackageURLConstraintValidator implements ConstraintValidator {
@Override
- public boolean isValid(String value, ConstraintValidatorContext context) {
+ public boolean isValid(@Nullable String value, ConstraintValidatorContext context) {
try {
if (value != null) {
new com.github.packageurl.PackageURL(value);
diff --git a/src/main/java/com/github/packageurl/validator/package-info.java b/src/main/java/com/github/packageurl/validator/package-info.java
new file mode 100644
index 0000000..03dc629
--- /dev/null
+++ b/src/main/java/com/github/packageurl/validator/package-info.java
@@ -0,0 +1,25 @@
+/*
+ * MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+@NullMarked
+package com.github.packageurl.validator;
+
+import org.jspecify.annotations.NullMarked;
\ No newline at end of file
diff --git a/src/test/java/com/github/packageurl/PackageURLBuilderTest.java b/src/test/java/com/github/packageurl/PackageURLBuilderTest.java
index 4e8168c..3b682d5 100644
--- a/src/test/java/com/github/packageurl/PackageURLBuilderTest.java
+++ b/src/test/java/com/github/packageurl/PackageURLBuilderTest.java
@@ -21,6 +21,8 @@
*/
package com.github.packageurl;
+import org.hamcrest.CoreMatchers;
+import org.hamcrest.MatcherAssert;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
@@ -30,6 +32,8 @@
import java.util.HashMap;
import java.util.Map;
+import static org.hamcrest.CoreMatchers.allOf;
+import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.*;
public class PackageURLBuilderTest {
@@ -102,7 +106,7 @@ public void testPackageURLBuilderException1() throws MalformedPackageURLExceptio
.withName("name")
.withQualifier("key","")
.build();
- assertNull(purl.getQualifiers());
+ assertEquals("qualifier count", 0, purl.getQualifiers().size());
}
@Test
@@ -112,13 +116,13 @@ public void testPackageURLBuilderException1Null() throws MalformedPackageURLExce
.withName("name")
.withQualifier("key",null)
.build();
- assertNull(purl.getQualifiers());
+ assertEquals("qualifier count", 0, purl.getQualifiers().size());
}
@Test
public void testPackageURLBuilderException2() throws MalformedPackageURLException {
exception.expect(MalformedPackageURLException.class);
- PackageURL purl = PackageURLBuilder.aPackageURL()
+ PackageURLBuilder.aPackageURL()
.withType("type")
.withNamespace("invalid//namespace")
.withName("name")
@@ -129,7 +133,7 @@ public void testPackageURLBuilderException2() throws MalformedPackageURLExceptio
@Test
public void testPackageURLBuilderException3() throws MalformedPackageURLException {
exception.expect(MalformedPackageURLException.class);
- PackageURL purl = PackageURLBuilder.aPackageURL()
+ PackageURLBuilder.aPackageURL()
.withType("typ^e")
.withSubpath("invalid/name%2Fspace")
.withName("name")
@@ -140,7 +144,7 @@ public void testPackageURLBuilderException3() throws MalformedPackageURLExceptio
@Test
public void testPackageURLBuilderException4() throws MalformedPackageURLException {
exception.expect(MalformedPackageURLException.class);
- PackageURL purl = PackageURLBuilder.aPackageURL()
+ PackageURLBuilder.aPackageURL()
.withType("0_type")
.withName("name")
.build();
@@ -150,7 +154,7 @@ public void testPackageURLBuilderException4() throws MalformedPackageURLExceptio
@Test
public void testPackageURLBuilderException5() throws MalformedPackageURLException {
exception.expect(MalformedPackageURLException.class);
- PackageURL purl = PackageURLBuilder.aPackageURL()
+ PackageURLBuilder.aPackageURL()
.withType("ype")
.withName("name")
.withQualifier("0_key","value")
@@ -161,7 +165,7 @@ public void testPackageURLBuilderException5() throws MalformedPackageURLExceptio
@Test
public void testPackageURLBuilderException6() throws MalformedPackageURLException {
exception.expect(MalformedPackageURLException.class);
- PackageURL purl = PackageURLBuilder.aPackageURL()
+ PackageURLBuilder.aPackageURL()
.withType("ype")
.withName("name")
.withQualifier("","value")
diff --git a/src/test/java/com/github/packageurl/PackageURLTest.java b/src/test/java/com/github/packageurl/PackageURLTest.java
index bf0a7da..508373c 100644
--- a/src/test/java/com/github/packageurl/PackageURLTest.java
+++ b/src/test/java/com/github/packageurl/PackageURLTest.java
@@ -24,14 +24,13 @@
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
-import java.util.Map;
import java.util.Locale;
+import java.util.Map;
import java.util.TreeMap;
-
import org.json.JSONArray;
import org.json.JSONObject;
-import org.junit.AfterClass;
import org.json.JSONTokener;
+import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Rule;
@@ -107,11 +106,9 @@ public void testConstructorParsing() throws Exception {
Assert.assertEquals(name, purl.getName());
Assert.assertEquals(version, purl.getVersion());
Assert.assertEquals(subpath, purl.getSubpath());
- if (qualifiers == null) {
- Assert.assertNull(purl.getQualifiers());
- } else {
- Assert.assertNotNull(purl.getQualifiers());
- Assert.assertEquals(qualifiers.length(), purl.getQualifiers().size());
+ Assert.assertNotNull(purl.getQualifiers());
+ Assert.assertEquals("qualifier count", qualifiers != null ? qualifiers.length() : 0, purl.getQualifiers().size());
+ if (qualifiers != null){
qualifiers.keySet().forEach(key -> {
String value = qualifiers.getString(key);
Assert.assertTrue(purl.getQualifiers().containsKey(key));
@@ -142,7 +139,7 @@ public void testConstructorParameters() throws MalformedPackageURLException {
final JSONObject qualifiers = testDefinition.optJSONObject("qualifiers");
final String subpath = testDefinition.optString("subpath", null);
- TreeMap map = null;
+ Map map = null;
Map hashMap = null;
if (qualifiers != null) {
map = qualifiers.toMap().entrySet().stream().collect(
@@ -159,7 +156,7 @@ public void testConstructorParameters() throws MalformedPackageURLException {
try {
PackageURL purl = new PackageURL(type, namespace, name, version, map, subpath);
Assert.fail("Invalid package url components should have caused an exception: " + purl);
- } catch (MalformedPackageURLException e) {
+ } catch (NullPointerException | MalformedPackageURLException e) {
Assert.assertNotNull(e.getMessage());
}
continue;
@@ -174,9 +171,9 @@ public void testConstructorParameters() throws MalformedPackageURLException {
Assert.assertEquals(name, purl.getName());
Assert.assertEquals(version, purl.getVersion());
Assert.assertEquals(subpath, purl.getSubpath());
+ Assert.assertNotNull(purl.getQualifiers());
+ Assert.assertEquals("qualifier count", qualifiers != null ? qualifiers.length() : 0, purl.getQualifiers().size());
if (qualifiers != null) {
- Assert.assertNotNull(purl.getQualifiers());
- Assert.assertEquals(qualifiers.length(), purl.getQualifiers().size());
qualifiers.keySet().forEach(key -> {
String value = qualifiers.getString(key);
Assert.assertTrue(purl.getQualifiers().containsKey(key));
@@ -242,7 +239,7 @@ public void testConstructorWithInvalidSubpath() throws MalformedPackageURLExcept
@Test
public void testConstructorWithNullPurl() throws MalformedPackageURLException {
- exception.expect(MalformedPackageURLException.class);
+ exception.expect(NullPointerException.class);
PackageURL purl = new PackageURL(null);
Assert.fail("constructor with null purl should have thrown an error and this line should not be reached");
@@ -299,9 +296,9 @@ public void testConstructorDuplicateQualifiersMixedCase() throws MalformedPackag
@Test
public void testConstructorWithUppercaseKey() throws MalformedPackageURLException {
PackageURL purl = new PackageURL("pkg://generic/name?KEY=one");
- Assert.assertNotNull(purl.getQualifiers());
+ Assert.assertEquals("qualifier count", 1, purl.getQualifiers().size());
Assert.assertEquals("one", purl.getQualifiers().get("key"));
- TreeMap qualifiers = new TreeMap<>();
+ Map qualifiers = new TreeMap<>();
qualifiers.put("key", "one");
PackageURL purl2 = new PackageURL("generic", null, "name", null, qualifiers, null);
Assert.assertEquals(purl, purl2);
@@ -310,8 +307,8 @@ public void testConstructorWithUppercaseKey() throws MalformedPackageURLExceptio
@Test
public void testConstructorWithEmptyKey() throws MalformedPackageURLException {
PackageURL purl = new PackageURL("pkg://generic/name?KEY");
- Assert.assertNull(purl.getQualifiers());
- TreeMap qualifiers = new TreeMap<>();
+ Assert.assertEquals("qualifier count", 0, purl.getQualifiers().size());
+ Map qualifiers = new TreeMap<>();
qualifiers.put("KEY", null);
PackageURL purl2 = new PackageURL("generic", null, "name", null, qualifiers, null);
Assert.assertEquals(purl, purl2);
@@ -357,10 +354,10 @@ public void testStandardTypes() {
}
@Test
- public void testBaseEquals() throws Exception {
+ public void testCoordinatesEquals() throws Exception {
PackageURL p1 = new PackageURL("pkg:generic/acme/example-component@1.0.0?key1=value1&key2=value2");
PackageURL p2 = new PackageURL("pkg:generic/acme/example-component@1.0.0");
- Assert.assertTrue(p1.isBaseEquals(p2));
+ Assert.assertTrue(p1.isCoordinatesEquals(p2));
}
@Test