@@ -62,6 +62,52 @@ public final class PackageURL implements Serializable {
6262
6363 private static final char PERCENT_CHAR = '%' ;
6464
65+ /**
66+ * The PackageURL scheme constant
67+ */
68+ public static final String SCHEME = "pkg" ;
69+
70+ /**
71+ * The PackageURL scheme ({@code "pkg"}) constant followed by a colon ({@code ':'}).
72+ */
73+ private static final String SCHEME_PART = SCHEME + ':' ;
74+
75+ /**
76+ * The package "type" or package "protocol" such as maven, npm, nuget, gem, pypi, etc.
77+ * Required.
78+ */
79+ private String type ;
80+
81+ /**
82+ * The name prefix such as a Maven groupid, a Docker image owner, a GitHub user or organization.
83+ * Optional and type-specific.
84+ */
85+ private @ Nullable String namespace ;
86+
87+ /**
88+ * The name of the package.
89+ * Required.
90+ */
91+ private String name ;
92+
93+ /**
94+ * The version of the package.
95+ * Optional.
96+ */
97+ private @ Nullable String version ;
98+
99+ /**
100+ * Extra qualifying data for a package such as an OS, architecture, a distro, etc.
101+ * Optional and type-specific.
102+ */
103+ private @ Nullable Map <String , String > qualifiers ;
104+
105+ /**
106+ * Extra subpath within a package, relative to the package root.
107+ * Optional.
108+ */
109+ private @ Nullable String subpath ;
110+
65111 /**
66112 * Constructs a new PackageURL object by parsing the specified string.
67113 *
@@ -111,8 +157,8 @@ public PackageURL(
111157 final @ Nullable String subpath )
112158 throws MalformedPackageURLException {
113159 this .type = toLowerCase (validateType (requireNonNull (type , "type" )));
114- this .namespace = validateNamespace (namespace );
115- this .name = validateName (requireNonNull (name , "name" ));
160+ this .namespace = validateNamespace (this . type , namespace );
161+ this .name = validateName (this . type , requireNonNull (name , "name" ));
116162 this .version = validateVersion (type , version );
117163 this .qualifiers = parseQualifiers (qualifiers );
118164 this .subpath = validateSubpath (subpath );
@@ -143,52 +189,6 @@ public PackageURL(
143189 this (type , namespace , name , version , (qualifiers != null ) ? new TreeMap <>(qualifiers ) : null , subpath );
144190 }
145191
146- /**
147- * The PackageURL scheme constant
148- */
149- public static final String SCHEME = "pkg" ;
150-
151- /**
152- * The PackageURL scheme ({@code "pkg"}) constant followed by a colon ({@code ':'}).
153- */
154- private static final String SCHEME_PART = SCHEME + ':' ;
155-
156- /**
157- * The package "type" or package "protocol" such as maven, npm, nuget, gem, pypi, etc.
158- * Required.
159- */
160- private String type ;
161-
162- /**
163- * The name prefix such as a Maven groupid, a Docker image owner, a GitHub user or organization.
164- * Optional and type-specific.
165- */
166- private @ Nullable String namespace ;
167-
168- /**
169- * The name of the package.
170- * Required.
171- */
172- private String name ;
173-
174- /**
175- * The version of the package.
176- * Optional.
177- */
178- private @ Nullable String version ;
179-
180- /**
181- * Extra qualifying data for a package such as an OS, architecture, a distro, etc.
182- * Optional and type-specific.
183- */
184- private @ Nullable Map <String , String > qualifiers ;
185-
186- /**
187- * Extra subpath within a package, relative to the package root.
188- * Optional.
189- */
190- private @ Nullable String subpath ;
191-
192192 /**
193193 * Converts this {@link PackageURL} to a {@link PackageURLBuilder}.
194194 *
@@ -276,7 +276,7 @@ public Map<String, String> getQualifiers() {
276276 return subpath ;
277277 }
278278
279- private void validateScheme (final String value ) throws MalformedPackageURLException {
279+ private static void validateScheme (final String value ) throws MalformedPackageURLException {
280280 if (!SCHEME .equals (value )) {
281281 throw new MalformedPackageURLException (
282282 "The PackageURL scheme '" + value + "' is invalid. It should be '" + SCHEME + "'" );
@@ -321,14 +321,16 @@ private static void validateChars(String value, IntPredicate predicate, String c
321321 }
322322 }
323323
324- private @ Nullable String validateNamespace (final @ Nullable String value ) throws MalformedPackageURLException {
324+ private static @ Nullable String validateNamespace (final String type , final @ Nullable String value )
325+ throws MalformedPackageURLException {
325326 if (isEmpty (value )) {
326327 return null ;
327328 }
328- return validateNamespace (value .split ("/" ));
329+ return validateNamespace (type , value .split ("/" ));
329330 }
330331
331- private @ Nullable String validateNamespace (final String [] values ) throws MalformedPackageURLException {
332+ private static @ Nullable String validateNamespace (final String type , final String [] values )
333+ throws MalformedPackageURLException {
332334 if (values .length == 0 ) {
333335 return null ;
334336 }
@@ -362,7 +364,7 @@ private static void validateChars(String value, IntPredicate predicate, String c
362364 return retVal ;
363365 }
364366
365- private String validateName (final String value ) throws MalformedPackageURLException {
367+ private static String validateName (final String type , final String value ) throws MalformedPackageURLException {
366368 if (value .isEmpty ()) {
367369 throw new MalformedPackageURLException ("The PackageURL name specified is invalid" );
368370 }
@@ -393,7 +395,7 @@ private String validateName(final String value) throws MalformedPackageURLExcept
393395 return temp ;
394396 }
395397
396- private @ Nullable String validateVersion (final String type , final @ Nullable String value ) {
398+ private static @ Nullable String validateVersion (final String type , final @ Nullable String value ) {
397399 if (value == null ) {
398400 return null ;
399401 }
@@ -408,7 +410,7 @@ private String validateName(final String value) throws MalformedPackageURLExcept
408410 }
409411 }
410412
411- private @ Nullable Map <String , String > validateQualifiers (final @ Nullable Map <String , String > values )
413+ private static @ Nullable Map <String , String > validateQualifiers (final @ Nullable Map <String , String > values )
412414 throws MalformedPackageURLException {
413415 if (values == null || values .isEmpty ()) {
414416 return null ;
@@ -438,7 +440,7 @@ private static void validateValue(final String key, final @Nullable String value
438440 }
439441 }
440442
441- private @ Nullable String validateSubpath (final @ Nullable String value ) throws MalformedPackageURLException {
443+ private static @ Nullable String validateSubpath (final @ Nullable String value ) throws MalformedPackageURLException {
442444 if (isEmpty (value )) {
443445 return null ;
444446 }
@@ -595,20 +597,13 @@ private static String toLowerCase(String s) {
595597 return new String (chars );
596598 }
597599
598- private static int indexOfPercentChar (final byte [] bytes , final int start ) {
599- return IntStream .range (start , bytes .length )
600+ private static int indexOfFirstPercentChar (final byte [] bytes ) {
601+ return IntStream .range (0 , bytes .length )
600602 .filter (i -> isPercent (bytes [i ]))
601603 .findFirst ()
602604 .orElse (-1 );
603605 }
604606
605- private static int indexOfUnsafeChar (final byte [] bytes , final int start ) {
606- return IntStream .range (start , bytes .length )
607- .filter (i -> shouldEncode (bytes [i ]))
608- .findFirst ()
609- .orElse (-1 );
610- }
611-
612607 private static byte percentDecode (final byte [] bytes , final int start ) {
613608 if (start + 2 >= bytes .length ) {
614609 throw new ValidationException ("Incomplete percent encoding at offset " + start + " with value '"
@@ -642,7 +637,7 @@ private static String percentDecode(final String source) {
642637 }
643638
644639 byte [] bytes = source .getBytes (StandardCharsets .UTF_8 );
645- int i = indexOfPercentChar (bytes , 0 );
640+ int i = indexOfFirstPercentChar (bytes );
646641
647642 if (i == -1 ) {
648643 return source ;
@@ -777,11 +772,11 @@ private void parse(final String purl) throws MalformedPackageURLException {
777772 // The 'remainder' should now consist of an optional namespace and the name
778773 index = remainder .lastIndexOf ('/' );
779774 if (index <= start ) {
780- this .name = validateName (percentDecode (remainder .substring (start )));
775+ this .name = validateName (this . type , percentDecode (remainder .substring (start )));
781776 } else {
782- this .name = validateName (percentDecode (remainder .substring (index + 1 )));
777+ this .name = validateName (this . type , percentDecode (remainder .substring (index + 1 )));
783778 remainder = remainder .substring (0 , index );
784- this .namespace = validateNamespace (parsePath (remainder .substring (start ), false ));
779+ this .namespace = validateNamespace (this . type , parsePath (remainder .substring (start ), false ));
785780 }
786781 verifyTypeConstraints (this .type , this .namespace , this .name );
787782 } catch (URISyntaxException e ) {
@@ -795,7 +790,7 @@ private void parse(final String purl) throws MalformedPackageURLException {
795790 * @param namespace the purl namespace
796791 * @throws MalformedPackageURLException if constraints are not met
797792 */
798- private void verifyTypeConstraints (String type , @ Nullable String namespace , @ Nullable String name )
793+ private static void verifyTypeConstraints (String type , @ Nullable String namespace , @ Nullable String name )
799794 throws MalformedPackageURLException {
800795 if (StandardTypes .MAVEN .equals (type )) {
801796 if (isEmpty (namespace ) || isEmpty (name )) {
@@ -805,7 +800,7 @@ private void verifyTypeConstraints(String type, @Nullable String namespace, @Nul
805800 }
806801 }
807802
808- private @ Nullable Map <String , String > parseQualifiers (final @ Nullable Map <String , String > qualifiers )
803+ private static @ Nullable Map <String , String > parseQualifiers (final @ Nullable Map <String , String > qualifiers )
809804 throws MalformedPackageURLException {
810805 if (qualifiers == null || qualifiers .isEmpty ()) {
811806 return null ;
@@ -825,7 +820,7 @@ private void verifyTypeConstraints(String type, @Nullable String namespace, @Nul
825820 }
826821
827822 @ SuppressWarnings ("StringSplitter" ) // reason: surprising behavior is okay in this case
828- private @ Nullable Map <String , String > parseQualifiers (final String encodedString )
823+ private static @ Nullable Map <String , String > parseQualifiers (final String encodedString )
829824 throws MalformedPackageURLException {
830825 try {
831826 final TreeMap <String , String > results = Arrays .stream (encodedString .split ("&" ))
@@ -849,14 +844,14 @@ private void verifyTypeConstraints(String type, @Nullable String namespace, @Nul
849844 }
850845 }
851846
852- private String [] parsePath (final String encodedPath , final boolean isSubpath ) {
847+ private static String [] parsePath (final String encodedPath , final boolean isSubpath ) {
853848 return Arrays .stream (encodedPath .split ("/" ))
854849 .filter (segment -> !segment .isEmpty () && !(isSubpath && ("." .equals (segment ) || ".." .equals (segment ))))
855850 .map (PackageURL ::percentDecode )
856851 .toArray (String []::new );
857852 }
858853
859- private String encodePath (final String path ) {
854+ private static String encodePath (final String path ) {
860855 return Arrays .stream (path .split ("/" )).map (PackageURL ::percentEncode ).collect (Collectors .joining ("/" ));
861856 }
862857
0 commit comments