@@ -60,6 +60,52 @@ public final class PackageURL implements Serializable {
6060
6161 private static final char PERCENT_CHAR = '%' ;
6262
63+ /**
64+ * The PackageURL scheme constant
65+ */
66+ public static final String SCHEME = "pkg" ;
67+
68+ /**
69+ * The PackageURL scheme ({@code "pkg"}) constant followed by a colon ({@code ':'}).
70+ */
71+ private static final String SCHEME_PART = SCHEME + ':' ;
72+
73+ /**
74+ * The package "type" or package "protocol" such as maven, npm, nuget, gem, pypi, etc.
75+ * Required.
76+ */
77+ private String type ;
78+
79+ /**
80+ * The name prefix such as a Maven groupid, a Docker image owner, a GitHub user or organization.
81+ * Optional and type-specific.
82+ */
83+ private @ Nullable String namespace ;
84+
85+ /**
86+ * The name of the package.
87+ * Required.
88+ */
89+ private String name ;
90+
91+ /**
92+ * The version of the package.
93+ * Optional.
94+ */
95+ private @ Nullable String version ;
96+
97+ /**
98+ * Extra qualifying data for a package such as an OS, architecture, a distro, etc.
99+ * Optional and type-specific.
100+ */
101+ private @ Nullable Map <String , String > qualifiers ;
102+
103+ /**
104+ * Extra subpath within a package, relative to the package root.
105+ * Optional.
106+ */
107+ private @ Nullable String subpath ;
108+
63109 /**
64110 * Constructs a new PackageURL object by parsing the specified string.
65111 *
@@ -130,60 +176,14 @@ public PackageURL(
130176 final @ Nullable String subpath )
131177 throws MalformedPackageURLException {
132178 this .type = toLowerCase (validateType (requireNonNull (type , "type" )));
133- this .namespace = validateNamespace (namespace );
134- this .name = validateName (requireNonNull (name , "name" ));
135- this .version = validateVersion (type , version );
179+ this .namespace = validateNamespace (this . type , namespace );
180+ this .name = validateName (this . type , requireNonNull (name , "name" ));
181+ this .version = validateVersion (this . type , version );
136182 this .qualifiers = parseQualifiers (qualifiers );
137183 this .subpath = validateSubpath (subpath );
138184 verifyTypeConstraints (this .type , this .namespace , this .name );
139185 }
140186
141- /**
142- * The PackageURL scheme constant
143- */
144- public static final String SCHEME = "pkg" ;
145-
146- /**
147- * The PackageURL scheme ({@code "pkg"}) constant followed by a colon ({@code ':'}).
148- */
149- private static final String SCHEME_PART = SCHEME + ':' ;
150-
151- /**
152- * The package "type" or package "protocol" such as maven, npm, nuget, gem, pypi, etc.
153- * Required.
154- */
155- private String type ;
156-
157- /**
158- * The name prefix such as a Maven groupId, a Docker image owner, a GitHub user or organization.
159- * Optional and type-specific.
160- */
161- private @ Nullable String namespace ;
162-
163- /**
164- * The name of the package.
165- * Required.
166- */
167- private String name ;
168-
169- /**
170- * The version of the package.
171- * Optional.
172- */
173- private @ Nullable String version ;
174-
175- /**
176- * Extra qualifying data for a package such as an OS, architecture, a distro, etc.
177- * Optional and type-specific.
178- */
179- private @ Nullable Map <String , String > qualifiers ;
180-
181- /**
182- * Extra subpath within a package, relative to the package root.
183- * Optional.
184- */
185- private @ Nullable String subpath ;
186-
187187 /**
188188 * Converts this {@link PackageURL} to a {@link PackageURLBuilder}.
189189 *
@@ -260,7 +260,7 @@ public Map<String, String> getQualifiers() {
260260 return subpath ;
261261 }
262262
263- private void validateScheme (final String value ) throws MalformedPackageURLException {
263+ private static void validateScheme (final String value ) throws MalformedPackageURLException {
264264 if (!SCHEME .equals (value )) {
265265 throw new MalformedPackageURLException (
266266 "The PackageURL scheme '" + value + "' is invalid. It should be '" + SCHEME + "'" );
@@ -305,14 +305,16 @@ private static void validateChars(String value, IntPredicate predicate, String c
305305 }
306306 }
307307
308- private @ Nullable String validateNamespace (final @ Nullable String value ) throws MalformedPackageURLException {
308+ private static @ Nullable String validateNamespace (final String type , final @ Nullable String value )
309+ throws MalformedPackageURLException {
309310 if (isEmpty (value )) {
310311 return null ;
311312 }
312- return validateNamespace (value .split ("/" ));
313+ return validateNamespace (type , value .split ("/" ));
313314 }
314315
315- private @ Nullable String validateNamespace (final String [] values ) throws MalformedPackageURLException {
316+ private static @ Nullable String validateNamespace (final String type , final String [] values )
317+ throws MalformedPackageURLException {
316318 if (values .length == 0 ) {
317319 return null ;
318320 }
@@ -346,7 +348,7 @@ private static void validateChars(String value, IntPredicate predicate, String c
346348 return retVal ;
347349 }
348350
349- private String validateName (final String value ) throws MalformedPackageURLException {
351+ private static String validateName (final String type , final String value ) throws MalformedPackageURLException {
350352 if (value .isEmpty ()) {
351353 throw new MalformedPackageURLException ("The PackageURL name specified is invalid" );
352354 }
@@ -377,7 +379,7 @@ private String validateName(final String value) throws MalformedPackageURLExcept
377379 return temp ;
378380 }
379381
380- private @ Nullable String validateVersion (final String type , final @ Nullable String value ) {
382+ private static @ Nullable String validateVersion (final String type , final @ Nullable String value ) {
381383 if (value == null ) {
382384 return null ;
383385 }
@@ -392,7 +394,7 @@ private String validateName(final String value) throws MalformedPackageURLExcept
392394 }
393395 }
394396
395- private @ Nullable Map <String , String > validateQualifiers (final @ Nullable Map <String , String > values )
397+ private static @ Nullable Map <String , String > validateQualifiers (final @ Nullable Map <String , String > values )
396398 throws MalformedPackageURLException {
397399 if (values == null || values .isEmpty ()) {
398400 return null ;
@@ -422,7 +424,7 @@ private static void validateValue(final String key, final @Nullable String value
422424 }
423425 }
424426
425- private @ Nullable String validateSubpath (final @ Nullable String value ) throws MalformedPackageURLException {
427+ private static @ Nullable String validateSubpath (final @ Nullable String value ) throws MalformedPackageURLException {
426428 if (isEmpty (value )) {
427429 return null ;
428430 }
@@ -574,20 +576,13 @@ private static String toLowerCase(String s) {
574576 return new String (chars );
575577 }
576578
577- private static int indexOfPercentChar (final byte [] bytes , final int start ) {
578- return IntStream .range (start , bytes .length )
579+ private static int indexOfFirstPercentChar (final byte [] bytes ) {
580+ return IntStream .range (0 , bytes .length )
579581 .filter (i -> isPercent (bytes [i ]))
580582 .findFirst ()
581583 .orElse (-1 );
582584 }
583585
584- private static int indexOfUnsafeChar (final byte [] bytes , final int start ) {
585- return IntStream .range (start , bytes .length )
586- .filter (i -> shouldEncode (bytes [i ]))
587- .findFirst ()
588- .orElse (-1 );
589- }
590-
591586 private static byte percentDecode (final byte [] bytes , final int start ) {
592587 if (start + 2 >= bytes .length ) {
593588 throw new ValidationException ("Incomplete percent encoding at offset " + start + " with value '"
@@ -621,7 +616,7 @@ static String percentDecode(final String source) {
621616 }
622617
623618 byte [] bytes = source .getBytes (StandardCharsets .UTF_8 );
624- int i = indexOfPercentChar (bytes , 0 );
619+ int i = indexOfFirstPercentChar (bytes );
625620
626621 if (i == -1 ) {
627622 return source ;
@@ -764,11 +759,11 @@ private void parse(final String purl) throws MalformedPackageURLException {
764759 // The 'remainder' should now consist of an optional namespace and the name
765760 index = remainder .lastIndexOf ('/' );
766761 if (index <= start ) {
767- this .name = validateName (percentDecode (remainder .substring (start )));
762+ this .name = validateName (this . type , percentDecode (remainder .substring (start )));
768763 } else {
769- this .name = validateName (percentDecode (remainder .substring (index + 1 )));
764+ this .name = validateName (this . type , percentDecode (remainder .substring (index + 1 )));
770765 remainder = remainder .substring (0 , index );
771- this .namespace = validateNamespace (parsePath (remainder .substring (start ), false ));
766+ this .namespace = validateNamespace (this . type , parsePath (remainder .substring (start ), false ));
772767 }
773768 verifyTypeConstraints (this .type , this .namespace , this .name );
774769 } catch (URISyntaxException e ) {
@@ -782,7 +777,7 @@ private void parse(final String purl) throws MalformedPackageURLException {
782777 * @param namespace the purl namespace
783778 * @throws MalformedPackageURLException if constraints are not met
784779 */
785- private void verifyTypeConstraints (String type , @ Nullable String namespace , @ Nullable String name )
780+ private static void verifyTypeConstraints (String type , @ Nullable String namespace , @ Nullable String name )
786781 throws MalformedPackageURLException {
787782 if (StandardTypes .MAVEN .equals (type )) {
788783 if (isEmpty (namespace ) || isEmpty (name )) {
@@ -792,7 +787,7 @@ private void verifyTypeConstraints(String type, @Nullable String namespace, @Nul
792787 }
793788 }
794789
795- private @ Nullable Map <String , String > parseQualifiers (final @ Nullable Map <String , String > qualifiers )
790+ private static @ Nullable Map <String , String > parseQualifiers (final @ Nullable Map <String , String > qualifiers )
796791 throws MalformedPackageURLException {
797792 if (qualifiers == null || qualifiers .isEmpty ()) {
798793 return null ;
@@ -812,7 +807,7 @@ private void verifyTypeConstraints(String type, @Nullable String namespace, @Nul
812807 }
813808
814809 @ SuppressWarnings ("StringSplitter" ) // reason: surprising behavior is okay in this case
815- private @ Nullable Map <String , String > parseQualifiers (final String encodedString )
810+ private static @ Nullable Map <String , String > parseQualifiers (final String encodedString )
816811 throws MalformedPackageURLException {
817812 try {
818813 final TreeMap <String , String > results = Arrays .stream (encodedString .split ("&" ))
@@ -836,14 +831,14 @@ private void verifyTypeConstraints(String type, @Nullable String namespace, @Nul
836831 }
837832 }
838833
839- private String [] parsePath (final String path , final boolean isSubpath ) {
834+ private static String [] parsePath (final String path , final boolean isSubpath ) {
840835 return Arrays .stream (path .split ("/" ))
841836 .filter (segment -> !segment .isEmpty () && !(isSubpath && ("." .equals (segment ) || ".." .equals (segment ))))
842837 .map (PackageURL ::percentDecode )
843838 .toArray (String []::new );
844839 }
845840
846- private String encodePath (final String path ) {
841+ private static String encodePath (final String path ) {
847842 return Arrays .stream (path .split ("/" )).map (PackageURL ::percentEncode ).collect (Collectors .joining ("/" ));
848843 }
849844
0 commit comments