1/* 2 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24/* 25 * @test 26 * @bug 5102804 27 * @summary Tests memory leak 28 * @author Sergey Malenkov 29 * @run main/othervm -ms16m -mx16m Test5102804 30 */ 31 32import java.beans.BeanInfo; 33import java.beans.IntrospectionException; 34import java.beans.Introspector; 35import java.beans.PropertyDescriptor; 36import java.beans.SimpleBeanInfo; 37import java.lang.ref.Reference; 38import java.lang.ref.WeakReference; 39import java.net.URL; 40import java.net.URLClassLoader; 41 42public class Test5102804 { 43 private static final String BEAN_NAME = "Test5102804$Example"; 44 private static final String BEAN_INFO_NAME = BEAN_NAME + "BeanInfo"; 45 46 public static void main(String[] args) { 47 if (!isCollectible(getReference())) 48 throw new Error("Reference is not collected"); 49 } 50 51 private static Reference getReference() { 52 try { 53 ClassLoader loader = new Loader(); 54 Class type = Class.forName(BEAN_NAME, true, loader); 55 if (!type.getClassLoader().equals(loader)) { 56 throw new Error("Wrong class loader"); 57 } 58 BeanInfo info = Introspector.getBeanInfo(type); 59 if (0 != info.getDefaultPropertyIndex()) { 60 throw new Error("Wrong bean info found"); 61 } 62 return new WeakReference<Class>(type); 63 } 64 catch (IntrospectionException exception) { 65 throw new Error("Introspection Error", exception); 66 } 67 catch (ClassNotFoundException exception) { 68 throw new Error("Class Not Found", exception); 69 } 70 } 71 72 private static boolean isCollectible(Reference reference) { 73 int[] array = new int[10]; 74 while (true) { 75 try { 76 array = new int[array.length + array.length / 3]; 77 } 78 catch (OutOfMemoryError error) { 79 return null == reference.get(); 80 } 81 } 82 } 83 84 /** 85 * Custom class loader to load the Example class by itself. 86 * Could also load it from a different code source, but this is easier to set up. 87 */ 88 private static final class Loader extends URLClassLoader { 89 Loader() { 90 super(new URL[] { 91 Test5102804.class.getProtectionDomain().getCodeSource().getLocation() 92 }); 93 } 94 95 @Override 96 protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { 97 Class c = findLoadedClass(name); 98 if (c == null) { 99 if (BEAN_NAME.equals(name) || BEAN_INFO_NAME.equals(name)) { 100 c = findClass(name); 101 } 102 else try { 103 c = getParent().loadClass(name); 104 } 105 catch (ClassNotFoundException exception) { 106 c = findClass(name); 107 } 108 } 109 if (resolve) { 110 resolveClass(c); 111 } 112 return c; 113 } 114 } 115 116 /** 117 * A simple bean to load from the Loader class, not main class loader. 118 */ 119 public static final class Example { 120 private int value; 121 122 public int getValue() { 123 return value; 124 } 125 126 public void setValue(int value) { 127 this.value = value; 128 } 129 } 130 131 /** 132 * The BeanInfo for the Example class. 133 * It is also loaded from the Loader class. 134 */ 135 public static final class ExampleBeanInfo extends SimpleBeanInfo { 136 @Override 137 public int getDefaultPropertyIndex() { 138 return 0; 139 } 140 141 @Override 142 public PropertyDescriptor[] getPropertyDescriptors() { 143 try { 144 return new PropertyDescriptor[] { 145 new PropertyDescriptor("value", Class.forName(BEAN_NAME)) 146 }; 147 } 148 catch (ClassNotFoundException exception) { 149 return null; 150 } 151 catch (IntrospectionException exception) { 152 return null; 153 } 154 } 155 } 156} 157