44package io .microsphere .util .jar ;
55
66import io .microsphere .annotation .Nonnull ;
7+ import io .microsphere .annotation .Nullable ;
78import io .microsphere .constants .ProtocolConstants ;
89import io .microsphere .filter .JarEntryFilter ;
910import io .microsphere .util .Utils ;
@@ -51,12 +52,25 @@ public abstract class JarUtils implements Utils {
5152 public static final String MANIFEST_RESOURCE_PATH = "META-INF/MANIFEST.MF" ;
5253
5354 /**
54- * Create a {@link JarFile} from specified {@link URL} of {@link JarFile}
55+ * Creates a {@link JarFile} from the specified {@link URL}.
5556 *
56- * @param jarURL {@link URL} of {@link JarFile} or {@link JarEntry}
57- * @return JarFile
58- * @throws IOException If {@link JarFile jar file} is invalid, see {@link JarFile#JarFile(String)}
57+ * <p>
58+ * This method resolves the absolute path of the JAR file from the provided URL and constructs
59+ * a new {@link JarFile} instance. If the URL does not point to a valid JAR or file resource,
60+ * this method returns {@code null}.
61+ * </p>
62+ *
63+ * <h3>Example Usage</h3>
64+ * <pre>{@code
65+ * URL jarURL = new URL("jar:file:/path/to/file.jar!/entry");
66+ * JarFile jarFile = JarUtils.toJarFile(jarURL);
67+ * }</pre>
68+ *
69+ * @param jarURL the URL pointing to a JAR file or entry; must not be {@code null}
70+ * @return a new {@link JarFile} instance if resolved successfully, or {@code null} if resolution fails
71+ * @throws IOException if an I/O error occurs while creating the JAR file
5972 */
73+ @ Nullable
6074 public static JarFile toJarFile (URL jarURL ) throws IOException {
6175 JarFile jarFile = null ;
6276 final String jarAbsolutePath = resolveJarAbsolutePath (jarURL );
@@ -83,15 +97,26 @@ protected static void assertJarURLProtocol(URL jarURL) throws NullPointerExcepti
8397 }
8498 }
8599
100+
86101 /**
87- * Resolve Relative path from Jar URL
102+ * Resolves the relative path from the given JAR URL.
88103 *
89- * @param jarURL {@link URL} of {@link JarFile} or {@link JarEntry}
90- * @return Non-null
91- * @throws NullPointerException see {@link #assertJarURLProtocol(URL)}
92- * @throws IllegalArgumentException see {@link #assertJarURLProtocol(URL)}
104+ * <p>This method extracts the part of the URL after the archive entry separator (e.g., "!/")
105+ * and decodes it to provide a normalized relative path within the JAR archive.</p>
106+ *
107+ * <h3>Example Usage</h3>
108+ * <pre>{@code
109+ * URL jarURL = new URL("jar:file:/path/to/file.jar!/com/example/resource.txt");
110+ * String relativePath = JarUtils.resolveRelativePath(jarURL);
111+ * System.out.println(relativePath); // Output: com/example/resource.txt
112+ * }</pre>
113+ *
114+ * @param jarURL the URL pointing to a resource within a JAR file; must not be {@code null}
115+ * @return the resolved relative path within the JAR archive
116+ * @throws NullPointerException if the provided {@code jarURL} is {@code null}
117+ * @throws IllegalArgumentException if the URL protocol is neither "jar" nor "file"
93118 */
94- @ Nonnull
119+ @ Nullable
95120 public static String resolveRelativePath (URL jarURL ) throws NullPointerException , IllegalArgumentException {
96121 assertJarURLProtocol (jarURL );
97122 String form = jarURL .toExternalForm ();
@@ -101,27 +126,49 @@ public static String resolveRelativePath(URL jarURL) throws NullPointerException
101126 }
102127
103128 /**
104- * Resolve absolute path from the {@link URL} of {@link JarEntry}
129+ * Resolves the absolute path of the JAR file from the provided URL.
105130 *
106- * @param jarURL {@link URL} of {@link JarFile} or {@link JarEntry}
107- * @return If {@link URL#getProtocol()} equals <code>jar</code> or <code>file</code> , resolves absolute path, or
108- * return <code>null</code>
109- * @throws NullPointerException see {@link #assertJarURLProtocol(URL)}
110- * @throws IllegalArgumentException see {@link #assertJarURLProtocol(URL)}
131+ * <p>
132+ * This method ensures that the URL protocol is either "jar" or "file", and then resolves
133+ * the absolute path to the corresponding JAR archive on the file system. If the URL does not
134+ * point to a valid JAR or file resource, this method returns {@code null}.
135+ * </p>
136+ *
137+ * <h3>Example Usage</h3>
138+ * <pre>{@code
139+ * URL jarURL = new URL("jar:file:/path/to/file.jar!/com/example/resource.txt");
140+ * String absolutePath = JarUtils.resolveJarAbsolutePath(jarURL);
141+ * System.out.println(absolutePath); // Output: /path/to/file.jar
142+ * }</pre>
143+ *
144+ * @param jarURL the URL pointing to a JAR file or entry; must not be {@code null}
145+ * @return the resolved absolute path of the JAR file if successful, or {@code null} if resolution fails
146+ * @throws NullPointerException if the provided {@code jarURL} is {@code null}
147+ * @throws IllegalArgumentException if the URL protocol is neither "jar" nor "file"
111148 */
112- @ Nonnull
149+ @ Nullable
113150 public static String resolveJarAbsolutePath (URL jarURL ) throws NullPointerException , IllegalArgumentException {
114151 assertJarURLProtocol (jarURL );
115152 File archiveFile = resolveArchiveFile (jarURL );
116153 return archiveFile == null ? null : archiveFile .getAbsolutePath ();
117154 }
118155
119156 /**
120- * Filter {@link JarEntry} list from {@link JarFile}
157+ * Filters the entries of a JAR file based on the provided {@link JarEntryFilter}.
158+ *
159+ * <p>This method iterates through all entries in the given JAR file and applies the filter to selectively include
160+ * or exclude entries. If the provided {@link JarFile} is null or empty, an empty list is returned.</p>
121161 *
122- * @param jarFile {@link JarFile}
123- * @param jarEntryFilter {@link JarEntryFilter}
124- * @return Read-only List
162+ * <h3>Example Usage</h3>
163+ * <pre>{@code
164+ * JarFile jarFile = new JarFile("example.jar");
165+ * JarEntryFilter classFileFilter = entry -> entry.getName().endsWith(".class");
166+ * List<JarEntry> filteredEntries = JarUtils.filter(jarFile, classFileFilter);
167+ * }</pre>
168+ *
169+ * @param jarFile The source JAR file; may be null.
170+ * @param jarEntryFilter The filter used to determine which entries to include; may be null (no filtering).
171+ * @return A read-only list of filtered JAR entries. Never null.
125172 */
126173 @ Nonnull
127174 public static List <JarEntry > filter (JarFile jarFile , JarEntryFilter jarEntryFilter ) {
@@ -144,65 +191,147 @@ protected static List<JarEntry> doFilter(Iterable<JarEntry> jarEntries, JarEntry
144191 }
145192
146193 /**
147- * Find {@link JarEntry} from specified <code>url</code>
194+ * Finds and returns the {@link JarEntry} from the specified JAR URL.
195+ *
196+ * <p>
197+ * This method resolves the relative path within the JAR archive from the provided URL and retrieves
198+ * the corresponding entry. If the entry does not exist or if there's an issue accessing the JAR file,
199+ * an exception may be thrown or a null value returned depending on underlying behavior.
200+ * </p>
148201 *
149- * @param jarURL jar resource url
150- * @return If found , return {@link JarEntry}
202+ * <h3>Example Usage</h3>
203+ * <pre>{@code
204+ * URL jarURL = new URL("jar:file:/path/to/file.jar!/com/example/resource.txt");
205+ * JarEntry jarEntry = JarUtils.findJarEntry(jarURL);
206+ * System.out.println(jarEntry.getName()); // Output: com/example/resource.txt
207+ * }</pre>
208+ *
209+ * @param jarURL the URL pointing to a resource within a JAR file; must not be {@code null}
210+ * @return the resolved {@link JarEntry} if found, or {@code null} if no such entry exists
211+ * @throws IOException if an I/O error occurs while reading the JAR file or resolving the entry
151212 */
213+ @ Nullable
152214 public static JarEntry findJarEntry (URL jarURL ) throws IOException {
153215 JarFile jarFile = toJarFile (jarURL );
154216 final String relativePath = resolveRelativePath (jarURL );
155217 JarEntry jarEntry = jarFile .getJarEntry (relativePath );
156218 return jarEntry ;
157219 }
158220
159-
160221 /**
161- * Extract the source {@link JarFile} to target directory
222+ * Extracts the contents of the specified JAR file to the given target directory.
162223 *
163- * @param jarSourceFile the source {@link JarFile}
164- * @param targetDirectory target directory
165- * @throws IOException When the source jar file is an invalid {@link JarFile}
224+ * <p>
225+ * This method extracts all entries from the provided JAR file into the target directory,
226+ * preserving the original directory structure. If the JAR file contains nested directories,
227+ * they will be recreated under the target directory.
228+ * </p>
229+ *
230+ * <h3>Example Usage</h3>
231+ * <pre>{@code
232+ * File jarFile = new File("example.jar");
233+ * File outputDir = new File("/path/to/output");
234+ * JarUtils.extract(jarFile, outputDir);
235+ * }</pre>
236+ *
237+ * @param jarSourceFile the source JAR file to extract; must not be {@code null}
238+ * @param targetDirectory the target directory where contents will be extracted; must not be {@code null}
239+ * @throws IOException if an I/O error occurs during extraction or if the provided file is not a valid JAR
166240 */
167241 public static void extract (File jarSourceFile , File targetDirectory ) throws IOException {
168242 extract (jarSourceFile , targetDirectory , null );
169243 }
170244
171245 /**
172- * Extract the source {@link JarFile} to target directory with specified {@link JarEntryFilter}
246+ * Extracts the contents of the specified JAR file to the given target directory, optionally filtering entries.
247+ *
248+ * <p>
249+ * This method extracts entries from the provided JAR file into the target directory. If a filter is provided,
250+ * only entries accepted by the filter will be extracted. The original directory structure of the JAR is preserved
251+ * under the target directory.
252+ * </p>
253+ *
254+ * <h3>Example Usage</h3>
255+ * <pre>{@code
256+ * File jarFile = new File("example.jar");
257+ * File outputDir = new File("/path/to/output");
173258 *
174- * @param jarSourceFile the source {@link JarFile}
175- * @param targetDirectory target directory
176- * @param jarEntryFilter {@link JarEntryFilter}
177- * @throws IOException When the source jar file is an invalid {@link JarFile}
259+ * // Extract all entries
260+ * JarUtils.extract(jarFile, outputDir, null);
261+ *
262+ * // Extract only .class files
263+ * JarEntryFilter classFileFilter = entry -> entry.getName().endsWith(".class");
264+ * JarUtils.extract(jarFile, outputDir, classFileFilter);
265+ * }</pre>
266+ *
267+ * @param jarSourceFile the source JAR file to extract; must not be {@code null}
268+ * @param targetDirectory the target directory where contents will be extracted; must not be {@code null}
269+ * @param jarEntryFilter an optional filter to restrict which entries are extracted; may be {@code null} to extract all entries
270+ * @throws IOException if an I/O error occurs during extraction or if the provided file is not a valid JAR
178271 */
179272 public static void extract (File jarSourceFile , File targetDirectory , JarEntryFilter jarEntryFilter ) throws IOException {
180-
181273 final JarFile jarFile = new JarFile (jarSourceFile );
182-
183274 extract (jarFile , targetDirectory , jarEntryFilter );
184275 }
185276
186277 /**
187- * Extract the source {@link JarFile} to target directory with specified {@link JarEntryFilter}
278+ * Extracts entries from a JAR file to the specified target directory, optionally filtering which entries to extract.
188279 *
189- * @param jarFile the source {@link JarFile}
190- * @param targetDirectory target directory
191- * @param jarEntryFilter {@link JarEntryFilter}
192- * @throws IOException When the source jar file is an invalid {@link JarFile}
280+ * <p>This method filters the entries in the JAR file using the provided {@link JarEntryFilter}, and extracts only those
281+ * entries that are accepted by the filter. If no filter is provided (i.e., {@code null}), all entries will be extracted.
282+ * The directory structure within the JAR is preserved under the target directory.</p>
283+ *
284+ * <h3>Example Usage</h3>
285+ * <pre>{@code
286+ * JarFile jarFile = new JarFile("example.jar");
287+ * File outputDir = new File("/path/to/output");
288+ *
289+ * // Extract all entries
290+ * JarUtils.extract(jarFile, outputDir, null);
291+ *
292+ * // Extract only .class files
293+ * JarEntryFilter classFileFilter = entry -> entry.getName().endsWith(".class");
294+ * JarUtils.extract(jarFile, outputDir, classFileFilter);
295+ * }</pre>
296+ *
297+ * @param jarFile the source JAR file to extract from; must not be {@code null}
298+ * @param targetDirectory the directory where the contents should be extracted; must not be {@code null}
299+ * @param jarEntryFilter an optional filter to determine which entries to extract; if {@code null}, all entries are extracted
300+ * @throws IOException if an I/O error occurs during extraction or if the JAR file is invalid
193301 */
194302 public static void extract (JarFile jarFile , File targetDirectory , JarEntryFilter jarEntryFilter ) throws IOException {
195303 List <JarEntry > jarEntriesList = filter (jarFile , jarEntryFilter );
196304 doExtract (jarFile , jarEntriesList , targetDirectory );
197305 }
198306
199307 /**
200- * Extract the source {@link JarFile} to target directory with specified {@link JarEntryFilter}
308+ * Extracts entries from a JAR resource pointed by the given URL to the specified target directory,
309+ * optionally filtering which entries to extract.
310+ *
311+ * <p>
312+ * This method resolves the JAR file and relative path from the provided URL, filters the entries
313+ * using the given {@link JarEntryFilter}, and extracts them to the target directory while preserving
314+ * the original directory structure. If no filter is provided (i.e., {@code null}), all entries under
315+ * the resolved path will be extracted.
316+ * </p>
317+ *
318+ * <h3>Example Usage</h3>
319+ * <pre>{@code
320+ * URL jarURL = new URL("jar:file:/path/to/file.jar!/com/example/");
321+ * File outputDir = new File("/path/to/output");
322+ *
323+ * // Extract all entries under 'com/example/'
324+ * JarUtils.extract(jarURL, outputDir, null);
325+ *
326+ * // Extract only .class files under 'com/example/'
327+ * JarEntryFilter classFileFilter = entry -> entry.getName().endsWith(".class");
328+ * JarUtils.extract(jarURL, outputDir, classFileFilter);
329+ * }</pre>
201330 *
202- * @param jarResourceURL The resource URL of {@link JarFile} or {@link JarEntry }
203- * @param targetDirectory target directory
204- * @param jarEntryFilter {@link JarEntryFilter}
205- * @throws IOException When the source jar file is an invalid {@link JarFile}
331+ * @param jarResourceURL the URL pointing to a resource within a JAR file; must not be {@code null }
332+ * @param targetDirectory the directory where the contents should be extracted; must not be {@code null}
333+ * @param jarEntryFilter an optional filter to determine which entries to extract; if {@code null}, all entries are extracted
334+ * @throws IOException if an I/O error occurs during extraction or resolving the JAR resource
206335 */
207336 public static void extract (URL jarResourceURL , File targetDirectory , JarEntryFilter jarEntryFilter ) throws IOException {
208337 final JarFile jarFile = toJarFile (jarResourceURL );
0 commit comments