1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.beanutils2.bugs;
18
19 import static org.junit.jupiter.api.Assertions.assertEquals;
20 import static org.junit.jupiter.api.Assertions.assertNotNull;
21 import static org.junit.jupiter.api.Assertions.assertNotSame;
22 import static org.junit.jupiter.api.Assertions.assertSame;
23 import static org.junit.jupiter.api.Assertions.fail;
24
25 import java.beans.IntrospectionException;
26 import java.lang.ref.SoftReference;
27 import java.lang.reflect.Method;
28 import java.net.MalformedURLException;
29 import java.net.URL;
30 import java.net.URLClassLoader;
31 import java.util.ArrayList;
32 import java.util.Objects;
33
34 import org.apache.commons.beanutils2.MappedPropertyDescriptor;
35 import org.apache.commons.beanutils2.memoryleaktests.MemoryLeakTest;
36 import org.junit.jupiter.api.Test;
37
38
39
40
41
42
43 public class Jira347Test {
44
45
46
47
48 private static URLClassLoader newClassLoader() throws MalformedURLException {
49
50 final String dataFilePath = MemoryLeakTest.class.getResource("pojotests").getFile();
51
52 final String location = "file://"
53 + dataFilePath.substring(0, dataFilePath.length() - "org.apache.commons.beanutils2.memoryleaktests.pojotests".length());
54
55
56 final StringBuilder newString = new StringBuilder();
57 for (int i = 0; i < location.length(); i++) {
58 if (location.charAt(i) == '\\') {
59 newString.append("/");
60 } else {
61 newString.append(location.charAt(i));
62 }
63 }
64 final String classLocation = newString.toString();
65
66
67 final URLClassLoader theLoader = URLClassLoader.newInstance(new URL[] { new URL(classLocation) }, null);
68 return theLoader;
69 }
70
71
72
73
74 private void forceGarbageCollection() throws Exception {
75
76 final SoftReference<Object> ref = new SoftReference<>(new Object());
77 int count = 0;
78 while (ref.get() != null && count++ < 5) {
79 ArrayList<Object> list = new ArrayList<>();
80 try {
81 long i = 0;
82 while (ref.get() != null) {
83 list.add(
84 "A Big String A Big String A Big String A Big String A Big String A Big String A Big String A Big String A Big String A Big String "
85 + i++);
86 }
87 } catch (final Throwable ignored) {
88 }
89 list.clear();
90 list = null;
91
92 System.gc();
93 Thread.sleep(1000);
94 }
95
96
97 if (ref.get() != null) {
98 throw new IllegalStateException("Your JVM is not releasing SoftReference, try running the test with less memory (-Xmx)");
99 }
100 }
101
102
103
104
105
106
107
108 private String getMappedWriteMethod(final MappedPropertyDescriptor descriptor) {
109 final Method m = descriptor.getMappedWriteMethod();
110 return Objects.toString(m, null);
111 }
112
113
114
115
116
117
118
119
120
121
122 @Test
123 public void testMappedPropertyDescriptor_AnyArgsProperty() throws Exception {
124 final String className = "org.apache.commons.beanutils2.MappedPropertyTestBean";
125 try (final URLClassLoader loader = newClassLoader()) {
126 final Class<?> beanClass = loader.loadClass(className);
127 beanClass.newInstance();
128
129
130 assertNotNull(loader, "ClassLoader is null");
131 assertNotNull(beanClass, "BeanClass is null");
132 assertNotSame(getClass().getClassLoader(), beanClass.getClassLoader(), "ClassLoaders should be different..");
133 assertSame(beanClass.getClassLoader(), loader, "BeanClass ClassLoader incorrect");
134
135
136 MappedPropertyDescriptor descriptor = null;
137 try {
138 descriptor = new MappedPropertyDescriptor("anyMapped", beanClass);
139 } catch (final IntrospectionException e) {
140
141 }
142
143 if (descriptor != null) {
144 final String m1 = getMappedWriteMethod(descriptor);
145 forceGarbageCollection();
146 try {
147 final String m2 = getMappedWriteMethod(descriptor);
148 assertEquals(m1, m2, "Method returned post garbage collection differs from Method returned prior to gc");
149 } catch (final RuntimeException e) {
150 fail("getMappedWriteMethod threw an exception after garbage collection " + e);
151 }
152 }
153 }
154 }
155 }