import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.Permission;
import java.security.Policy;
import java.security.ProtectionDomain;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;

public class ClassForNameLeak {
	public static WeakReference<ClassLoader> init() throws Exception { 
		System.setSecurityManager(new SecurityManager() { 
			@Override 
			public void checkPermission(final Permission perm) { 
				return; 
			} 
		}); 
		Policy.setPolicy(new Policy() { 
			@Override 
			public boolean implies(final ProtectionDomain domain, final Permission permission) { 
				return true; 
			} 
		}); 

		URL resource = ClassForNameLeak.class.getResource("ClassForName.class"); 
		File jarFile = File.createTempFile("cfn", ".jar"); 
		JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(jarFile)); 
		jarFile.deleteOnExit(); 

//		ZipEntry zipEntry = new ZipEntry("classfornameleak/"); 
//		jarOutputStream.putNextEntry(zipEntry); 

		ZipEntry zipEntry = new ZipEntry("ClassForName.class"); 
		byte[] buffer = new byte[1024]; 
		InputStream openStream = resource.openStream(); 

		jarOutputStream.putNextEntry(zipEntry); 
		while (true) { 
			int count = openStream.read(buffer); 
			if (count == -1) { 
				break; 
			} 
			jarOutputStream.write(buffer, 0, count); 
		} 
		jarOutputStream.closeEntry(); 
		jarOutputStream.close(); 

		ClassLoader classLoader = new URLClassLoader(new URL[] {jarFile.toURI().toURL()}) { 

			@Override 
			public Class<?> loadClass(final String name) throws ClassNotFoundException { 
				if (ClassForName.class.getName().equals(name)) { 
					return findClass(name); 
				} 
				return super.loadClass(name); 
			} 

			@Override 
			public String toString() { 
				return "leaked classloader"; 
			} 
		}; 

		Class<?> loadClass = classLoader.loadClass(ClassForName.class.getName()); 
		((Runnable) loadClass.newInstance()).run(); 
		return new WeakReference<ClassLoader>(classLoader); 
	} 

	public static void main(final String[] args) throws Exception { 
		WeakReference<ClassLoader> weakReference = init(); 

		for (int i = 0; i < 10; i++) { 
			System.gc(); 
		} 
		while (weakReference.get() != null) { 
			System.out.println("Not yet GC"); 
			System.gc(); 
			Thread.sleep(100); 
		} 

		System.out.println("OK no bug"); 

	} 

}
