]> source.dussan.org Git - javassist.git/commitdiff
Remove close method on ClassPath. Add unit tests for new behaviour.
authorChristian Melchior <christian@ilios.dk>
Sun, 12 Nov 2017 14:17:19 +0000 (15:17 +0100)
committerChristian Melchior <christian@ilios.dk>
Sun, 12 Nov 2017 14:17:19 +0000 (15:17 +0100)
Readme.html
pom.xml
src/main/javassist/ByteArrayClassPath.java
src/main/javassist/ClassClassPath.java
src/main/javassist/ClassPath.java
src/main/javassist/ClassPoolTail.java
src/main/javassist/LoaderClassPath.java
src/main/javassist/URLClassPath.java
src/test/javassist/JvstTest.java
src/test/resources/Readme.txt [new file with mode: 0644]
src/test/resources/empty.jar [new file with mode: 0755]

index 563ce36f340a98b8524cd8a79b3d172062803d45..4685062a238d4608a0b32ba4840ffb1a86d33150 100644 (file)
@@ -281,6 +281,14 @@ see javassist.Dump.
 
 <h2>Changes</h2>
 
+<p>-version 3.23 on MMM DD, YYYY
+
+<ul>
+    <li>Fix leaking file handlers in ClassPool and removed ClassPath.close(). Github issue #165.
+</ul>
+</p>
+
+
 <p>-version 3.22 on October 10, 2017
 
 <ul>
diff --git a/pom.xml b/pom.xml
index 06d1f6da874ee417953af0468f535f5567337ac4..6259547a8ce4f204ce7bf8f71424475efd31d5e4 100644 (file)
--- a/pom.xml
+++ b/pom.xml
   <build>
     <sourceDirectory>src/main/</sourceDirectory>
     <testSourceDirectory>src/test/</testSourceDirectory>
+    <testResources>
+      <testResource>
+        <directory>src/test/resources</directory>
+      </testResource>
+    </testResources>
     <plugins>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
           <includes>
             <include>javassist/JvstTest.java</include>
           </includes>
-         <forkMode>once</forkMode>
+          <additionalClasspathElements>
+            <additionalClasspathElement>resources</additionalClasspathElement>
+          </additionalClasspathElements>
+             <forkMode>once</forkMode>
           <workingDirectory>runtest</workingDirectory>
         </configuration>
       </plugin>
index d385eddcdb358c1d43012b1ee0ecce74323ecdd8..00397470932e6fc3bc783642570c98de1299baad 100644 (file)
@@ -62,11 +62,6 @@ public class ByteArrayClassPath implements ClassPath {
         this.classfile = classfile;
     }
 
-    /**
-     * Closes this class path.
-     */
-    public void close() {}
-
     public String toString() {
         return "byte[]:" + classname;
     }
index 3befbf4c89a49975e14c425c810a0e555d202afb..e1c44f08462d5a6d9eced93dd5a1efa5f44599f7 100644 (file)
@@ -91,12 +91,6 @@ public class ClassClassPath implements ClassPath {
         return thisClass.getResource(filename);
     }
 
-    /**
-     * Does nothing.
-     */
-    public void close() {
-    }
-
     public String toString() {
         return thisClass.getName() + ".class";
     }
index 0c605de2f35645571898431de18711d341e3a72d..60fe80e91eccaff550eb1468e160850804043106 100644 (file)
@@ -58,11 +58,4 @@ public interface ClassPath {
      * @return null if the specified class file could not be found.
      */
     URL find(String classname);
-
-    /**
-     * This method is invoked when the <code>ClassPath</code> object is
-     * detached from the search path.  It will be an empty method in most of
-     * classes.
-     */
-    void close();
 }
index 1b580855884ac2afc14ca8fec640c0dcffbce8d9..8e03873c254cb0977a7c6fda162b1b981203e0bf 100644 (file)
@@ -25,6 +25,9 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
 
@@ -72,8 +75,6 @@ final class DirClassPath implements ClassPath {
         return null;
     }
 
-    public void close() {}
-
     public String toString() {
         return directory;
     }
@@ -118,67 +119,63 @@ final class JarDirClassPath implements ClassPath {
 
         return null;    // not found
     }
-
-    public void close() {
-        if (jars != null)
-            for (int i = 0; i < jars.length; i++)
-                jars[i].close();
-    }
 }
 
 final class JarClassPath implements ClassPath {
-    JarFile jarfile;
+    List<String> jarfileEntries;
     String jarfileURL;
 
     JarClassPath(String pathname) throws NotFoundException {
+        JarFile jarfile = null;
         try {
             jarfile = new JarFile(pathname);
+            jarfileEntries = new ArrayList<String>();
+            for (JarEntry je:Collections.list(jarfile.entries()))
+                if (je.getName().endsWith(".class"))
+                    jarfileEntries.add(je.getName());
             jarfileURL = new File(pathname).getCanonicalFile()
-                                           .toURI().toURL().toString();
+                    .toURI().toURL().toString();
             return;
+        } catch (IOException e) {}
+        finally {
+            if (null != jarfile)
+                try {
+                    jarfile.close();
+                } catch (IOException e) {}
         }
-        catch (IOException e) {}
         throw new NotFoundException(pathname);
     }
 
+    @Override
     public InputStream openClassfile(String classname)
-        throws NotFoundException
+            throws NotFoundException
     {
-        try {
-            String jarname = classname.replace('.', '/') + ".class";
-            JarEntry je = jarfile.getJarEntry(jarname);
-            if (je != null)
-                return jarfile.getInputStream(je);
-            else
-                return null;    // not found
-        }
-        catch (IOException e) {}
-        throw new NotFoundException("broken jar file?: "
-                                    + jarfile.getName());
+        URL jarURL = find(classname);
+        if (null != jarURL)
+            try {
+                return jarURL.openConnection().getInputStream();
+            }
+            catch (IOException e) {
+                throw new NotFoundException("broken jar file?: "
+                        + classname);
+            }
+        return null;
     }
 
+    @Override
     public URL find(String classname) {
         String jarname = classname.replace('.', '/') + ".class";
-        JarEntry je = jarfile.getJarEntry(jarname);
-        if (je != null)
+        if (jarfileEntries.contains(jarname))
             try {
-                return new URL("jar:" + jarfileURL + "!/" + jarname);
+                return new URL(String.format("jar:%s!/%s", jarfileURL, jarname));
             }
             catch (MalformedURLException e) {}
-
         return null;            // not found
     }
 
-    public void close() {
-        try {
-            jarfile.close();
-            jarfile = null;
-        }
-        catch (IOException e) {}
-    }
-
+    @Override
     public String toString() {
-        return jarfile == null ? "<null>" : jarfile.toString();
+        return jarfileURL == null ? "<null>" : jarfileURL.toString();
     }
 }
 
@@ -235,8 +232,6 @@ final class ClassPoolTail {
                     else
                         list = list.next;
             }
-
-        cp.close();
     }
 
     public ClassPath appendSystemPath() {
index 6921ca6e757971e117e5d833b4667740547a49ad..299fdb859997a0aefc4e89adff236b11422da5be 100644 (file)
@@ -94,11 +94,4 @@ public class LoaderClassPath implements ClassPath {
             return url;
         }
     }
-
-    /**
-     * Closes this class path.
-     */
-    public void close() {
-        clref = null;
-    }
 }
index bea0b3c2bd465529eb7fa18d1eb463a730f19222..5eeef3a9e80a2f57876df4febea692d60d03f39f 100644 (file)
@@ -112,11 +112,6 @@ public class URLClassPath implements ClassPath {
         return null; 
     }
 
-    /**
-     * Closes this class path.
-     */
-    public void close() {}
-
     /**
      * Reads a class file on an http server.
      *
index d660a335c832bd0acbe7a9710b811b028b234463..11cdbe966246fc00fdc9124fd4fc78dc235e7920 100644 (file)
@@ -1,6 +1,7 @@
 package javassist;
 
 import junit.framework.*;
+import java.io.File;
 import java.io.FileInputStream;
 import java.lang.reflect.Method;
 import javassist.bytecode.*;
@@ -63,6 +64,27 @@ public class JvstTest extends JvstTestRoot {
         assertTrue("[class path: ]".equals(pool.toString()));
     }
 
+    public void testReleaseJarClassPathFileHandle() throws Exception {
+        String jarFileName = "./empty.jar";
+        ClassLoader classLoader = getClass().getClassLoader();
+        File jarFile = new File(classLoader.getResource(jarFileName).getFile());
+        assertTrue(jarFile.exists());
+
+        // Prepare class pool and force it to open the Jar file
+        ClassPool pool = ClassPool.getDefault();
+        ClassPath cp = pool.appendClassPath(jarFile.getAbsolutePath());
+        assertNull(cp.openClassfile("nothere.Dummy"));
+
+        // Assert that it is possible to delete the jar file.
+        // On Windows deleting an open file will fail, while on on Mac/Linux this is always possible.
+        // This check will thus only fail on Windos if the file is still open.
+        assertTrue(jarFile.delete());
+    }
+
+    public void testJarClassPath() throws Exception {
+        // TODO: Verify that classes can be loaded from a JarClassPath
+    }
+
     public void testSubtype() throws Exception {
         CtClass cc = sloader.get("test1.Subtype");
         assertTrue(cc.subtypeOf(cc));
diff --git a/src/test/resources/Readme.txt b/src/test/resources/Readme.txt
new file mode 100644 (file)
index 0000000..93de248
--- /dev/null
@@ -0,0 +1,7 @@
+This directory contains files used by the unit tests.
+
+empty.jar:
+An empty, but valid, jar file.
+
+
+
diff --git a/src/test/resources/empty.jar b/src/test/resources/empty.jar
new file mode 100755 (executable)
index 0000000..3a12dba
Binary files /dev/null and b/src/test/resources/empty.jar differ